├── .gitignore ├── CHANGELOG ├── CONTRIBUTING.md ├── COPYING ├── INSTALL ├── MANIFEST.in ├── README.rst ├── bin ├── _preamble.py └── hackersh ├── distribute_setup.py ├── doc ├── TODO └── requirements.txt ├── hackersh ├── __init__.py ├── _ordereddict.py ├── _version.py ├── components │ ├── __init__.py │ ├── external │ │ ├── __init__.py │ │ ├── amap.py │ │ ├── dnsdict6.py │ │ ├── nbtscan.py │ │ ├── nikto.py │ │ ├── nmap.py │ │ ├── ping.py │ │ ├── sqlmap.py │ │ ├── w3af.py │ │ └── xprobe2.py │ ├── internal │ │ ├── __init__.py │ │ ├── browse.py │ │ ├── domain.py │ │ ├── hostname.py │ │ ├── ipv4_address.py │ │ ├── ipv4_range.py │ │ ├── ipv6_address.py │ │ ├── iterate_links.py │ │ ├── nslookup.py │ │ ├── submit.py │ │ └── url.py │ └── system │ │ ├── __init__.py │ │ ├── alert.py │ │ ├── null.py │ │ ├── print.py │ │ ├── system.py │ │ └── tmpfile.py ├── conio.py ├── eval.py ├── exceptions.py ├── log.py ├── miscellaneous.py └── objects.py ├── setup.cfg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | /dist/ 4 | /build/ 5 | *.egg-info 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | # Hackersh Changelog 2 | 3 | Hackersh 0.2 [2013-05-02] 4 | 5 | o Introduce `dnsdict6` - new external component for: 6 | Information Gathering / Network Analysis / DNS Analysis 7 | dnsdict6 v1.8 (c) 2011 by van Hauser / THC www.thc.org 8 | Example: "hackersh.org" -> domain -> dnsdict6("-4 -s") -> ... 9 | 10 | o Implement SimpleRegExHandler class - a new Pseudo SAX Content Handler 11 | class for processing output using regex 12 | 13 | o amap, nikto, nmap, ping, w3af, xprobe2, and browse: Change DEFAULT_QUERY 14 | to evaluate context['IPV4_ADDRESS'] before context['HOSTNAME'] 15 | 16 | o Implement NbtScanStdoutOutputHandler class. Rewrite nbtscan to use it 17 | 18 | o Implement SqlMapStdoutOutputHandler class. Rewrite sqlmap to use it 19 | 20 | o Implement StdoutOutputHandler - a new Pseudo SAX Content Handler base 21 | class for stdout processing 22 | 23 | o Implement ExternalComponentStreamOutput - a new base class for generic 24 | SAX-style output parsing. Change ExternalComponentStdoutOutput and 25 | ExternalComponentFileOutput to inherit from it. 26 | 27 | o Implement shell_split() and replace shlex.split() with it. shell_split() 28 | will not remove double quotes (i.e. "") when splitting DEFAULT_QUERY. 29 | 30 | o sqlmap: Change DEFAULT_QUERY to use "inline IF" to avoid: 31 | TypeError: unsupported operand type(s) for +: 'bool' and 'str' 32 | Whenever: 33 | context['COOKIES'] = False 34 | 35 | o Introduce `ipv6_address` - new root component for processing IPv6 Address. 36 | Example: "::1" -> ipv6_address -> ... 37 | 38 | o Introduce `domain` - new root component for processing domain names. 39 | Example: "hackersh.org" -> domain -> ... 40 | 41 | o Implement HackershError Exception class and add 3 new error messages: 42 | XXX: not enough data to start (if Component Filter is False) 43 | XXX: command not found (if Ext. Component filename is missing) 44 | XXX: unable to parse (if all Output Handlers failed) 45 | 46 | o Split hackersh/network.py and hackersh/misc.py into multiple files and 47 | implement a simple plug-in architecture to load them during startup 48 | 49 | o Add support for BackTrack 5R3 and 5R2 50 | 51 | Hackersh 0.1 [2013-04-01] 52 | 53 | o Initial commit 54 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for your interest in contributing to Hackersh. We are more than happy to accept external contributions to the project in the form of feedback, bug reports and even better - pull requests :) At this time we are primarily focusing on improving the user-experience and stability of Hackersh for our first release. Please keep this in mind if submitting feature requests, which we're happy to consider for future versions. 4 | 5 | 6 | ## Contributor License Agreement 7 | 8 | Before we can accept patches, there's a quick web form we need you to fill out [here](http://www.clahub.com/agreements/ikotler/hackersh) (**scroll to the bottom!**). 9 | 10 | Hackersh’s CLA is a copy of the one used by Sun Microsystems for all contributions to their projects. 11 | 12 | This particular agreement has been used by other software projects in addition to Sun and is generally accepted as reasonable within the Open Source community. 13 | 14 | [More about CLAs](https://www.google.com/search?q=Contributor%20License%20Agreement) 15 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Ideally, you should be able to just type: 2 | 3 | python setup.py install 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include bin/hackersh README.rst COPYING CHANGELOG 2 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Hackersh 3 | ======== 4 | 5 | `Hackersh `_ ("Hacker Shell") is a shell (command interpreter) written in Python with Pythonect-like syntax, builtin security commands, and out of the box wrappers for various security tools. 6 | 7 | Hello, world 8 | ------------ 9 | 10 | Here is the canonical "Hello, world" example program in Hackersh:: 11 | 12 | "http://localhost" -> url -> nmap -> w3af 13 | 14 | Wait, what? This is a a compacted but 100% complete implementation of a black-box web application vulnerability scanner 15 | 16 | Installation 17 | ------------ 18 | 19 | There are a few ways to install Hackersh. 20 | 21 | 1. You can install directly from PyPI_ using ``easy_install`` or pip_:: 22 | 23 | easy_install hackersh 24 | 25 | or:: 26 | 27 | pip install hackersh 28 | 29 | 2. You can clone the git repository somewhere in your system:: 30 | 31 | git clone git://github.com/ikotler/hackersh.git 32 | 33 | Then you should do following steps:: 34 | 35 | cd hackersh 36 | python setup.py install 37 | 38 | Alternatively, if you use pip_, you can install directly from the git repository:: 39 | 40 | pip install \ 41 | git+git://github.com/ikotler/hackersh.git@master#egg=Hackersh \ 42 | -r https://github.com/ikotler/hackersh/raw/master/doc/requirements.txt 43 | 44 | For any of the above methods, if you want to do a system-wide installation, you will have to do this with *root* permissions (e.g. using ``su`` or ``sudo``). 45 | 46 | .. _PyPI: http://pypi.python.org/pypi/Hackersh/ 47 | .. _pip: http://www.pip-installer.org/ 48 | 49 | License 50 | ------- 51 | 52 | Hackersh is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. 53 | -------------------------------------------------------------------------------- /bin/_preamble.py: -------------------------------------------------------------------------------- 1 | # This makes sure that users don't have to set up their environment 2 | # specially in order to run the interpreter. 3 | 4 | # This helper is not intended to be packaged or installed, it is only 5 | # a developer convenience. By the time Hackersh is actually installed 6 | # somewhere, the environment should already be set up properly without 7 | # the help of this tool. 8 | 9 | 10 | import sys 11 | import os 12 | 13 | 14 | path = os.path.abspath(sys.argv[0]) 15 | 16 | 17 | while os.path.dirname(path) != path: 18 | 19 | if os.path.exists(os.path.join(path, 'hackersh', '__init__.py')): 20 | 21 | sys.path.insert(0, path) 22 | 23 | break 24 | 25 | path = os.path.dirname(path) 26 | -------------------------------------------------------------------------------- /bin/hackersh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2013 Itzik Kotler 4 | # 5 | # This file is part of Hackersh. 6 | # 7 | # Hackersh is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2, or (at your option) 10 | # any later version. 11 | # 12 | # Hackersh is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with Hackersh; see the file COPYING. If not, 19 | # see . 20 | 21 | import sys 22 | import readline 23 | import code 24 | import codeop 25 | import argparse 26 | import os 27 | import atexit 28 | import pythonect 29 | 30 | 31 | try: 32 | 33 | import _preamble 34 | 35 | except ImportError: 36 | 37 | sys.exc_clear() 38 | 39 | 40 | # Local imports 41 | 42 | import hackersh 43 | import hackersh.components 44 | import hackersh.conio 45 | import hackersh.log 46 | 47 | 48 | # Hackersh Console 49 | 50 | class HackershCompile(codeop.Compile): 51 | 52 | def __init__(self): 53 | 54 | codeop.Compile.__init__(self) 55 | 56 | def __call__(self, source, filename, symbol): 57 | 58 | if source[-1] == '\\': 59 | return None 60 | 61 | return source.replace('\\\n', '') 62 | 63 | 64 | class HackershCommandCompiler(codeop.CommandCompiler): 65 | 66 | def __init__(self): 67 | 68 | codeop.CommandCompiler.__init__(self) 69 | 70 | self.compiler = HackershCompile() 71 | 72 | 73 | class HackershInteractiveConsole(code.InteractiveConsole): 74 | 75 | def __init__(self, locals=None, histfile=os.path.expanduser("~/.hackersh_history")): 76 | 77 | code.InteractiveConsole.__init__(self, locals) 78 | 79 | self.compile = HackershCommandCompiler() 80 | 81 | self.init_history(histfile) 82 | 83 | def init_history(self, histfile): 84 | 85 | try: 86 | 87 | readline.read_history_file(histfile) 88 | 89 | except IOError, e: 90 | 91 | hackersh.log.logger.warn('Reading history file %s failed due to %s' % (histfile, e)) 92 | 93 | # No history file 94 | 95 | pass 96 | 97 | atexit.register(self.save_history, histfile) 98 | 99 | def save_history(self, histfile): 100 | 101 | readline.write_history_file(histfile) 102 | 103 | def runcode(self, code_): 104 | 105 | try: 106 | 107 | hackersh.log.logger.debug('Evaluating `%s`' % code_) 108 | 109 | return_value = hackersh.eval(code_, self.locals) 110 | 111 | print return_value 112 | 113 | if return_value is not False: 114 | 115 | # Reset locals to None 116 | 117 | self.locals['_'] = return_value 118 | 119 | except SystemExit: 120 | 121 | raise 122 | 123 | except hackersh.HackershError as e: 124 | 125 | print e.msg 126 | 127 | except: 128 | 129 | self.showtraceback() 130 | 131 | else: 132 | 133 | if code.softspace(sys.stdout, 0): 134 | 135 | print 136 | 137 | 138 | def set_or_update_env(): 139 | 140 | os.environ['HACKERSHPATH'] = os.path.pathsep.join(os.getenv('HACKERSHPATH', '').split(os.path.pathsep) + map(lambda x: os.path.abspath(os.path.join(os.path.dirname(hackersh.components.__file__), '..', 'components')) + '/' + x, ['system', 'internal', 'external'])) 141 | 142 | 143 | def main(): 144 | 145 | locals_ = {} 146 | 147 | banner = "Hackersh version %s ( http://www.hackersh.org )" % hackersh.__version__ 148 | 149 | # Parse command-line arguments 150 | 151 | parser = argparse.ArgumentParser(sys.argv) 152 | 153 | parser.add_argument('script', metavar='file', nargs='?', type=argparse.FileType('rt')) 154 | parser.add_argument('--verbose', '-v', action='count', default=0) 155 | parser.add_argument('--quiet', '-q', help='Do not print the normal Hackersh welcome', action='store_true', default=0) 156 | parser.add_argument('--version', '-V', action='version', version=banner) 157 | 158 | args = parser.parse_args() 159 | 160 | # Set or Update Hackersh Environment Variables 161 | 162 | set_or_update_env() 163 | 164 | # Setup logging level 165 | 166 | if args.verbose: 167 | 168 | hackersh.log.logger.setLevel(hackersh.log.logging.ERROR - ((args.verbose % 4) * 10)) 169 | 170 | hackersh.log.logger.info('Started Hackersh with args = %s' % args) 171 | 172 | # Add current working directory to sys.path 173 | 174 | sys.path.insert(0, os.getcwd()) 175 | 176 | # Extract components into locals_ 177 | 178 | components = hackersh.components.get_all_components(os.getenv('HACKERSHPATH')) 179 | 180 | if not components: 181 | 182 | hackersh.log.logger.warn('No components were found!') 183 | 184 | else: 185 | 186 | locals_.update(components) 187 | 188 | # Script-mode (i.e. ./hackersh script or #!/usr/bin/env hackersh) 189 | 190 | if args.script: 191 | 192 | content = args.script.read() 193 | 194 | scriptname, scriptextension = os.path.splitext(args.script.name) 195 | 196 | if scriptextension: 197 | 198 | parsers = pythonect.internal.parsers.get_parsers(os.path.abspath(os.path.join(os.path.dirname(pythonect.internal.parsers.__file__), '..', 'parsers'))) 199 | 200 | content = parsers[scriptextension[1:]].parse(content) 201 | 202 | if content is None: 203 | 204 | raise Exception("Unable to parse %s with %s" % (scriptname, parsers[scriptextension].__repr__())) 205 | 206 | hackersh.eval(content, locals_) 207 | 208 | args.script.close() 209 | 210 | # Interactive-mode (i.e. ./hackersh) 211 | 212 | else: 213 | 214 | # Change prompt 215 | 216 | sys.ps1 = '% ' 217 | 218 | motd = "Welcome to Hacker Shell Version %s!" % hackersh.__version__ 219 | 220 | banner = "Hackersh Version %s\nCopyright (C) 2013 Itzik Kotler\nVisit http://www.hackersh.org for updates.\n" % hackersh.__version__ 221 | 222 | HackershInteractiveConsole(locals_).interact(banner + hackersh.conio.draw_msgbox(motd) if not args.quiet else '') 223 | 224 | return 0 225 | 226 | 227 | # Entry Point 228 | 229 | if __name__ == "__main__": 230 | 231 | sys.exit(main()) 232 | -------------------------------------------------------------------------------- /distribute_setup.py: -------------------------------------------------------------------------------- 1 | #!python 2 | """Bootstrap distribute installation 3 | 4 | If you want to use setuptools in your package's setup.py, just include this 5 | file in the same directory with it, and add this to the top of your setup.py:: 6 | 7 | from distribute_setup import use_setuptools 8 | use_setuptools() 9 | 10 | If you want to require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, you can do so by supplying 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import os 17 | import sys 18 | import time 19 | import fnmatch 20 | import tempfile 21 | import tarfile 22 | from distutils import log 23 | 24 | try: 25 | from site import USER_SITE 26 | except ImportError: 27 | USER_SITE = None 28 | 29 | try: 30 | import subprocess 31 | 32 | def _python_cmd(*args): 33 | args = (sys.executable,) + args 34 | return subprocess.call(args) == 0 35 | 36 | except ImportError: 37 | # will be used for python 2.3 38 | def _python_cmd(*args): 39 | args = (sys.executable,) + args 40 | # quoting arguments if windows 41 | if sys.platform == 'win32': 42 | def quote(arg): 43 | if ' ' in arg: 44 | return '"%s"' % arg 45 | return arg 46 | args = [quote(arg) for arg in args] 47 | return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 48 | 49 | DEFAULT_VERSION = "0.6.28" 50 | DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" 51 | SETUPTOOLS_FAKED_VERSION = "0.6c11" 52 | 53 | SETUPTOOLS_PKG_INFO = """\ 54 | Metadata-Version: 1.0 55 | Name: setuptools 56 | Version: %s 57 | Summary: xxxx 58 | Home-page: xxx 59 | Author: xxx 60 | Author-email: xxx 61 | License: xxx 62 | Description: xxx 63 | """ % SETUPTOOLS_FAKED_VERSION 64 | 65 | 66 | def _install(tarball, install_args=()): 67 | # extracting the tarball 68 | tmpdir = tempfile.mkdtemp() 69 | log.warn('Extracting in %s', tmpdir) 70 | old_wd = os.getcwd() 71 | try: 72 | os.chdir(tmpdir) 73 | tar = tarfile.open(tarball) 74 | _extractall(tar) 75 | tar.close() 76 | 77 | # going in the directory 78 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 79 | os.chdir(subdir) 80 | log.warn('Now working in %s', subdir) 81 | 82 | # installing 83 | log.warn('Installing Distribute') 84 | if not _python_cmd('setup.py', 'install', *install_args): 85 | log.warn('Something went wrong during the installation.') 86 | log.warn('See the error message above.') 87 | finally: 88 | os.chdir(old_wd) 89 | 90 | 91 | def _build_egg(egg, tarball, to_dir): 92 | # extracting the tarball 93 | tmpdir = tempfile.mkdtemp() 94 | log.warn('Extracting in %s', tmpdir) 95 | old_wd = os.getcwd() 96 | try: 97 | os.chdir(tmpdir) 98 | tar = tarfile.open(tarball) 99 | _extractall(tar) 100 | tar.close() 101 | 102 | # going in the directory 103 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) 104 | os.chdir(subdir) 105 | log.warn('Now working in %s', subdir) 106 | 107 | # building an egg 108 | log.warn('Building a Distribute egg in %s', to_dir) 109 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) 110 | 111 | finally: 112 | os.chdir(old_wd) 113 | # returning the result 114 | log.warn(egg) 115 | if not os.path.exists(egg): 116 | raise IOError('Could not build the egg.') 117 | 118 | 119 | def _do_download(version, download_base, to_dir, download_delay): 120 | egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' 121 | % (version, sys.version_info[0], sys.version_info[1])) 122 | if not os.path.exists(egg): 123 | tarball = download_setuptools(version, download_base, 124 | to_dir, download_delay) 125 | _build_egg(egg, tarball, to_dir) 126 | sys.path.insert(0, egg) 127 | import setuptools 128 | setuptools.bootstrap_install_from = egg 129 | 130 | 131 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 132 | to_dir=os.curdir, download_delay=15, no_fake=True): 133 | # making sure we use the absolute path 134 | to_dir = os.path.abspath(to_dir) 135 | was_imported = 'pkg_resources' in sys.modules or \ 136 | 'setuptools' in sys.modules 137 | try: 138 | try: 139 | import pkg_resources 140 | if not hasattr(pkg_resources, '_distribute'): 141 | if not no_fake: 142 | _fake_setuptools() 143 | raise ImportError 144 | except ImportError: 145 | return _do_download(version, download_base, to_dir, download_delay) 146 | try: 147 | pkg_resources.require("distribute>=" + version) 148 | return 149 | except pkg_resources.VersionConflict: 150 | e = sys.exc_info()[1] 151 | if was_imported: 152 | sys.stderr.write( 153 | "The required version of distribute (>=%s) is not available,\n" 154 | "and can't be installed while this script is running. Please\n" 155 | "install a more recent version first, using\n" 156 | "'easy_install -U distribute'." 157 | "\n\n(Currently using %r)\n" % (version, e.args[0])) 158 | sys.exit(2) 159 | else: 160 | del pkg_resources, sys.modules['pkg_resources'] # reload ok 161 | return _do_download(version, download_base, to_dir, 162 | download_delay) 163 | except pkg_resources.DistributionNotFound: 164 | return _do_download(version, download_base, to_dir, 165 | download_delay) 166 | finally: 167 | if not no_fake: 168 | _create_fake_setuptools_pkg_info(to_dir) 169 | 170 | 171 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, 172 | to_dir=os.curdir, delay=15): 173 | """Download distribute from a specified location and return its filename 174 | 175 | `version` should be a valid distribute version number that is available 176 | as an egg for download under the `download_base` URL (which should end 177 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 178 | `delay` is the number of seconds to pause before an actual download 179 | attempt. 180 | """ 181 | # making sure we use the absolute path 182 | to_dir = os.path.abspath(to_dir) 183 | try: 184 | from urllib.request import urlopen 185 | except ImportError: 186 | from urllib2 import urlopen 187 | tgz_name = "distribute-%s.tar.gz" % version 188 | url = download_base + tgz_name 189 | saveto = os.path.join(to_dir, tgz_name) 190 | src = dst = None 191 | if not os.path.exists(saveto): # Avoid repeated downloads 192 | try: 193 | log.warn("Downloading %s", url) 194 | src = urlopen(url) 195 | # Read/write all in one block, so we don't create a corrupt file 196 | # if the download is interrupted. 197 | data = src.read() 198 | dst = open(saveto, "wb") 199 | dst.write(data) 200 | finally: 201 | if src: 202 | src.close() 203 | if dst: 204 | dst.close() 205 | return os.path.realpath(saveto) 206 | 207 | 208 | def _no_sandbox(function): 209 | def __no_sandbox(*args, **kw): 210 | try: 211 | from setuptools.sandbox import DirectorySandbox 212 | if not hasattr(DirectorySandbox, '_old'): 213 | def violation(*args): 214 | pass 215 | DirectorySandbox._old = DirectorySandbox._violation 216 | DirectorySandbox._violation = violation 217 | patched = True 218 | else: 219 | patched = False 220 | except ImportError: 221 | patched = False 222 | 223 | try: 224 | return function(*args, **kw) 225 | finally: 226 | if patched: 227 | DirectorySandbox._violation = DirectorySandbox._old 228 | del DirectorySandbox._old 229 | 230 | return __no_sandbox 231 | 232 | 233 | def _patch_file(path, content): 234 | """Will backup the file then patch it""" 235 | existing_content = open(path).read() 236 | if existing_content == content: 237 | # already patched 238 | log.warn('Already patched.') 239 | return False 240 | log.warn('Patching...') 241 | _rename_path(path) 242 | f = open(path, 'w') 243 | try: 244 | f.write(content) 245 | finally: 246 | f.close() 247 | return True 248 | 249 | _patch_file = _no_sandbox(_patch_file) 250 | 251 | 252 | def _same_content(path, content): 253 | return open(path).read() == content 254 | 255 | 256 | def _rename_path(path): 257 | new_name = path + '.OLD.%s' % time.time() 258 | log.warn('Renaming %s into %s', path, new_name) 259 | os.rename(path, new_name) 260 | return new_name 261 | 262 | 263 | def _remove_flat_installation(placeholder): 264 | if not os.path.isdir(placeholder): 265 | log.warn('Unkown installation at %s', placeholder) 266 | return False 267 | found = False 268 | for file in os.listdir(placeholder): 269 | if fnmatch.fnmatch(file, 'setuptools*.egg-info'): 270 | found = True 271 | break 272 | if not found: 273 | log.warn('Could not locate setuptools*.egg-info') 274 | return 275 | 276 | log.warn('Removing elements out of the way...') 277 | pkg_info = os.path.join(placeholder, file) 278 | if os.path.isdir(pkg_info): 279 | patched = _patch_egg_dir(pkg_info) 280 | else: 281 | patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) 282 | 283 | if not patched: 284 | log.warn('%s already patched.', pkg_info) 285 | return False 286 | # now let's move the files out of the way 287 | for element in ('setuptools', 'pkg_resources.py', 'site.py'): 288 | element = os.path.join(placeholder, element) 289 | if os.path.exists(element): 290 | _rename_path(element) 291 | else: 292 | log.warn('Could not find the %s element of the ' 293 | 'Setuptools distribution', element) 294 | return True 295 | 296 | _remove_flat_installation = _no_sandbox(_remove_flat_installation) 297 | 298 | 299 | def _after_install(dist): 300 | log.warn('After install bootstrap.') 301 | placeholder = dist.get_command_obj('install').install_purelib 302 | _create_fake_setuptools_pkg_info(placeholder) 303 | 304 | 305 | def _create_fake_setuptools_pkg_info(placeholder): 306 | if not placeholder or not os.path.exists(placeholder): 307 | log.warn('Could not find the install location') 308 | return 309 | pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) 310 | setuptools_file = 'setuptools-%s-py%s.egg-info' % \ 311 | (SETUPTOOLS_FAKED_VERSION, pyver) 312 | pkg_info = os.path.join(placeholder, setuptools_file) 313 | if os.path.exists(pkg_info): 314 | log.warn('%s already exists', pkg_info) 315 | return 316 | 317 | if not os.access(pkg_info, os.W_OK): 318 | log.warn("Don't have permissions to write %s, skipping", pkg_info) 319 | 320 | log.warn('Creating %s', pkg_info) 321 | f = open(pkg_info, 'w') 322 | try: 323 | f.write(SETUPTOOLS_PKG_INFO) 324 | finally: 325 | f.close() 326 | 327 | pth_file = os.path.join(placeholder, 'setuptools.pth') 328 | log.warn('Creating %s', pth_file) 329 | f = open(pth_file, 'w') 330 | try: 331 | f.write(os.path.join(os.curdir, setuptools_file)) 332 | finally: 333 | f.close() 334 | 335 | _create_fake_setuptools_pkg_info = _no_sandbox( 336 | _create_fake_setuptools_pkg_info 337 | ) 338 | 339 | 340 | def _patch_egg_dir(path): 341 | # let's check if it's already patched 342 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 343 | if os.path.exists(pkg_info): 344 | if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): 345 | log.warn('%s already patched.', pkg_info) 346 | return False 347 | _rename_path(path) 348 | os.mkdir(path) 349 | os.mkdir(os.path.join(path, 'EGG-INFO')) 350 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') 351 | f = open(pkg_info, 'w') 352 | try: 353 | f.write(SETUPTOOLS_PKG_INFO) 354 | finally: 355 | f.close() 356 | return True 357 | 358 | _patch_egg_dir = _no_sandbox(_patch_egg_dir) 359 | 360 | 361 | def _before_install(): 362 | log.warn('Before install bootstrap.') 363 | _fake_setuptools() 364 | 365 | 366 | def _under_prefix(location): 367 | if 'install' not in sys.argv: 368 | return True 369 | args = sys.argv[sys.argv.index('install') + 1:] 370 | for index, arg in enumerate(args): 371 | for option in ('--root', '--prefix'): 372 | if arg.startswith('%s=' % option): 373 | top_dir = arg.split('root=')[-1] 374 | return location.startswith(top_dir) 375 | elif arg == option: 376 | if len(args) > index: 377 | top_dir = args[index + 1] 378 | return location.startswith(top_dir) 379 | if arg == '--user' and USER_SITE is not None: 380 | return location.startswith(USER_SITE) 381 | return True 382 | 383 | 384 | def _fake_setuptools(): 385 | log.warn('Scanning installed packages') 386 | try: 387 | import pkg_resources 388 | except ImportError: 389 | # we're cool 390 | log.warn('Setuptools or Distribute does not seem to be installed.') 391 | return 392 | ws = pkg_resources.working_set 393 | try: 394 | setuptools_dist = ws.find( 395 | pkg_resources.Requirement.parse('setuptools', replacement=False) 396 | ) 397 | except TypeError: 398 | # old distribute API 399 | setuptools_dist = ws.find( 400 | pkg_resources.Requirement.parse('setuptools') 401 | ) 402 | 403 | if setuptools_dist is None: 404 | log.warn('No setuptools distribution found') 405 | return 406 | # detecting if it was already faked 407 | setuptools_location = setuptools_dist.location 408 | log.warn('Setuptools installation detected at %s', setuptools_location) 409 | 410 | # if --root or --preix was provided, and if 411 | # setuptools is not located in them, we don't patch it 412 | if not _under_prefix(setuptools_location): 413 | log.warn('Not patching, --root or --prefix is installing Distribute' 414 | ' in another location') 415 | return 416 | 417 | # let's see if its an egg 418 | if not setuptools_location.endswith('.egg'): 419 | log.warn('Non-egg installation') 420 | res = _remove_flat_installation(setuptools_location) 421 | if not res: 422 | return 423 | else: 424 | log.warn('Egg installation') 425 | pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') 426 | if (os.path.exists(pkg_info) and 427 | _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): 428 | log.warn('Already patched.') 429 | return 430 | log.warn('Patching...') 431 | # let's create a fake egg replacing setuptools one 432 | res = _patch_egg_dir(setuptools_location) 433 | if not res: 434 | return 435 | log.warn('Patched done.') 436 | _relaunch() 437 | 438 | 439 | def _relaunch(): 440 | log.warn('Relaunching...') 441 | # we have to relaunch the process 442 | # pip marker to avoid a relaunch bug 443 | _cmd = ['-c', 'install', '--single-version-externally-managed'] 444 | if sys.argv[:3] == _cmd: 445 | sys.argv[0] = 'setup.py' 446 | args = [sys.executable] + sys.argv 447 | sys.exit(subprocess.call(args)) 448 | 449 | 450 | def _extractall(self, path=".", members=None): 451 | """Extract all members from the archive to the current working 452 | directory and set owner, modification time and permissions on 453 | directories afterwards. `path' specifies a different directory 454 | to extract to. `members' is optional and must be a subset of the 455 | list returned by getmembers(). 456 | """ 457 | import copy 458 | import operator 459 | from tarfile import ExtractError 460 | directories = [] 461 | 462 | if members is None: 463 | members = self 464 | 465 | for tarinfo in members: 466 | if tarinfo.isdir(): 467 | # Extract directories with a safe mode. 468 | directories.append(tarinfo) 469 | tarinfo = copy.copy(tarinfo) 470 | tarinfo.mode = 448 # decimal for oct 0700 471 | self.extract(tarinfo, path) 472 | 473 | # Reverse sort directories. 474 | if sys.version_info < (2, 4): 475 | def sorter(dir1, dir2): 476 | return cmp(dir1.name, dir2.name) 477 | directories.sort(sorter) 478 | directories.reverse() 479 | else: 480 | directories.sort(key=operator.attrgetter('name'), reverse=True) 481 | 482 | # Set correct owner, mtime and filemode on directories. 483 | for tarinfo in directories: 484 | dirpath = os.path.join(path, tarinfo.name) 485 | try: 486 | self.chown(tarinfo, dirpath) 487 | self.utime(tarinfo, dirpath) 488 | self.chmod(tarinfo, dirpath) 489 | except ExtractError: 490 | e = sys.exc_info()[1] 491 | if self.errorlevel > 1: 492 | raise 493 | else: 494 | self._dbg(1, "tarfile: %s" % e) 495 | 496 | 497 | def _build_install_args(argv): 498 | install_args = [] 499 | user_install = '--user' in argv 500 | if user_install and sys.version_info < (2, 6): 501 | log.warn("--user requires Python 2.6 or later") 502 | raise SystemExit(1) 503 | if user_install: 504 | install_args.append('--user') 505 | return install_args 506 | 507 | 508 | def main(argv, version=DEFAULT_VERSION): 509 | """Install or upgrade setuptools and EasyInstall""" 510 | tarball = download_setuptools() 511 | _install(tarball, _build_install_args(argv)) 512 | 513 | 514 | if __name__ == '__main__': 515 | main(sys.argv[1:]) 516 | -------------------------------------------------------------------------------- /doc/TODO: -------------------------------------------------------------------------------- 1 | Hackersh TODOs 2 | ============== 3 | 4 | Priority 5 | -------- 6 | 7 | - Add Unit Tests 8 | 9 | - Add Documentation 10 | 11 | - Test IPv6 Components 12 | 13 | 14 | Nice-to-Have 15 | ------------ 16 | 17 | - Add Tools (sorted by no particular order): 18 | - Metasploit 19 | - OpenVAS 20 | - ScanSSH 21 | - TheHarvester 22 | - Maltego 23 | - Hydra 24 | - Traceroute 25 | - TcpTraceroute 26 | - WHOIS 27 | - Nmap NSE Scripts? 28 | - hping3 29 | - Brutus 30 | - medusa 31 | - fping 32 | - netenum 33 | - unicornscan 34 | - scanrand 35 | - hping 36 | - sinfp 37 | - Netcat? 38 | - John The Ripper 39 | - Hping 40 | - Dig 41 | - Nslookup? 42 | - netglub 43 | 44 | - Implement "Save As" (CSV? XML? HTML?) Components 45 | 46 | - Add support for .hackershrc 47 | 48 | - Implement an `alias` built-in command 49 | 50 | - Add '.' commands (aka. built-in commands). 51 | 52 | - Cross-platform API to get network routing 53 | 54 | 55 | Future 56 | ------ 57 | 58 | - Add support for SQLLite3 (and other?) backend 59 | 60 | - Implement `cast` built-in command. 61 | 62 | 63 | Science Fiction 64 | --------------- 65 | 66 | - GUI (UI Frontend) 67 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | # requirements.txt for Python's PIP (see: http://www.pip-installer.org/en/latest/requirements.html) 2 | pythonect>=0.6.0 3 | prettytable>=0.6.1, 4 | netaddr>=0.7.10 5 | networkx>=1.7 6 | -------------------------------------------------------------------------------- /hackersh/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | from _version import __version__ 20 | 21 | 22 | # API 23 | 24 | from objects import * 25 | from exceptions import * 26 | from eval import eval 27 | -------------------------------------------------------------------------------- /hackersh/_ordereddict.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | try: 20 | 21 | # Python 2.7+ 22 | 23 | from collections import OrderedDict 24 | 25 | except Exception as e: 26 | 27 | # Python2.6 28 | 29 | from ordereddict import OrderedDict 30 | -------------------------------------------------------------------------------- /hackersh/_version.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.2.0' 2 | -------------------------------------------------------------------------------- /hackersh/components/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import importlib 20 | import glob 21 | import os 22 | import sys 23 | 24 | 25 | # Local imports 26 | 27 | import hackersh 28 | import hackersh.log 29 | 30 | 31 | def get_all_components(components_path): 32 | 33 | instances = {} 34 | 35 | # For each directory in components path 36 | 37 | for component_directory in components_path.split(os.path.pathsep): 38 | 39 | # Add component directory to path 40 | 41 | sys.path.insert(0, component_directory) 42 | 43 | components_list = glob.glob(component_directory + '/*.py') 44 | 45 | # For each *.py file in directory 46 | 47 | for component_file in components_list: 48 | 49 | component = os.path.splitext(os.path.basename(component_file))[0] 50 | 51 | try: 52 | 53 | current_module = importlib.import_module(component) 54 | 55 | for name in dir(current_module): 56 | 57 | if not name.startswith('_'): 58 | 59 | obj = getattr(current_module, name) 60 | 61 | try: 62 | 63 | if obj != hackersh.Component and issubclass(obj, hackersh.Component): 64 | 65 | instances[name.lower()] = obj 66 | 67 | hackersh.log.logger.debug('Registering %s as %s' % (obj, name.lower())) 68 | 69 | except TypeError: 70 | 71 | pass 72 | 73 | except Exception as e: 74 | 75 | hackersh.log.logger.warn('Unable to register %s due to: %s' % (component_file, e)) 76 | 77 | pass 78 | 79 | return instances 80 | -------------------------------------------------------------------------------- /hackersh/components/external/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikotler/hackersh/13af753815290891aab749a771c543c3cb715cc7/hackersh/components/external/__init__.py -------------------------------------------------------------------------------- /hackersh/components/external/amap.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.1" 28 | 29 | 30 | # Implementation 31 | 32 | class Amap(hackersh.objects.ExternalComponentFileOutput): 33 | 34 | class AmapCSVOutputHandler(hackersh.objects.CSVOutputHandler): 35 | 36 | def startDocument(self): 37 | 38 | self._entry_or_entries = [] 39 | 40 | # i.e. test.old:21:tcp:open::ftp:220 ProFTPD 1.3.4a Server (Debian) [ffff127.0.0.1]\r\n500 GET not understood\r\n500 Invalid command try being more creative\r\n:"220 ProFTPD 1.3.4a Server (Debian) [::ffff:127.0.0.1]\r\n500 GET not understood\r\n500 Invalid command: try being more creative\r\n" 41 | 42 | def startRow(self, row): 43 | 44 | try: 45 | 46 | # IP_ADDRESS:PORT:PROTOCOL:PORT_STATUS:SSL:IDENTIFICATION:PRINTABLE_BANNER:FULL_BANNER 47 | 48 | (ip_addr, port, proto, port_status, ssl, identification) = row[:6] 49 | 50 | self._entry_or_entries.extend([{'PROTO': proto.upper(), 'PORT': str(int(port)), 'SERVICE': identification.upper()}]) 51 | 52 | except Exception: 53 | 54 | pass 55 | 56 | def endRow(self): 57 | 58 | pass 59 | 60 | def endDocument(self): 61 | 62 | for entry in self._entry_or_entries: 63 | 64 | self._output.append(hackersh.objects.RemoteSessionContext(self._context, **entry)) 65 | 66 | if not self._output: 67 | 68 | self._output.append(self._context) 69 | 70 | # CSV Parsing Parameter 71 | 72 | delimiter = ':' 73 | 74 | # Consts 75 | 76 | DEFAULT_FILENAME = "amap" 77 | 78 | DEFAULT_OUTPUT_OPTIONS = "-m -o" 79 | 80 | DEFAULT_FILTER = \ 81 | "(context['IPV4_ADDRESS'] or context['HOSTNAME']) and context['PROTO'] == 'TCP'" 82 | 83 | DEFAULT_QUERY = \ 84 | "(context['IPV4_ADDRESS'] or context['HOSTNAME']) + ' ' + context['PORT']" 85 | -------------------------------------------------------------------------------- /hackersh/components/external/dnsdict6.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.0" 28 | 29 | 30 | # Implementation 31 | 32 | class DnsDict6(hackersh.objects.ExternalComponentStdoutOutput): 33 | 34 | class DnsDict6IPv4Output(hackersh.objects.SimpleRegExHandler): 35 | 36 | PATTERN = "(?P.*)\s+->\s+(?P.*)" 37 | 38 | class DnsDict6IPv6Output(hackersh.objects.SimpleRegExHandler): 39 | 40 | PATTERN = "(?P.*)\s+=>\s+(?P.*)" 41 | 42 | # Consts 43 | 44 | DEFAULT_FILENAME = "dnsdict6" 45 | 46 | DEFAULT_OUTPUT_OPTIONS = '' 47 | 48 | DEFAULT_QUERY = DEFAULT_FILTER = "context['DOMAIN']" 49 | -------------------------------------------------------------------------------- /hackersh/components/external/nbtscan.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import csv 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | 26 | 27 | # Metadata 28 | 29 | __author__ = "Itzik Kotler " 30 | __version__ = "0.1.1" 31 | 32 | 33 | # Implementation 34 | 35 | class NbtScan(hackersh.objects.ExternalComponentStdoutOutput): 36 | 37 | class NbtScanStdoutOutputHandler(hackersh.objects.StdoutOutputHandler): 38 | 39 | def startDocument(self): 40 | 41 | self._names = {} 42 | 43 | def feed(self, data): 44 | 45 | for row in csv.reader(data.split('\n'), delimiter=','): 46 | 47 | # i.e. 192.168.1.106,TV ,Workstation Service 48 | 49 | try: 50 | 51 | (ip_addr, group_name, netbios_service) = row[:3] 52 | 53 | self._names[group_name.strip().upper()] = self._names.get(group_name.strip().upper(), []) + [netbios_service.strip()] 54 | 55 | except Exception: 56 | 57 | pass 58 | 59 | def endDocument(self): 60 | 61 | if self._names: 62 | 63 | self._output.append(hackersh.objects.RemoteSessionContext(self._context, **{'PROTO': 'UDP', 'PORT': '137', 'SERVICE': 'NETBIOS-NS', 'NETBIOS-NS': {'NAMES': self._names}})) 64 | 65 | # Consts 66 | 67 | DEFAULT_FILENAME = "nbtscan" 68 | 69 | DEFAULT_OUTPUT_OPTIONS = "-v -h -q -s ," 70 | 71 | DEFAULT_FILTER = DEFAULT_QUERY = "context['IPV4_ADDRESS']" 72 | -------------------------------------------------------------------------------- /hackersh/components/external/nikto.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.1" 28 | 29 | 30 | # Implementation 31 | 32 | class Nikto(hackersh.objects.ExternalComponentFileOutput): 33 | 34 | # XML Parser(s) 35 | 36 | class NiktoXMLOutputHandler(hackersh.objects.XMLOutputHandler): 37 | 38 | def startDocument(self): 39 | 40 | self._vulnerabilities = [] 41 | 42 | def startElement(self, name, attrs): 43 | 44 | # 45 | # 46 | # 47 | # 48 | # 49 | # 50 | 51 | if name == "item": 52 | 53 | self._entry = {'OSVDBID': str(attrs['osvdbid'])} 54 | 55 | def characters(self, content): 56 | 57 | self._data = str(content) 58 | 59 | def endElement(self, name): 60 | 61 | if name == "item": 62 | 63 | self._entry['DESTINATION'] = self._entry['NAMELINK'] 64 | 65 | self._vulnerabilities.append(dict(self._entry)) 66 | 67 | self._entry = {} 68 | 69 | else: 70 | 71 | self._entry[str(name).upper()] = self._data 72 | 73 | def endDocument(self): 74 | 75 | self._output.append(hackersh.objects.RemoteSessionContext(self._context, **{'VULNERABILITIES': self._context.get('VULNERABILITIES', []) + self._vulnerabilities})) 76 | 77 | # Consts 78 | 79 | DEFAULT_FILENAME = "nikto" 80 | 81 | DEFAULT_STDIN_BUFFER = "n\n\n" 82 | 83 | DEFAULT_OUTPUT_OPTIONS = "-Format xml -o" 84 | 85 | DEFAULT_FILTER = \ 86 | "(context['SERVICE'] == 'HTTP' or context['SERVICE'] == 'HTTPS') and " \ 87 | "(context['IPV4_ADDRESS'] or context['HOSTNAME']) and " \ 88 | "context['PROTO'] == 'TCP'" 89 | 90 | DEFAULT_QUERY = \ 91 | "'-host ' + (context['IPV4_ADDRESS'] or context['HOSTNAME']) + ' -port ' + context['PORT']" 92 | -------------------------------------------------------------------------------- /hackersh/components/external/nmap.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.1" 28 | 29 | 30 | # Implementation 31 | 32 | class Nmap(hackersh.objects.ExternalComponentFileOutput): 33 | 34 | # XML Parser(s) 35 | 36 | class NmapXMLOutputHandler(hackersh.objects.XMLOutputHandler): 37 | 38 | def startElement(self, name, attrs): 39 | 40 | # i.e. 41 | 42 | if name == "port": 43 | 44 | self._open = False 45 | 46 | self._portid = str(attrs['portid']).upper() 47 | 48 | self._protocol = str(attrs['protocol']).upper() 49 | 50 | # i.e. 51 | 52 | if name == "state": 53 | 54 | if attrs['state'] == 'open': 55 | 56 | self._open = True 57 | 58 | # i.e. 59 | 60 | if name == "service": 61 | 62 | self._service = str(attrs['name']).upper() 63 | 64 | def endElement(self, name): 65 | 66 | if name == "port" and self._open: 67 | 68 | spinoffs = [] 69 | 70 | # 'HTTP-PROXY' => 'HTTP' Spinoff. 71 | 72 | if self._service == 'HTTP-PROXY': 73 | 74 | spinoffs.extend([{"PROTO": self._protocol.upper(), "PORT": self._portid, "SERVICE": 'HTTP'}]) 75 | 76 | # PORT is already set, but with a different SERVICE? Spinoff. 77 | 78 | if self._context["PORT"] == self._portid \ 79 | and self._context['PROTO'] == self._protocol.upper() \ 80 | and self._context['SERVICE'] != self._service and self._service != 'HTTP-PROXY': 81 | 82 | # "AS IT IS" Spinoff. 83 | 84 | spinoffs.extend([{}]) 85 | 86 | # i.e. {'PORT': 22, 'SERVICE': 'SSH'} 87 | 88 | spinoffs.extend([{'PROTO': self._protocol.upper(), 'PORT': self._portid, 'SERVICE': self._service}]) 89 | 90 | for entry in spinoffs: 91 | 92 | # Context per entry 93 | 94 | self._output.append(hackersh.objects.RemoteSessionContext(self._context, **entry)) 95 | 96 | def endDocument(self): 97 | 98 | if not self._output: 99 | 100 | self._output.append(self._context) 101 | 102 | # Consts 103 | 104 | DEFAULT_FILENAME = "nmap" 105 | 106 | DEFAULT_OUTPUT_OPTIONS = "-oX" 107 | 108 | DEFAULT_QUERY = DEFAULT_FILTER = "context['IPV4_ADDRESS'] or context['HOSTNAME']" 109 | -------------------------------------------------------------------------------- /hackersh/components/external/ping.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.1" 28 | 29 | 30 | # Implementation 31 | 32 | class Ping(hackersh.objects.ExternalComponentReturnValueOutput): 33 | 34 | def _processor(self, context, data): 35 | 36 | retval = False 37 | 38 | # i.e. Return Value == 0 39 | 40 | if data == 0: 41 | 42 | retval = hackersh.objects.RemoteSessionContext(context, PINGABLE=True) 43 | 44 | return retval 45 | 46 | # Consts 47 | 48 | DEFAULT_FILENAME = "ping" 49 | 50 | DEFAULT_OUTPUT_OPTIONS = "-c 3" 51 | 52 | DEFAULT_QUERY = DEFAULT_FILTER = "context['IPV4_ADDRESS'] or context['HOSTNAME']" 53 | -------------------------------------------------------------------------------- /hackersh/components/external/sqlmap.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.2" 28 | 29 | 30 | # Implementation 31 | 32 | class SqlMap(hackersh.objects.ExternalComponentStdoutOutput): 33 | 34 | # --- 35 | # Place: GET 36 | # Parameter: id 37 | # Type: error-based 38 | # Title: MySQL >= 5.0 AND error-based - WHERE or HAVING clause 39 | # Payload: id=vGep' AND (SELECT 4752 FROM(SELECT COUNT(*),CONCAT(0x3a79706f3a,(SELECT (CASE WHEN (4752=4752) THEN 1 ELSE 0 END)),0x3a7a74783a,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a) AND 'ZzRA'='ZzRA&Submit=Submit 40 | # 41 | # Type: UNION query 42 | # Title: MySQL UNION query (NULL) - 2 columns 43 | # Payload: id=vGep' LIMIT 1,1 UNION ALL SELECT CONCAT(0x3a79706f3a,0x4f674d774c6351717853,0x3a7a74783a), NULL#&Submit=Submit 44 | # 45 | # Type: AND/OR time-based blind 46 | # Title: MySQL < 5.0.12 AND time-based blind (heavy query) 47 | # Payload: id=vGep' AND 7534=BENCHMARK(5000000,MD5(0x6d704e4c)) AND 'eALp'='eALp&Submit=Submit 48 | # --- 49 | 50 | class SqlMapStdoutOutputHandler(hackersh.objects.StdoutOutputHandler): 51 | 52 | def startDocument(self): 53 | 54 | self._vulnerabilities = [] 55 | 56 | def feed(self, data): 57 | 58 | for vuln_parameter in data.split('---'): 59 | 60 | if vuln_parameter.startswith('\nPlace'): 61 | 62 | entry = {} 63 | 64 | for line in vuln_parameter.split('\n'): 65 | 66 | if line.find(':') == -1: 67 | 68 | if entry: 69 | 70 | # Fixup: if GET && Append URL to NAMELINK Value 71 | 72 | if entry['Place'] == 'GET': 73 | 74 | entry['DESTINATION'] = self._context['URL'] + entry['DESTINATION'] 75 | 76 | self.vulnerabilities.append(dict(entry)) 77 | 78 | continue 79 | 80 | (k, v) = line.lstrip().split(':') 81 | 82 | entry[self.SQLMAP_KEYS_TO_GENERIC_WEB_VULN_KEYS.get(k, k)] = v.lstrip() 83 | 84 | def endDocument(self): 85 | 86 | self._output.append(hackersh.objects.RemoteSessionContext(self._context, **{'VULNERABILITIES': self._context.get('VULNERABILITIES', []) + self._vulnerabilities})) 87 | 88 | # Consts 89 | 90 | SQLMAP_KEYS_TO_GENERIC_WEB_VULN_KEYS = {'Title': 'DESCRIPTION', 'Payload': 'DESTINATION'} 91 | 92 | # Consts 93 | 94 | DEFAULT_FILENAME = "sqlmap.py" 95 | 96 | DEFAULT_OUTPUT_OPTIONS = '' 97 | 98 | DEFAULT_FILTER = "context['URL']" 99 | 100 | DEFAULT_QUERY = \ 101 | "(('--cookie ' + str(context['COOKIES'])) if context['COOKIES'] else '') + ' -u ' + context['URL']" 102 | -------------------------------------------------------------------------------- /hackersh/components/external/w3af.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import tempfile 20 | import os 21 | import subprocess 22 | import shlex 23 | 24 | 25 | # Local imports 26 | 27 | import hackersh.objects 28 | 29 | 30 | # Metadata 31 | 32 | __author__ = "Itzik Kotler " 33 | __version__ = "0.1.1" 34 | 35 | 36 | # Implementation 37 | 38 | class W3af(hackersh.objects.ExternalComponentFileOutput): 39 | 40 | class W3afHTMLOutputHandler(hackersh.objects.HTMLOutputHandler): 41 | 42 | def startDocument(self): 43 | 44 | self._dups = {} 45 | 46 | self._data = "" 47 | 48 | self._export_data = False 49 | 50 | self._in_tr = False 51 | 52 | self._vulnerabilities = [] 53 | 54 | def handle_starttag(self, tag, attrs): 55 | 56 | if self._in_tr: 57 | 58 | if tag == 'td' and attrs == [('class', 'default'), ('width', '80%')]: 59 | 60 | self._export_data = True 61 | 62 | if tag == 'tr': 63 | 64 | self._in_tr = True 65 | 66 | def handle_endtag(self, tag): 67 | 68 | if tag == 'tr': 69 | 70 | self._in_tr = False 71 | 72 | if tag == 'td' and self._export_data: 73 | 74 | self._export_data = False 75 | 76 | if self._data.find('\nSeverity'): 77 | 78 | details = self._data.split('\nSeverity')[0].split('URL : ') 79 | 80 | else: 81 | 82 | details = self._data.split('URL : ') 83 | 84 | if details[0].find('.') != -1: 85 | 86 | # Remove the 'This vulnerability was found in the request with id 484.' 87 | 88 | details[0] = '.'.join(details[0].split('.')[:-2]) 89 | 90 | if not details[0].strip() in self._dups: 91 | 92 | self._vulnerabilities.append({'DESCRIPTION': details[0], 'DESTINATION': details[1]}) 93 | 94 | self._dups[details[0].strip()] = True 95 | 96 | self._data = "" 97 | 98 | def handle_data(self, data): 99 | 100 | if self._export_data: 101 | 102 | self._data = self._data + data 103 | 104 | def endDocument(self): 105 | 106 | self._output.append(hackersh.objects.RemoteSessionContext(self._context, **{'VULNERABILITIES': self._context.get('VULNERABILITIES', []) + self._vulnerabilities})) 107 | 108 | # class W3afCSVOutputHandler(hackersh.objects.CSVOutputHandler): 109 | # 110 | # def startDocument(self): 111 | # 112 | # self._vulnerabilities = [] 113 | # 114 | # # i.e. Cross site scripting vulnerability,GET,http://192.168.1.108:8008/feed.gtl?uid=,uid,uid=%3CSCrIPT%3Ealert%28%22flgC%22%29%3C%2FSCrIPT%3E,[1499],|Cross Site Scripting was found at: "http://192.168.1.108:8008/feed.gtl", using HTTP method GET. The sent data was: "uid=%3CSCrIPT%3Ealert%28%22flgC%22%29%3C%2FSCrIPT%3E". This vulnerability affects ALL browsers. This vulnerability was found in the request with id 1499.| 115 | # 116 | # def startRow(self, row): 117 | # 118 | # try: 119 | # 120 | # (desc, method, url) = row[:3] 121 | # 122 | # self._vulnerabilities.append({'DESCRIPTION': desc, 'DESTINATION': url}) 123 | # 124 | # except Exception: 125 | # 126 | # pass 127 | # 128 | # def endRow(self): 129 | # 130 | # pass 131 | # 132 | # def endDocument(self): 133 | # 134 | # self._output.append(hackersh.objects.RemoteSessionContext(self._context, **{'VULNERABILITIES': self._context.get('VULNERABILITIES', []) + self._vulnerabilities})) 135 | 136 | # Custom _execute 137 | 138 | def _execute(self, argv, context): 139 | 140 | if len(argv) < 2: 141 | 142 | return False 143 | 144 | tmp_script_file = tempfile.NamedTemporaryFile() 145 | 146 | tmp_output_file = tempfile.NamedTemporaryFile() 147 | 148 | tmp_input_csv_file = tempfile.NamedTemporaryFile() 149 | 150 | tmp_cj_file = tempfile.NamedTemporaryFile() 151 | 152 | url = argv[1] 153 | 154 | tmp_input_csv_file.write("GET,%s,''" % url) 155 | 156 | tmp_input_csv_file.flush() 157 | 158 | script_content = [ 159 | "plugins", 160 | "output console, csv_file, textFile, htmlFile", 161 | "output config csv_file", 162 | "set output_file /tmp/output.csv", 163 | "back", 164 | "output config console", 165 | "set verbose False", 166 | "back", 167 | "output config textFile", 168 | "set httpFileName /tmp/output-http.txt", 169 | "set fileName /tmp/output.txt", 170 | "set verbose True", 171 | "back", 172 | "output htmlFile", 173 | "output config htmlFile", 174 | "set fileName %s" % tmp_output_file.name, 175 | "set verbose False", 176 | "back", 177 | "output config xmlFile", 178 | "set fileName /tmp/output.xml", 179 | "back", 180 | "back" 181 | ] 182 | 183 | # Cookies? 184 | 185 | cj = context['COOKIES'] 186 | 187 | if cj: 188 | 189 | cj.save(tmp_cj_file.name, True, True) 190 | 191 | script_content.extend([ 192 | "http-settings", 193 | "set cookieJarFile %s" % tmp_cj_file.name, 194 | "back" 195 | ]) 196 | 197 | tmp_cj_file.flush() 198 | 199 | os.fsync(tmp_cj_file.fileno()) 200 | 201 | # User-Agent? 202 | 203 | ua = context['USER-AGENT'] 204 | 205 | if ua: 206 | 207 | script_content.extend([ 208 | "http-settings", 209 | "set userAgent %s" % ua, 210 | "back", 211 | ]) 212 | 213 | # Visited URL's? 214 | 215 | visited_urls_list = context['VISITED_URLS'] 216 | 217 | if visited_urls_list: 218 | 219 | script_content.extend([ 220 | "misc-settings", 221 | "set nonTargets %s" % ','.join(visited_urls_list), 222 | "back" 223 | ]) 224 | 225 | pass 226 | 227 | script_content.extend([ 228 | "plugins", 229 | "grep all, !pathDisclosure" 230 | ]) 231 | 232 | if self._kwargs.get('step', False): 233 | 234 | script_content.extend([ 235 | "discovery !all, allowedMethods, importResults", 236 | "discovery config importResults", 237 | "set input_csv %s" % tmp_input_csv_file.name, 238 | "back" 239 | ]) 240 | 241 | else: 242 | 243 | script_content.extend([ 244 | "discovery !all, allowedMethods, webSpider", 245 | "discovery config webSpider", 246 | "set onlyForward True", 247 | "back" 248 | ]) 249 | 250 | script_content.extend([ 251 | "audit all, !xsrf", 252 | "bruteforce all", 253 | "audit config xss", 254 | "set numberOfChecks 15", 255 | "back", 256 | "back", 257 | "target", 258 | "set target %s" % url, 259 | "back", 260 | "start", 261 | "exit" 262 | ]) 263 | 264 | tmp_script_file.write('\n'.join(script_content)) 265 | 266 | tmp_script_file.flush() 267 | 268 | os.fsync(tmp_script_file.fileno()) 269 | 270 | cmd = argv[0] + ' -s ' + tmp_script_file.name 271 | 272 | self.logger.debug('Invoking Popen w/ %s' % cmd) 273 | 274 | p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 275 | 276 | (stdout_output, stderr_output) = p.communicate() 277 | 278 | tmp_output_file.flush() 279 | 280 | os.fsync(tmp_output_file.fileno()) 281 | 282 | app_output = tmp_output_file.read() 283 | 284 | self.logger.debug('Application-specific Output:\n %s' % app_output) 285 | 286 | return app_output 287 | 288 | # Consts 289 | 290 | DEFAULT_FILENAME = "w3af_console" 291 | 292 | DEFAULT_FILTER = \ 293 | "(context['SERVICE'] == 'HTTP' or context['SERVICE'] == 'HTTPS') and " \ 294 | "(context['IPV4_ADDRESS'] or context['HOSTNAME']) and " \ 295 | "context['PROTO'] == 'TCP'" 296 | 297 | DEFAULT_QUERY = \ 298 | "context['URL'] or (context['SERVICE'].lower() + '://' + (context['IPV4_ADDRESS'] or context['HOSTNAME']) + ':' + context['PORT'])" 299 | -------------------------------------------------------------------------------- /hackersh/components/external/xprobe2.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.1" 28 | 29 | 30 | # Implementation 31 | 32 | class Xprobe2(hackersh.objects.ExternalComponentFileOutput): 33 | 34 | # XML Parser(s) 35 | 36 | class Xprobe2XMLOutputHandler(hackersh.objects.XMLOutputHandler): 37 | 38 | def startDocument(self): 39 | 40 | self._read_content = False 41 | 42 | self._os_guess = [] 43 | 44 | def startElement(self, name, attrs): 45 | 46 | # 47 | # "Linux Kernel 2.4.30" 48 | # "Linux Kernel 2.4.29" 49 | # "Linux Kernel 2.4.28" 50 | # "Linux Kernel 2.4.27" 51 | # "Linux Kernel 2.4.26" 52 | # "Linux Kernel 2.4.25" 53 | # "Linux Kernel 2.4.24" 54 | # "Linux Kernel 2.4.19" 55 | # "Linux Kernel 2.4.20" 56 | # "Linux Kernel 2.4.21" 57 | # 58 | 59 | if name == "primary" or name == "secondary": 60 | 61 | self._entry = {} 62 | 63 | self._read_content = True 64 | 65 | def characters(self, content): 66 | 67 | if self._read_content: 68 | 69 | self._entry.update({"OS": str(content).replace('"', '').strip()}) 70 | 71 | def endElement(self, name): 72 | 73 | if name == "primary" or name == "secondary": 74 | 75 | self._os_guess.append(hackersh.objects.RemoteSessionContext(self._context, **self._entry)) 76 | 77 | self._read_content = False 78 | 79 | def endDocument(self): 80 | 81 | if not self._os_guess: 82 | 83 | self._output.append(self._context) 84 | 85 | else: 86 | 87 | for entry in self._os_guess: 88 | 89 | self._output.append(entry) 90 | 91 | # Consts 92 | 93 | DEFAULT_FILENAME = "xprobe2" 94 | 95 | DEFAULT_OUTPUT_OPTIONS = "-X -o" 96 | 97 | DEFAULT_QUERY = DEFAULT_FILTER = "context['IPV4_ADDRESS'] or context['HOSTNAME']" 98 | -------------------------------------------------------------------------------- /hackersh/components/internal/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikotler/hackersh/13af753815290891aab749a771c543c3cb715cc7/hackersh/components/internal/__init__.py -------------------------------------------------------------------------------- /hackersh/components/internal/browse.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import cookielib 20 | import mechanize 21 | import tempfile 22 | import os 23 | 24 | 25 | # Local imports 26 | 27 | import hackersh.objects 28 | 29 | 30 | # Metadata 31 | 32 | __author__ = "Itzik Kotler " 33 | __version__ = "0.1.1" 34 | 35 | 36 | # Implementation 37 | 38 | class _MozillaCookieJarAsCommandLineArgument(cookielib.MozillaCookieJar): 39 | 40 | def __str__(self): 41 | 42 | cookies_arg = "" 43 | 44 | for cookie in self: 45 | 46 | cookies_arg += cookie.name + '=' + cookie.value + '; ' 47 | 48 | return '"' + cookies_arg + '"' 49 | 50 | 51 | class Browse(hackersh.objects.InternalComponent): 52 | 53 | def run(self, argv, context): 54 | 55 | url = argv[0] 56 | 57 | br = mechanize.Browser() 58 | 59 | cj = _MozillaCookieJarAsCommandLineArgument() 60 | 61 | already_existing_cj = context['COOKIES'] 62 | 63 | # Duplicate Jar 64 | 65 | if already_existing_cj: 66 | 67 | tmp_cj_file = tempfile.NamedTemporaryFile() 68 | 69 | already_existing_cj.save(tmp_cj_file.name, True, True) 70 | 71 | tmp_cj_file.flush() 72 | 73 | os.fsync(tmp_cj_file.fileno()) 74 | 75 | cj.load(tmp_cj_file.name, True, True) 76 | 77 | br.set_cookiejar(cj) 78 | 79 | # Browser Options 80 | 81 | br.set_handle_equiv(True) 82 | br.set_handle_redirect(True) 83 | br.set_handle_referer(True) 84 | br.set_handle_robots(False) 85 | br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1) 86 | 87 | if self._kwargs.get('ua', False): 88 | 89 | br.addheaders = [('User-agent', self._kwargs.get('ua'))] 90 | 91 | context['USER-AGENT'] = self._kwargs['ua'] 92 | 93 | # Open URL 94 | 95 | response = br.open(url) 96 | 97 | response = br.open(url) 98 | 99 | if self._kwargs.get('dump', False): 100 | 101 | print response.read() 102 | 103 | return hackersh.objects.RemoteSessionContext(context, **{'BR_OBJECT': br, 'URL': url, 'COOKIES': cj}) 104 | 105 | DEFAULT_FILTER = \ 106 | "(" \ 107 | " (context['SERVICE'] == 'HTTP' or context['SERVICE'] == 'HTTPS') and " \ 108 | " (context['IPV4_ADDRESS'] or context['HOSTNAME']) and " \ 109 | " context['PROTO'] == 'TCP'" \ 110 | ")" \ 111 | "or" \ 112 | "(" \ 113 | " context['URL']" \ 114 | ")" 115 | 116 | DEFAULT_QUERY = \ 117 | "context['URL'] or (context['SERVICE'].lower() + '://' + (context['IPV4_ADDRESS'] or context['HOSTNAME']) + ':' + context['PORT'])" 118 | -------------------------------------------------------------------------------- /hackersh/components/internal/domain.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | 20 | # Local imports 21 | 22 | import hackersh.objects 23 | 24 | 25 | # Metadata 26 | 27 | __author__ = "Itzik Kotler " 28 | __version__ = "0.1.0" 29 | 30 | 31 | # Implementation 32 | 33 | class Domain(hackersh.objects.RootComponent): 34 | 35 | def run(self, argv, context): 36 | 37 | _context = False 38 | 39 | if argv[0].find('.') != -1: 40 | 41 | _context = hackersh.objects.RemoteSessionContext(DOMAIN=argv[0]) 42 | 43 | return _context 44 | -------------------------------------------------------------------------------- /hackersh/components/internal/hostname.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import socket 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | 26 | 27 | # Metadata 28 | 29 | __author__ = "Itzik Kotler " 30 | __version__ = "0.1.0" 31 | 32 | 33 | # Implementation 34 | 35 | class Hostname(hackersh.objects.RootComponent): 36 | 37 | def run(self, argv, context): 38 | 39 | _context = False 40 | 41 | try: 42 | 43 | socket.gethostbyname(argv[0]) 44 | 45 | _context = hackersh.objects.RemoteSessionContext(HOSTNAME=argv[0]) 46 | 47 | except socket.error as e: 48 | 49 | # i.e. socket.gaierror: [Errno -2] Name or service not known 50 | 51 | self.logger.debug('Caught exception %s' % str(e)) 52 | 53 | pass 54 | 55 | return _context 56 | -------------------------------------------------------------------------------- /hackersh/components/internal/ipv4_address.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import socket 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | 26 | 27 | # Metadata 28 | 29 | __author__ = "Itzik Kotler " 30 | __version__ = "0.1.0" 31 | 32 | 33 | # Implementation 34 | 35 | class IPv4_Address(hackersh.objects.RootComponent): 36 | 37 | def run(self, argv, context): 38 | 39 | _context = False 40 | 41 | try: 42 | 43 | socket.inet_aton(argv[0]) 44 | 45 | _context = hackersh.objects.RemoteSessionContext(IPV4_ADDRESS=argv[0]) 46 | 47 | except socket.error, e: 48 | 49 | self.logger.debug('Caught exception %s' % str(e)) 50 | 51 | # i.e. illegal IP address string passed to inet_aton 52 | 53 | pass 54 | 55 | return _context 56 | -------------------------------------------------------------------------------- /hackersh/components/internal/ipv4_range.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import netaddr 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | 26 | 27 | # Metadata 28 | 29 | __author__ = "Itzik Kotler " 30 | __version__ = "0.1.0" 31 | 32 | 33 | # Implementation 34 | 35 | class IPv4_Range(hackersh.objects.RootComponent): 36 | 37 | def run(self, argv, context): 38 | 39 | contexts = [] 40 | 41 | ipv4_addresses_gen = None 42 | 43 | try: 44 | 45 | # 192.168.1.0-255 46 | 47 | try: 48 | 49 | ipv4_addresses_gen = netaddr.IPGlob(argv[0]) 50 | 51 | except netaddr.core.AddrFormatError as e: 52 | 53 | self.logger.debug('Caught exception %s' % str(e)) 54 | 55 | try: 56 | 57 | # 192.168.1.0/24 58 | 59 | ipv4_addresses_gen = netaddr.IPNetwork(argv[0]) 60 | 61 | except netaddr.core.AddrFormatError as e: 62 | 63 | self.logger.debug('Caught exception %s' % str(e)) 64 | 65 | pass 66 | 67 | for ipv4_addr in ipv4_addresses_gen: 68 | 69 | contexts.append(hackersh.objects.RemoteSessionContext(IPV4_ADDRESS=str(ipv4_addr))) 70 | 71 | except TypeError as e: 72 | 73 | pass 74 | 75 | return contexts 76 | -------------------------------------------------------------------------------- /hackersh/components/internal/ipv6_address.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import socket 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | 26 | 27 | # Metadata 28 | 29 | __author__ = "Itzik Kotler " 30 | __version__ = "0.1.0" 31 | 32 | 33 | # Implementation 34 | 35 | class IPv6_Address(hackersh.objects.RootComponent): 36 | 37 | def run(self, argv, context): 38 | 39 | _context = False 40 | 41 | try: 42 | 43 | socket.inet_pton(socket.AF_INET6, argv[0]) 44 | 45 | _context = hackersh.objects.RemoteSessionContext(IPV6_ADDRESS=argv[0]) 46 | 47 | except socket.error, e: 48 | 49 | self.logger.debug('Caught exception %s' % str(e)) 50 | 51 | # i.e. illegal IP address string passed to inet_aton 52 | 53 | pass 54 | 55 | return _context 56 | -------------------------------------------------------------------------------- /hackersh/components/internal/iterate_links.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.0" 28 | 29 | 30 | # Implementation 31 | 32 | class Iterate_Links(hackersh.objects.InternalComponent): 33 | 34 | def run(self, argv, context): 35 | 36 | contexts = [] 37 | 38 | br = argv[0] 39 | 40 | for link in br.links(): 41 | 42 | contexts.append(hackersh.objects.RemoteSessionContext(context, URL=link.absolute_url)) 43 | 44 | return contexts if contexts else False 45 | 46 | DEFAULT_FILTER = DEFAULT_QUERY = "context['BR_OBJECT']" 47 | -------------------------------------------------------------------------------- /hackersh/components/internal/nslookup.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import socket 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | import hackersh.components.internal.ipv4_address 26 | 27 | 28 | # Metadata 29 | 30 | __author__ = "Itzik Kotler " 31 | __version__ = "0.1.0" 32 | 33 | 34 | # Implementation 35 | 36 | class Nslookup(hackersh.objects.RootComponent): 37 | 38 | def run(self, argv, context): 39 | 40 | _context = False 41 | 42 | try: 43 | 44 | # i.e. '127.0.0.1' 45 | 46 | if isinstance(argv[0], basestring): 47 | 48 | _context = hackersh.components.internal.ipv4_address.IPv4_Address().run([socket.gethostbyname(argv[0])], {}) 49 | 50 | # i.e. RemoteSessionContext(HOSTNAME='localhost', ...) 51 | 52 | else: 53 | 54 | __context = hackersh.objects.RemoteSessionContext(argv[0]) 55 | 56 | _context = hackersh.components.internal.ipv4_address.IPv4_Address().run([socket.gethostbyname(__context['HOSTNAME'])], {}) 57 | 58 | _context.update(__context) 59 | 60 | # Turn HOSTNAME into a shadowed key 61 | 62 | __context['_HOSTNAME'] = __context['HOSTNAME'] 63 | 64 | del __context['HOSTNAME'] 65 | 66 | except socket.error as e: 67 | 68 | # i.e. socket.gaierror: [Errno -5] No address associated with hostname 69 | 70 | self.logger.debug('Caught exception %s' % str(e)) 71 | 72 | pass 73 | 74 | return _context 75 | -------------------------------------------------------------------------------- /hackersh/components/internal/submit.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.0" 28 | 29 | 30 | # Implementation 31 | 32 | class Submit(hackersh.objects.InternalComponent): 33 | 34 | def run(self, argv, context): 35 | 36 | br = argv[0] 37 | 38 | br.select_form(nr=0) 39 | 40 | for k, v in self._kwargs.iteritems(): 41 | 42 | br[k] = v 43 | 44 | response = br.submit() 45 | 46 | return hackersh.objects.RemoteSessionContext(context, **{'BR_OBJECT': br, 'URL': response.geturl()}) 47 | 48 | DEFAULT_FILTER = DEFAULT_QUERY = "context['BR_OBJECT']" 49 | -------------------------------------------------------------------------------- /hackersh/components/internal/url.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import urlparse 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | import hackersh.components.internal.ipv4_address 26 | import hackersh.components.internal.hostname 27 | 28 | 29 | # Metadata 30 | 31 | __author__ = "Itzik Kotler " 32 | __version__ = "0.1.0" 33 | 34 | 35 | # Implementation 36 | 37 | class URL(hackersh.objects.RootComponent): 38 | 39 | def run(self, argv, context): 40 | 41 | _context = hackersh.objects.RemoteSessionContext({'URL': argv[0]}) 42 | 43 | parse_result = urlparse.urlparse(argv[0]) 44 | 45 | if parse_result.scheme and parse_result.netloc: 46 | 47 | netloc = parse_result.netloc 48 | 49 | # i.e. http://localhost:8080 50 | 51 | try: 52 | 53 | (netloc, netport) = netloc.split(':') 54 | 55 | except ValueError: 56 | 57 | # i.e. http://localhost 58 | 59 | netport = '80' 60 | 61 | # i.e. http://locahost or http://127.0.0.1? 62 | 63 | __context = hackersh.components.internal.ipv4_address.IPv4_Address().run([netloc], {}) 64 | 65 | if not __context: 66 | 67 | __context = hackersh.components.internal.hostname.Hostname().run([netloc], {}) 68 | 69 | if not __context: 70 | 71 | # TODO: IPv6? MAC Address? 72 | 73 | return __context 74 | 75 | # TODO: xrefer w/ URI scheme to make sure it's TCP, and not just assume 76 | 77 | _context.update(__context) 78 | 79 | _context.update({'PORT': netport, 'SERVICE': parse_result.scheme.upper(), 'PROTO': 'TCP'}) 80 | 81 | return _context 82 | -------------------------------------------------------------------------------- /hackersh/components/system/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikotler/hackersh/13af753815290891aab749a771c543c3cb715cc7/hackersh/components/system/__init__.py -------------------------------------------------------------------------------- /hackersh/components/system/alert.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.0" 28 | 29 | 30 | # Implementation 31 | 32 | class Alert(hackersh.objects.Component): 33 | 34 | def __call__(self, arg): 35 | 36 | return arg.__class__(arg, **{'VULNERABILITIES': arg.get('VULNERABILITIES', []) + [self._kwargs]}) 37 | -------------------------------------------------------------------------------- /hackersh/components/system/null.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | # Local imports 20 | 21 | import hackersh.objects 22 | 23 | 24 | # Metadata 25 | 26 | __author__ = "Itzik Kotler " 27 | __version__ = "0.1.0" 28 | 29 | 30 | # Implementation 31 | 32 | class Null(hackersh.objects.Component): 33 | 34 | def __call__(self, arg): 35 | 36 | return '' 37 | -------------------------------------------------------------------------------- /hackersh/components/system/print.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import sys 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | 26 | 27 | # Metadata 28 | 29 | __author__ = "Itzik Kotler " 30 | __version__ = "0.1.0" 31 | 32 | 33 | # Implementation 34 | 35 | class print_(hackersh.objects.Component): 36 | 37 | def __call__(self, arg): 38 | 39 | sys.stdout.write(str(arg) + '\n') 40 | 41 | sys.stdout.flush() 42 | 43 | return arg 44 | -------------------------------------------------------------------------------- /hackersh/components/system/system.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import subprocess 20 | import shlex 21 | 22 | 23 | # Local imports 24 | 25 | import hackersh.objects 26 | 27 | 28 | # Metadata 29 | 30 | __author__ = "Itzik Kotler " 31 | __version__ = "0.1.0" 32 | 33 | 34 | # Implementation 35 | 36 | class System(hackersh.objects.Component): 37 | 38 | def __call__(self, arg): 39 | 40 | cmd = shlex.split(self._kwargs['path']) + list(self._args) 41 | 42 | self.logger.debug('Executing shell command %s' % ' '.join(cmd)) 43 | 44 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT) 45 | 46 | (stdout_output, stderr_output) = p.communicate(arg) 47 | 48 | return str(stdout_output) 49 | -------------------------------------------------------------------------------- /hackersh/components/system/tmpfile.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import tempfile 20 | 21 | 22 | # Local imports 23 | 24 | import hackersh.objects 25 | 26 | 27 | # Metadata 28 | 29 | __author__ = "Itzik Kotler " 30 | __version__ = "0.1.0" 31 | 32 | 33 | # Implementation 34 | 35 | class tmpfile(hackersh.objects.Component): 36 | 37 | def __call__(self, arg): 38 | 39 | tfile = tempfile.NamedTemporaryFile(delete=False) 40 | 41 | print tfile.name 42 | 43 | tfile.write(str(arg)) 44 | 45 | tfile.close() 46 | 47 | return '' 48 | -------------------------------------------------------------------------------- /hackersh/conio.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import os 20 | import fcntl 21 | import termios 22 | import struct 23 | import textwrap 24 | import prettytable 25 | 26 | 27 | # http://stackoverflow.com/questions/566746/how-to-get-console-window-width-in-python/566752#566752 28 | 29 | def __ioctl_GWINSZ(fd): 30 | 31 | cr = None 32 | 33 | try: 34 | 35 | cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) 36 | 37 | except Exception: 38 | 39 | pass 40 | 41 | return cr 42 | 43 | 44 | def terminalsize(): 45 | 46 | cr = __ioctl_GWINSZ(0) or __ioctl_GWINSZ(1) or __ioctl_GWINSZ(2) 47 | 48 | if not cr: 49 | 50 | try: 51 | 52 | fd = os.open(os.ctermid(), os.O_RDONLY) 53 | 54 | cr = __ioctl_GWINSZ(fd) 55 | 56 | os.close(fd) 57 | 58 | except: 59 | 60 | try: 61 | 62 | cr = (os.environ['LINES'], os.environ['COLUMNS']) 63 | 64 | except: 65 | 66 | cr = (25, 80) 67 | 68 | return int(cr[1]), int(cr[0]) 69 | 70 | 71 | def draw_underline(string): 72 | 73 | return string + '\n' + '-' * len(string) + '\n' 74 | 75 | 76 | def __mk_tbl(fields): 77 | 78 | tbl = prettytable.PrettyTable(fields, left_padding_width=1, right_padding_width=1, hrules=prettytable.ALL) 79 | 80 | col_max_width = (terminalsize()[0] / len(fields)) - 30 81 | 82 | for k in tbl.align: 83 | 84 | tbl.align[k] = 'l' 85 | 86 | return (tbl, col_max_width) 87 | 88 | 89 | def draw_static_tbl(data, fields, values): 90 | 91 | (tbl, col_max_width) = __mk_tbl(fields) 92 | 93 | for dataset in data: 94 | 95 | row_data = [] 96 | 97 | for value in values: 98 | 99 | row_data.append('\n'.join(textwrap.wrap(dataset.get(value, ''), col_max_width))) 100 | 101 | tbl.add_row(row_data) 102 | 103 | return tbl.get_string() 104 | 105 | 106 | def draw_dict_tbl(dct, fields, keys): 107 | 108 | (tbl, col_max_width) = __mk_tbl(fields) 109 | 110 | for key in keys: 111 | 112 | row_data = [str(key).title()] 113 | 114 | row_data.append('\n'.join(textwrap.wrap(str(dct.get(key, '')), col_max_width))) 115 | 116 | tbl.add_row(row_data) 117 | 118 | return tbl.get_string() 119 | 120 | 121 | def draw_msgbox(string): 122 | 123 | msgbox = '\n' 124 | msgbox += '*' * 80 + '\n' 125 | msgbox += '*' + ' '.ljust(78) + '*' + '\n' 126 | msgbox += '*' + ' '.ljust(78) + '*' + '\n' 127 | msgbox += '* ' + string.ljust(76) + '*' + '\n' 128 | msgbox += '*' + ' '.ljust(78) + '*' + '\n' 129 | msgbox += '*' + ' '.ljust(78) + '*' + '\n' 130 | msgbox += '*' * 80 + '\n' 131 | 132 | return msgbox 133 | -------------------------------------------------------------------------------- /hackersh/eval.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import types 20 | import os 21 | import shlex 22 | import pythonect 23 | import networkx 24 | 25 | 26 | # Local imports 27 | 28 | import miscellaneous 29 | 30 | 31 | def __quotes_wrap(list): 32 | 33 | new_list = [] 34 | 35 | for e in list: 36 | 37 | new_list.append("'%s'" % e) 38 | 39 | return new_list 40 | 41 | 42 | def __hackersh_preprocessor(source, sym_tbl): 43 | 44 | orig_source = source 45 | 46 | # i.e. nmap 47 | 48 | if source in sym_tbl and not isinstance(sym_tbl[source], types.FunctionType): 49 | 50 | source = "%s()" % source 51 | 52 | # i.e. /usr/bin/nmap or ./nmap 53 | 54 | if source.startswith('/') or source.startswith('./') or source.startswith('../'): 55 | 56 | expression_cmd = shlex.split(source) 57 | 58 | external_component_path = os.path.abspath(expression_cmd[0]) 59 | 60 | external_component_name = os.path.splitext(os.path.basename(external_component_path))[0] 61 | 62 | external_component_kwargs = '**{}' 63 | 64 | # External binary? (i.e. /bin/ls) 65 | 66 | if external_component_name not in sym_tbl: 67 | 68 | if not os.path.isfile(external_component_path): 69 | 70 | external_component_path = miscellaneous.which(expression_cmd[0])[0] 71 | 72 | if not external_component_path: 73 | 74 | print '%s: command not found' % expression_cmd[0] 75 | 76 | return False 77 | 78 | external_component_kwargs = "**{'path':'%s'}" % external_component_path 79 | 80 | external_component_name = "system" 81 | 82 | external_component_args = "*(%s)" % ','.join(__quotes_wrap(expression_cmd[1:]) + [' ']) 83 | 84 | source = "%s(%s, %s)" % (external_component_name, external_component_args, external_component_kwargs) 85 | 86 | # print '%s => %s' % (orig_source, source) 87 | 88 | return source 89 | 90 | 91 | def _hackersh_graph_transform(graph, hackersh_locals): 92 | 93 | # TODO: XSLT? 94 | 95 | for node in graph: 96 | 97 | graph.node[node]['CONTENT'] = __hackersh_preprocessor(graph.node[node]['CONTENT'].strip(), hackersh_locals) 98 | 99 | return graph 100 | 101 | 102 | def parse(source): 103 | 104 | return pythonect.parse(source) 105 | 106 | 107 | def eval(source, locals_): 108 | 109 | return_value = None 110 | 111 | graph = None 112 | 113 | if source != "pass": 114 | 115 | if not isinstance(source, networkx.DiGraph): 116 | 117 | graph = parse(source) 118 | 119 | else: 120 | 121 | graph = source 122 | 123 | return_value = pythonect.eval(_hackersh_graph_transform(graph, locals_), {}, locals_) 124 | 125 | return return_value 126 | -------------------------------------------------------------------------------- /hackersh/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | 20 | class HackershError(Exception): 21 | 22 | def __init__(self, context, msg): 23 | self.context = context 24 | self.msg = msg 25 | -------------------------------------------------------------------------------- /hackersh/log.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import logging 20 | 21 | 22 | VERBOSE_LEVELS = [logging.WARNING, logging.INFO, logging.DEBUG] 23 | 24 | 25 | logging.basicConfig(format="%(asctime)s %(name)s: [%(levelname)s] %(message)s", datefmt='%b %d %R:%S', level=logging.ERROR) 26 | 27 | 28 | # Default Logger 29 | 30 | logger = logging.getLogger('hackersh') 31 | -------------------------------------------------------------------------------- /hackersh/miscellaneous.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import os 20 | import shlex 21 | 22 | 23 | def shell_split(s): 24 | lex = shlex.shlex(s) 25 | lex.quotes = '"' 26 | lex.whitespace_split = True 27 | lex.commenters = '' 28 | return list(lex) 29 | 30 | 31 | # https://twistedmatrix.com/trac/browser/tags/releases/twisted-8.2.0/twisted/python/procutils.py 32 | 33 | def which(name, flags=os.X_OK): 34 | 35 | result = [] 36 | 37 | exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep)) 38 | 39 | path = os.environ.get('PATH', None) 40 | 41 | if path is None: 42 | 43 | return [] 44 | 45 | for p in os.environ.get('PATH', '').split(os.pathsep): 46 | 47 | p = os.path.join(p, name) 48 | 49 | if os.access(p, flags): 50 | result.append(p) 51 | 52 | for e in exts: 53 | 54 | pext = p + e 55 | 56 | if os.access(pext, flags): 57 | result.append(pext) 58 | 59 | return result 60 | -------------------------------------------------------------------------------- /hackersh/objects.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Itzik Kotler 2 | # 3 | # This file is part of Hackersh. 4 | # 5 | # Hackersh is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # Hackersh is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Hackersh; see the file COPYING. If not, 17 | # see . 18 | 19 | import os 20 | import tempfile 21 | import subprocess 22 | import types 23 | import xml.sax 24 | import csv 25 | import HTMLParser 26 | import re 27 | 28 | 29 | # Local imports 30 | 31 | import log 32 | import conio 33 | import miscellaneous 34 | import _ordereddict 35 | import exceptions 36 | 37 | 38 | # Component Classes 39 | 40 | class Component(object): 41 | 42 | def __init__(self, *args, **kwargs): 43 | 44 | self.DEFAULT_STDIN_BUFFER = None 45 | 46 | self._args = args 47 | 48 | self._kwargs = kwargs 49 | 50 | self.logger = log.logging.getLogger(self.__class__.__name__.lower()) 51 | 52 | if 'debug' in kwargs: 53 | 54 | self.logger.setLevel(log.logging.DEBUG) 55 | 56 | self.logger.debug('Initialized %s with args = %s and kwargs = %s' % (repr(self), args, kwargs)) 57 | 58 | def __call__(self, arg): 59 | 60 | context = arg 61 | 62 | if not eval(self._kwargs.get('filter', self.DEFAULT_FILTER), {'context': context}): 63 | 64 | self.logger.debug("Filter %s is False" % self._kwargs.get('filter', self.DEFAULT_FILTER)) 65 | 66 | raise exceptions.HackershError(context, "%s: not enough data to start" % self.__class__.__name__.lower()) 67 | 68 | self.logger.debug("Filter %s is True" % self._kwargs.get('filter', self.DEFAULT_FILTER)) 69 | 70 | component_args_as_str = eval(self._kwargs.get('query', self.DEFAULT_QUERY), {'context': context}) 71 | 72 | self.logger.debug("Query = %s" % component_args_as_str) 73 | 74 | argv = [] 75 | 76 | try: 77 | 78 | argv = miscellaneous.shell_split(self._args[0] + ' ' + component_args_as_str) 79 | 80 | except IndexError: 81 | 82 | try: 83 | 84 | argv = miscellaneous.shell_split(component_args_as_str) 85 | 86 | except Exception: 87 | 88 | # "AS IT IS" 89 | 90 | argv = [component_args_as_str] 91 | 92 | self.logger.debug('Running with argv = %s and context = %s' % (argv, repr(context))) 93 | 94 | context = self.run(argv, context) 95 | 96 | if context: 97 | 98 | if isinstance(context, list): 99 | 100 | for _context in context: 101 | 102 | # Update STACK 103 | 104 | _context.update({'STACK': _context.get('STACK', []) + [self.__class__.__name__]}) 105 | 106 | else: 107 | 108 | # Don't iterate Generator, wrap it with another Generator 109 | 110 | if isinstance(context, types.GeneratorType): 111 | 112 | # TODO: Add support for Generaor 113 | 114 | pass 115 | 116 | else: 117 | 118 | context.update({'STACK': context.get('STACK', []) + [self.__class__.__name__]}) 119 | 120 | return context 121 | 122 | # Application Binary Interface-like 123 | 124 | def run(self, argv, context): 125 | 126 | raise NotImplementedError 127 | 128 | 129 | class RootComponent(Component): 130 | 131 | def __call__(self, arg): 132 | 133 | argv = list(self._args) or [arg] 134 | 135 | self.logger.debug('Running with argv = %s and context = None' % argv) 136 | 137 | context = self.run(argv, None) 138 | 139 | if context: 140 | 141 | if isinstance(context, list): 142 | 143 | for _context in context: 144 | 145 | # Add 'ROOT' and 'STACK' 146 | 147 | _context.update({'ROOT': _context.get('ROOT', argv[0]), 'STACK': [self.__class__.__name__] + _context.get('STACK', [])}) 148 | 149 | else: 150 | 151 | context.update({'ROOT': context.get('ROOT', argv[0]), 'STACK': [self.__class__.__name__] + context.get('STACK', [])}) 152 | 153 | return context 154 | 155 | 156 | class InternalComponent(Component): 157 | 158 | pass 159 | 160 | 161 | class ExternalComponent(Component): 162 | 163 | def _execute(self, argv, context): 164 | 165 | raise NotImplementedError 166 | 167 | def run(self, argv, context): 168 | 169 | filename = self._kwargs.get('filename', self.DEFAULT_FILENAME) 170 | 171 | self.logger.debug('FILENAME = ' + filename) 172 | 173 | path = miscellaneous.which(filename)[:1] 174 | 175 | if not path: 176 | 177 | self.logger.debug("NO PATH!") 178 | 179 | raise exceptions.HackershError(context, "%s: command not found" % self._kwargs.get('filename', self.DEFAULT_FILENAME)) 180 | 181 | self.logger.debug('PATH = ' + path[0]) 182 | 183 | return self._processor(context, self._execute(path + argv, context)) 184 | 185 | def _processor(self, context, data): 186 | 187 | raise NotImplementedError 188 | 189 | 190 | class ExternalComponentReturnValueOutput(ExternalComponent): 191 | 192 | def _execute(self, argv, context): 193 | 194 | cmd = argv[0] + ' ' + self._kwargs.get('output_opts', self.DEFAULT_OUTPUT_OPTIONS) + " " + ' '.join(argv[1:]) 195 | 196 | self.logger.debug('CMD = ' + cmd) 197 | 198 | p = subprocess.Popen(miscellaneous.shell_split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 199 | 200 | p.wait() 201 | 202 | return p.returncode 203 | 204 | 205 | class ExternalComponentStreamOutput(ExternalComponent): 206 | 207 | def __init__(self, *args, **kwargs): 208 | 209 | ExternalComponent.__init__(self, *args, **kwargs) 210 | 211 | self._handlers = [] 212 | 213 | # Auto-discovery of Output Handlers 214 | 215 | for name in dir(self): 216 | 217 | obj = getattr(self, name) 218 | 219 | if isinstance(obj, types.ClassType) and issubclass(obj, OutputHandler): 220 | 221 | self._handlers.append(obj) 222 | 223 | def _execute(self, argv, context): 224 | 225 | tmpfile = tempfile.NamedTemporaryFile(delete=False) 226 | 227 | fname = tmpfile.name 228 | 229 | data = "" 230 | 231 | try: 232 | 233 | cmd = argv[0] + ' ' + self._kwargs.get('output_opts', self.DEFAULT_OUTPUT_OPTIONS) + " " + tmpfile.name + " " + ' '.join(argv[1:]) 234 | 235 | self.logger.debug('CMD = ' + cmd) 236 | 237 | p = subprocess.Popen(miscellaneous.shell_split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 238 | 239 | (stdout_output, stderr_output) = p.communicate(input=self._kwargs.get('stdin', self.DEFAULT_STDIN_BUFFER)) 240 | 241 | self.logger.debug(stdout_output) 242 | 243 | tmpfile.flush() 244 | 245 | os.fsync(tmpfile.fileno()) 246 | 247 | tmpfile.close() 248 | 249 | tmpfile = open(fname, 'r') 250 | 251 | data = tmpfile.read() 252 | 253 | self.logger.debug('DATA (%d bytes) = %s' % (len(data), data)) 254 | 255 | except Exception: 256 | 257 | os.remove(fname) 258 | 259 | return data 260 | 261 | def _processor(self, context, data): 262 | 263 | if data: 264 | 265 | contexts = [] 266 | 267 | # Do-while, try parse data with *every* possible Output Handler 268 | 269 | for handler in self._handlers: 270 | 271 | handler_instance = handler(context, contexts) 272 | 273 | handler_instance.parse(data) 274 | 275 | # No Output Handler could process output, unknown format? 276 | 277 | if not contexts: 278 | 279 | raise exceptions.HackershError(context, "%s: unable to parse: %s" % (self.__class__.__name__.lower(), str(data))) 280 | 281 | return contexts 282 | 283 | else: 284 | 285 | return data 286 | 287 | 288 | class ExternalComponentFileOutput(ExternalComponentStreamOutput): 289 | 290 | def _execute(self, argv, context): 291 | 292 | tmpfile = tempfile.NamedTemporaryFile(delete=False) 293 | 294 | fname = tmpfile.name 295 | 296 | data = "" 297 | 298 | try: 299 | 300 | cmd = argv[0] + ' ' + self._kwargs.get('output_opts', self.DEFAULT_OUTPUT_OPTIONS) + " " + tmpfile.name + " " + ' '.join(argv[1:]) 301 | 302 | self.logger.debug('CMD = ' + cmd) 303 | 304 | p = subprocess.Popen(miscellaneous.shell_split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 305 | 306 | (stdout_output, stderr_output) = p.communicate(input=self._kwargs.get('stdin', self.DEFAULT_STDIN_BUFFER)) 307 | 308 | self.logger.debug(stdout_output) 309 | 310 | tmpfile.flush() 311 | 312 | os.fsync(tmpfile.fileno()) 313 | 314 | tmpfile.close() 315 | 316 | tmpfile = open(fname, 'r') 317 | 318 | data = tmpfile.read() 319 | 320 | self.logger.debug('DATA (%d bytes) = %s' % (len(data), data)) 321 | 322 | except Exception: 323 | 324 | os.remove(fname) 325 | 326 | return data 327 | 328 | 329 | class ExternalComponentStdoutOutput(ExternalComponentStreamOutput): 330 | 331 | def _execute(self, argv, context): 332 | 333 | cmd = argv[0] + ' ' + self._kwargs.get('output_opts', self.DEFAULT_OUTPUT_OPTIONS) + " " + ' '.join(argv[1:]) 334 | 335 | self.logger.debug('CMD = ' + cmd) 336 | 337 | p = subprocess.Popen(miscellaneous.shell_split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 338 | 339 | p_stdout = p.communicate(input=self._kwargs.get('stdin', self.DEFAULT_STDIN_BUFFER))[0] 340 | 341 | self.logger.debug('DATA (%d bytes) = %s' % (len(p_stdout), p_stdout)) 342 | 343 | return p_stdout 344 | 345 | 346 | # Datatype Classes 347 | 348 | class OutputHandler: 349 | 350 | def __init__(self, context, output): 351 | 352 | self._context = context 353 | 354 | self._output = output 355 | 356 | def parse(self): 357 | 358 | raise NotImplementedError 359 | 360 | 361 | # Pseudo SAX Content Handler for Simple Regualr Expression Match Handler 362 | 363 | class SimpleRegExHandler(OutputHandler): 364 | 365 | def parse(self, data): 366 | 367 | regex = re.compile(self.PATTERN) 368 | 369 | for match in regex.finditer(data): 370 | 371 | self._output.append(self._context.__class__(self._context, **match.groupdict())) 372 | 373 | PATTERN = "" 374 | 375 | 376 | # Pseudo SAX Content Handler for Stdout Output 377 | 378 | class StdoutOutputHandler(OutputHandler): 379 | 380 | def startDocument(): 381 | pass 382 | 383 | def endDocument(): 384 | pass 385 | 386 | def parse(self, data): 387 | 388 | self.startDocument() 389 | 390 | self.feed(data) 391 | 392 | self.endDocument() 393 | 394 | 395 | # Pseudo SAX Content Handler for CSV 396 | 397 | class CSVOutputHandler(OutputHandler): 398 | 399 | def parse(self, data): 400 | 401 | self.startDocument() 402 | 403 | for row in csv.reader(data.split('\n'), delimiter=self.delimiter, quotechar=self.quotechar): 404 | 405 | self.startRow(row) 406 | 407 | self.endRow() 408 | 409 | self.endDocument() 410 | 411 | delimiter = csv.excel.delimiter 412 | 413 | quotechar = csv.excel.quotechar 414 | 415 | 416 | # Pseudo SAX Content Handler for HTML 417 | 418 | class HTMLOutputHandler(OutputHandler, HTMLParser.HTMLParser): 419 | 420 | def __init__(self, context, output): 421 | 422 | HTMLParser.HTMLParser.__init__(self) 423 | 424 | self._context = context 425 | 426 | self._output = output 427 | 428 | def parse(self, data): 429 | 430 | self.startDocument() 431 | 432 | self.feed(data) 433 | 434 | self.endDocument() 435 | 436 | 437 | class XMLOutputHandler(OutputHandler, xml.sax.handler.ContentHandler): 438 | 439 | def __init__(self, context, output): 440 | 441 | xml.sax.handler.ContentHandler.__init__(self) 442 | 443 | self._context = context 444 | 445 | self._output = output 446 | 447 | def parse(self, data): 448 | 449 | xml.sax.parseString(data, self) 450 | 451 | 452 | class SessionContext(_ordereddict.OrderedDict): 453 | 454 | def __getitem__(self, key): 455 | 456 | value = False 457 | 458 | try: 459 | 460 | # Case insensitive 461 | 462 | value = _ordereddict.OrderedDict.__getitem__(self, key.upper()) 463 | 464 | except KeyError: 465 | 466 | pass 467 | 468 | return value 469 | 470 | 471 | class RemoteSessionContext(SessionContext): 472 | 473 | def __init__(self, *args, **kwargs): 474 | 475 | SessionContext.__init__(self, *args, **kwargs) 476 | 477 | def _tree_str(self): 478 | 479 | # TCP / UDP ? 480 | 481 | if self['PROTO'] == 'TCP' or self['PROTO'] == 'UDP': 482 | 483 | return self['PORT'] + '/' + self['PROTO'].lower() + ' (' + self.get('SERVICE', '?') + ')' 484 | 485 | else: 486 | 487 | return '' 488 | 489 | def __str__(self): 490 | 491 | # Properties 492 | 493 | output = \ 494 | '\n' + conio.draw_underline('Properties:') + '\n' + \ 495 | conio.draw_dict_tbl(self, ["Property", "Value"], filter(lambda key: not key.startswith('_') and key != 'VULNERABILITIES', self.keys())) + '\n' 496 | 497 | # Vulnerabilities 498 | 499 | if 'VULNERABILITIES' in self: 500 | 501 | output = \ 502 | output + '\n' + \ 503 | conio.draw_underline('Vulnerabilities:') + '\n' + \ 504 | conio.draw_static_tbl(self['VULNERABILITIES'], ["VULNERABILITY DESCRIPTION", "URL"], ["DESCRIPTION", "DESTINATION"]) + '\n' 505 | 506 | return output 507 | 508 | 509 | class LocalSessionContext(SessionContext): 510 | 511 | pass 512 | 513 | 514 | class SessionsTree(object): 515 | 516 | def __init__(self, children): 517 | 518 | self.children = [] 519 | 520 | self.keys = _ordereddict.OrderedDict() 521 | 522 | # N 523 | 524 | if isinstance(children, list): 525 | 526 | # Remove False's 527 | 528 | self.children = filter(lambda x: not isinstance(x, bool), children) 529 | 530 | # 1 531 | 532 | elif not isinstance(children, bool): 533 | 534 | self.children.append(children) 535 | 536 | if self.children: 537 | 538 | children_roots = list(set([child.values()[0] for child in self.children])) 539 | 540 | # 1 541 | 542 | if len(children_roots) == 1: 543 | 544 | self.keys[children_roots[0]] = self 545 | 546 | # N 547 | 548 | else: 549 | 550 | for children_root in children_roots: 551 | 552 | self.keys[children_root] = SessionsTree(filter(lambda child: child.values()[0] == children_root, self.children)) 553 | 554 | def _tree_str(self): 555 | 556 | if self.keys: 557 | 558 | if len(self.keys) == 1: 559 | 560 | yield self.children[0].values()[0] 561 | 562 | last = self.children[-1] if self.children else None 563 | 564 | for child in self.children: 565 | 566 | prefix = ' `-' if child is last else ' +-' 567 | 568 | for line in child._tree_str().splitlines(): 569 | 570 | yield '\n' + prefix + line 571 | 572 | prefix = ' ' if child is last else ' | ' 573 | 574 | yield '\n' 575 | 576 | # N 577 | 578 | else: 579 | 580 | for key in self.keys.keys(): 581 | 582 | yield self.keys[key] 583 | 584 | else: 585 | 586 | yield "Error\n" 587 | 588 | def __str__(self): 589 | 590 | return reduce(lambda x, y: str(x) + str(y), self._tree_str()) 591 | 592 | def __getitem__(self, key): 593 | 594 | return self.keys.get(key, False) 595 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [pep8] 2 | ignore=E501 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2013 Itzik Kotler 4 | # 5 | # This file is part of Hackersh. 6 | # 7 | # Hackersh is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2, or (at your option) 10 | # any later version. 11 | # 12 | # Hackersh is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with Hackersh; see the file COPYING. If not, 19 | # see . 20 | 21 | try: 22 | 23 | import setuptools 24 | 25 | except ImportError: 26 | 27 | from distribute_setup import use_setuptools 28 | 29 | use_setuptools() 30 | 31 | import setuptools 32 | 33 | 34 | import sys 35 | 36 | 37 | # Functions 38 | 39 | def _safe_get_version(): 40 | 41 | tmp_globals = {} 42 | 43 | # Importing _version.py may raise ImportError due to missing dependencies 44 | 45 | execfile('hackersh/_version.py', tmp_globals) 46 | 47 | version = tmp_globals['__version__'] 48 | 49 | return version 50 | 51 | 52 | # Entry Point 53 | 54 | if __name__ == "__main__": 55 | 56 | dependencies = ['pythonect>=0.6.0', 'networkx>=1.7', 'prettytable>=0.6.1', 'netaddr>=0.7.10'] 57 | 58 | major, minor = sys.version_info[:2] 59 | 60 | python_27 = (major > 2 or (major == 2 and minor >= 7)) 61 | 62 | # < Python 2.7 ? 63 | 64 | if not python_27: 65 | 66 | # Python 2.6 67 | 68 | dependencies = dependencies + ['argparse>=1.2.1', 'ordereddict>=1.1'] 69 | 70 | setupconf = dict( 71 | name='Hackersh', 72 | version=_safe_get_version(), 73 | author='Itzik Kotler', 74 | author_email='xorninja@gmail.com', 75 | url='http://www.hackersh.org/', 76 | license='GPLv2+', 77 | description='Hacker Shell, a shell (command interpreter) written in Python with Pythonect-like syntax, built-in security commands, and out of the box wrappers for various security tools.', 78 | 79 | long_description=open('README.rst').read(), 80 | 81 | scripts=['bin/hackersh'], 82 | data_files=[('', ['COPYING'])], 83 | packages=setuptools.find_packages(), 84 | 85 | classifiers=[ 86 | 'Development Status :: 4 - Beta', 87 | 'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)', 88 | 'Operating System :: OS Independent', 89 | 'Programming Language :: Python', 90 | 'Programming Language :: Python :: 2.6', 91 | 'Programming Language :: Python :: 2.7', 92 | ], 93 | 94 | install_requires=dependencies, 95 | 96 | zip_safe=False, 97 | 98 | ) 99 | 100 | setuptools.setup(**setupconf) 101 | --------------------------------------------------------------------------------