├── .gitignore ├── LICENSE ├── README.md ├── intelspy.py ├── logo.png ├── profiles ├── global-patterns.toml ├── live-host-scan-profiles.toml ├── port-scan-profiles.toml └── service-scans-profiles.toml └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/python,pycharm+all 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=python,pycharm+all 4 | 5 | ### PyCharm+all ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | 19 | # Sensitive or high-churn files 20 | .idea/**/dataSources/ 21 | .idea/**/dataSources.ids 22 | .idea/**/dataSources.local.xml 23 | .idea/**/sqlDataSources.xml 24 | .idea/**/dynamic.xml 25 | .idea/**/uiDesigner.xml 26 | .idea/**/dbnavigator.xml 27 | 28 | # Gradle 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | 32 | # Gradle and Maven with auto-import 33 | # When using Gradle or Maven with auto-import, you should exclude module files, 34 | # since they will be recreated, and may cause churn. Uncomment if using 35 | # auto-import. 36 | # .idea/artifacts 37 | # .idea/compiler.xml 38 | # .idea/jarRepositories.xml 39 | # .idea/modules.xml 40 | # .idea/*.iml 41 | # .idea/modules 42 | # *.iml 43 | # *.ipr 44 | 45 | # CMake 46 | cmake-build-*/ 47 | 48 | # Mongo Explorer plugin 49 | .idea/**/mongoSettings.xml 50 | 51 | # File-based project format 52 | *.iws 53 | 54 | # IntelliJ 55 | out/ 56 | 57 | # mpeltonen/sbt-idea plugin 58 | .idea_modules/ 59 | 60 | # JIRA plugin 61 | atlassian-ide-plugin.xml 62 | 63 | # Cursive Clojure plugin 64 | .idea/replstate.xml 65 | 66 | # Crashlytics plugin (for Android Studio and IntelliJ) 67 | com_crashlytics_export_strings.xml 68 | crashlytics.properties 69 | crashlytics-build.properties 70 | fabric.properties 71 | 72 | # Editor-based Rest Client 73 | .idea/httpRequests 74 | 75 | # Android studio 3.1+ serialized cache file 76 | .idea/caches/build_file_checksums.ser 77 | 78 | ### PyCharm+all Patch ### 79 | # Ignores the whole .idea folder and all .iml files 80 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 81 | 82 | .idea/ 83 | 84 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 85 | 86 | *.iml 87 | modules.xml 88 | .idea/misc.xml 89 | *.ipr 90 | 91 | # Sonarlint plugin 92 | .idea/sonarlint 93 | 94 | ### Python ### 95 | # Byte-compiled / optimized / DLL files 96 | __pycache__/ 97 | *.py[cod] 98 | *$py.class 99 | 100 | # C extensions 101 | *.so 102 | 103 | # Distribution / packaging 104 | .Python 105 | build/ 106 | develop-eggs/ 107 | dist/ 108 | downloads/ 109 | eggs/ 110 | .eggs/ 111 | lib/ 112 | lib64/ 113 | parts/ 114 | sdist/ 115 | var/ 116 | wheels/ 117 | pip-wheel-metadata/ 118 | share/python-wheels/ 119 | *.egg-info/ 120 | .installed.cfg 121 | *.egg 122 | MANIFEST 123 | 124 | # PyInstaller 125 | # Usually these files are written by a python script from a template 126 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 127 | *.manifest 128 | *.spec 129 | 130 | # Installer logs 131 | pip-log.txt 132 | pip-delete-this-directory.txt 133 | 134 | # Unit test / coverage reports 135 | htmlcov/ 136 | .tox/ 137 | .nox/ 138 | .coverage 139 | .coverage.* 140 | .cache 141 | nosetests.xml 142 | coverage.xml 143 | *.cover 144 | *.py,cover 145 | .hypothesis/ 146 | .pytest_cache/ 147 | 148 | # Translations 149 | *.mo 150 | *.pot 151 | 152 | # Django stuff: 153 | *.log 154 | local_settings.py 155 | db.sqlite3 156 | db.sqlite3-journal 157 | 158 | # Flask stuff: 159 | instance/ 160 | .webassets-cache 161 | 162 | # Scrapy stuff: 163 | .scrapy 164 | 165 | # Sphinx documentation 166 | docs/_build/ 167 | 168 | # PyBuilder 169 | target/ 170 | 171 | # Jupyter Notebook 172 | .ipynb_checkpoints 173 | 174 | # IPython 175 | profile_default/ 176 | ipython_config.py 177 | 178 | # pyenv 179 | .python-version 180 | 181 | # pipenv 182 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 183 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 184 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 185 | # install all needed dependencies. 186 | #Pipfile.lock 187 | 188 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 189 | __pypackages__/ 190 | 191 | # Celery stuff 192 | celerybeat-schedule 193 | celerybeat.pid 194 | 195 | # SageMath parsed files 196 | *.sage.py 197 | 198 | # Environments 199 | .env 200 | .venv 201 | env/ 202 | venv/ 203 | ENV/ 204 | env.bak/ 205 | venv.bak/ 206 | 207 | # Spyder project settings 208 | .spyderproject 209 | .spyproject 210 | 211 | # Rope project settings 212 | .ropeproject 213 | 214 | # mkdocs documentation 215 | /site 216 | 217 | # mypy 218 | .mypy_cache/ 219 | .dmypy.json 220 | dmypy.json 221 | 222 | # Pyre type checker 223 | .pyre/ 224 | 225 | # pytype static type analyzer 226 | .pytype/ 227 | 228 | # End of https://www.toptal.com/developers/gitignore/api/python,pycharm+all 229 | 230 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Alt text](logo.png?raw=true "IntelSpy") 2 | 3 | Perform automated network reconnaissance scans to gather network intelligence. 4 | 5 | IntelSpy is a multi-threaded network intelligence tool which performs automated network services enumeration. It performs live hosts detection scans, port scans, services enumeration scans, web content scans, brute-forcing, detailed off-line exploits searches and more. 6 | 7 | The tool will also launch further enumeration scans for each detected service using a number of different tools. 8 | 9 | --- 10 | 11 | ### Features 12 | 13 | * Scans multiple targets in the form of IP addresses, IP ranges (CIDR notation) and resolvable hostnames. 14 | * Scans targets concurrently. 15 | * Detects live hosts in an IP range (CIDR) network. 16 | * Customizable port scanning profiles and service enumeration commands. 17 | * Creates a directory structure for results gathering and reporting. 18 | * Logs every command that was executed. 19 | * Generates shell scripts containing commands to be run manually. 20 | * Extracts important information in txt and markdown format for further inspection. 21 | * Stores data to an SQLite database. 22 | * Generates an HTML report. 23 | 24 | --- 25 | 26 | ### Requirements 27 | 28 | * Python 3 (``` sudo apt install python3 ```) 29 | * Linux (preferably Kali Linux or any other hacking distribution containing the tools below.) 30 | * https://www.kali.org/downloads/ 31 | * toml (https://github.com/toml-lang/toml) 32 | * seclists (https://github.com/danielmiessler/SecLists) 33 | * curl (*prerequisite*) (``` sudo apt install curl ```) 34 | * enum4linux (*prerequisite*) (``` sudo apt install enum4linux ```) 35 | * gobuster (*prerequisite*) (``` sudo apt install gobuster ```) 36 | * hydra (*optional*) (``` sudo apt install hydra ```) 37 | * ldapsearch (*optional*) (``` sudo apt install ldap-utils ```) 38 | * medusa (*optional*) (``` sudo apt install medusa ```) 39 | * nbtscan (*prerequisite*) (``` sudo apt install nbtscan ```) 40 | * nikto (*prerequisite*) (``` sudo apt install nikto ```) 41 | * nmap (*prerequisite*) (``` sudo apt install nmap ```) 42 | * onesixtyone (*prerequisite*) (``` sudo apt install onesixtyone ```) 43 | * oscanner (*optional*) (``` sudo apt install oscanner ```) 44 | * pandoc (*prerequisite*) (``` sudo apt install pandoc ```) 45 | * patator (*optional*) (``` sudo apt install patator ```) 46 | * showmount (*prerequisite*) (``` sudo apt install nfs-common ```) 47 | * smbclient (*prerequisite*) (``` sudo apt install smbclient ```) 48 | * smbmap (*prerequisite*) (``` sudo apt install smbmap ```) 49 | * smtp-user-enum (*prerequisite*) (``` sudo apt install smtp-user-enum ```) 50 | * snmpwalk (*prerequisite*) (``` sudo apt install snmp ```) 51 | * sslscan (*prerequisite*) (``` sudo apt install sslscan ```) 52 | * svwar (*prerequisite*) (``` sudo apt install sipvicious ```) 53 | * tnscmd10g (*prerequisite*) (``` sudo apt install tnscmd10g ```) 54 | * whatweb (*prerequisite*) (``` sudo apt install whatweb ```) 55 | * wkhtmltoimage (*prerequisite*) (``` sudo apt install wkhtmltopdf ```) 56 | * wpscan (*optional*) (``` sudo apt install wpscan ```) 57 | 58 | 59 | ``` 60 | pip3 install -r requirements.txt 61 | ``` 62 | 63 | --- 64 | 65 | ### Usage 66 | 67 | ``` 68 | $ python3 intelspy.py -h 69 | 70 | ___ __ 71 | | ._ _|_ _ | (_ ._ 72 | _|_ | | |_ (/_ | __) |_) \/ 73 | | / 74 | 75 | IntelSpy v2.0 - Perform automated network reconnaissance scans to gather network intelligence. 76 | IntelSpy is an open source tool licensed under GPLv3. 77 | Written by: @maldevel | Logisek ICT 78 | Web: https://logisek.com | https://pentest-labs.com 79 | Project: https://github.com/maldevel/intelspy 80 | 81 | 82 | usage: intelspy.py [-h] [-ts TARGET_FILE] -p PROJECT_NAME -w WORKING_DIR 83 | [--exclude ] [-s SPEED] 84 | [-ct ] [-cs ] [--profile PROFILE_NAME] 85 | [--livehost-profile LIVEHOST_PROFILE_NAME] 86 | [--heartbeat HEARTBEAT] [-v] 87 | [targets [targets ...]] 88 | 89 | positional arguments: 90 | targets IP addresses (e.g. 10.0.0.1), CIDR notation (e.g. 91 | 10.0.0.1/24), or resolvable hostnames (e.g. 92 | example.com) to scan. 93 | 94 | optional arguments: 95 | -h, --help show this help message and exit 96 | -ts TARGET_FILE, --targets TARGET_FILE 97 | Read targets from file. 98 | -p PROJECT_NAME, --project-name PROJECT_NAME 99 | project name 100 | -w WORKING_DIR, --working-dir WORKING_DIR 101 | working directory 102 | --exclude 103 | exclude hosts/networks 104 | -s SPEED, --speed SPEED 105 | 0-5, set timing template (higher is faster) (default: 106 | 4) 107 | -ct , --concurrent-targets 108 | The maximum number of target hosts to scan 109 | concurrently. Default: 5 110 | -cs , --concurrent-scans 111 | The maximum number of scans to perform per target 112 | host. Default: 10 113 | --profile PROFILE_NAME 114 | The port scanning profile to use (defined in port- 115 | scan-profiles.toml). Default: default 116 | --livehost-profile LIVEHOST_PROFILE_NAME 117 | The live host scanning profile to use (defined in 118 | live-host-scan-profiles.toml). Default: default 119 | --heartbeat HEARTBEAT 120 | Specifies the heartbeat interval (in seconds) for task 121 | status messages. Default: 60 122 | -v, --verbose Enable verbose output. Repeat for more verbosity (-v, 123 | -vv, -vvv). 124 | ``` 125 | 126 | --- 127 | 128 | ### Usage Examples 129 | 130 | Scanning single target 131 | 132 | ``` 133 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ 192.168.10.15 134 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ 192.168.10.15 -v 135 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ 192.168.10.15 -vv 136 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ 192.168.10.15 -vvv 137 | ``` 138 | 139 | Scanning a hostname 140 | 141 | ``` 142 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ example.com 143 | ``` 144 | 145 | Scanning a network range(CIDR) 146 | 147 | ``` 148 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ 192.168.10.0/24 149 | ``` 150 | 151 | Scanning multiple targets (comma separated) 152 | 153 | ``` 154 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ 192.168.10.15 192.168.10.0/24 example.com 155 | ``` 156 | 157 | Scanning targets from file 158 | 159 | ``` 160 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ -ts /home/user/targets.txt 161 | ``` 162 | 163 | Excluding one host 164 | 165 | ``` 166 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ --exclude 192.168.10.9 192.168.10.0/24 167 | ``` 168 | 169 | Excluding many hosts 170 | 171 | ``` 172 | sudo python3 intelspy.py -p MyProjectName -w /home/user/pt/projects/ --exclude 192.168.10.9,192.168.10.24 192.168.10.0/24 173 | ``` 174 | 175 | --- 176 | 177 | ### Credits 178 | 179 | I started working on IntelSpy when I discovered [AutoRecon](https://github.com/Tib3rius/AutoRecon). Instead of reinventing the wheel, IntelSpy is the result of merging IntelSpy with the best features of the AutoRecon to create a network reconnaissance tool suitable for Penetration Testing engagements. 180 | 181 | --- 182 | -------------------------------------------------------------------------------- /intelspy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # encoding: UTF-8 3 | 4 | # This file is part of IntelSpy 5 | # Copyright (C) 2020 @maldevel 6 | # https://github.com/maldevel/intelspy 7 | # 8 | # IntelSpy - Perform automated network reconnaissance scans. 9 | # Gather network intelligence. 10 | # 11 | # This program is free software: you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see . 23 | # 24 | # For more see the file 'LICENSE' for copying permission. 25 | 26 | 27 | # Created by @maldevel | Logisek ICT 28 | # https://logisek.com | https://pentest-labs.com 29 | # intelspy.py | Python3 30 | # Released under GPL Version 3 License 31 | # 2020 32 | 33 | 34 | import atexit 35 | import argparse 36 | import asyncio 37 | # import colorama 38 | from colorama import Fore, Style 39 | from concurrent.futures import ProcessPoolExecutor, as_completed, FIRST_COMPLETED 40 | from datetime import datetime 41 | import ipaddress 42 | import os 43 | import re 44 | import socket 45 | import string 46 | import sys 47 | import time 48 | import toml 49 | import termios 50 | from pathlib import Path 51 | from datetime import timezone 52 | import sqlite3 53 | import subprocess 54 | # from subprocess import Popen, PIPE, STDOUT 55 | from random import randrange 56 | from collections import namedtuple 57 | import shutil 58 | 59 | ##################################################################################################################### 60 | 61 | __version__ = 2.0 62 | 63 | ##################################################################################################################### 64 | 65 | message = """ 66 | ___ __ 67 | | ._ _|_ _ | (_ ._ 68 | _|_ | | |_ (/_ | __) |_) \/ 69 | | / 70 | 71 | IntelSpy v{0} - Perform automated network reconnaissance scans to gather network intelligence. 72 | IntelSpy is an open source tool licensed under GPLv3. 73 | Written by: @maldevel | Logisek ICT 74 | Web: https://logisek.com | https://pentest-labs.com 75 | Project: https://github.com/maldevel/intelspy 76 | 77 | """.format(__version__) 78 | 79 | 80 | ##################################################################################################################### 81 | def _quit(): 82 | try: 83 | termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, TERM_FLAGS) 84 | except Exception as e: 85 | pass 86 | 87 | 88 | ##################################################################################################################### 89 | 90 | atexit.register(_quit) 91 | TERM_FLAGS = termios.tcgetattr(sys.stdin.fileno()) 92 | 93 | verbose = 0 94 | speed = 4 95 | # nmap = '-vv --reason -Pn' 96 | nmap = '' 97 | heartbeat_interval = 60 98 | 99 | RootDir = os.path.dirname(os.path.realpath(__file__)) 100 | ProjectDir = '' 101 | CommandsDir = '' 102 | DatabaseDir = '' 103 | LogsDir = '' 104 | ReportDir = '' 105 | TargetsDir = '' 106 | LogsFile = '' 107 | DatabaseFile = '' 108 | FinalReportMDFile = '' 109 | FinalReportHTMLFile = '' 110 | CommandsFile = '' 111 | ManualCommandsFile = '' 112 | 113 | username_wordlist = '/usr/share/seclists/Usernames/top-usernames-shortlist.txt' 114 | password_wordlist = '/usr/share/seclists/Passwords/darkweb2017-top100.txt' 115 | 116 | CurrentDateTime = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") 117 | DbConnection = None 118 | 119 | Matched_Patterns_Report = [] 120 | 121 | tools = ['curl', 'enum4linux', 'gobuster', 'nbtscan', 'nikto', 'nmap', 'onesixtyone', 'pandoc', 'showmount', 122 | 'smbclient', 'smbmap', 'smtp-user-enum', 'snmpwalk', 'sslscan', 'svwar', 'tnscmd10g', 'whatweb', 123 | 'wkhtmltoimage'] 124 | 125 | 126 | ##################################################################################################################### 127 | def e(*args, frame_index=1, **kvargs): 128 | frame = sys._getframe(frame_index) 129 | 130 | vals = {} 131 | 132 | vals.update(frame.f_globals) 133 | vals.update(frame.f_locals) 134 | vals.update(kvargs) 135 | 136 | return string.Formatter().vformat(' '.join(args), args, vals) 137 | 138 | 139 | ##################################################################################################################### 140 | def cprint(*args, type='info', color=Fore.RESET, char='*', sep=' ', end='\n', frame_index=1, file=sys.stdout, **kvargs): 141 | frame = sys._getframe(frame_index) 142 | 143 | vals = { 144 | 'bgreen': Fore.GREEN + Style.BRIGHT, 145 | 'bred': Fore.RED + Style.BRIGHT, 146 | 'bblue': Fore.BLUE + Style.BRIGHT, 147 | 'byellow': Fore.YELLOW + Style.BRIGHT, 148 | 'bmagenta': Fore.MAGENTA + Style.BRIGHT, 149 | 150 | 'green': Fore.GREEN, 151 | 'red': Fore.RED, 152 | 'blue': Fore.BLUE, 153 | 'yellow': Fore.YELLOW, 154 | 'magenta': Fore.MAGENTA, 155 | 156 | 'bright': Style.BRIGHT, 157 | 'srst': Style.NORMAL, 158 | 'crst': Fore.RESET, 159 | 'rst': Style.NORMAL + Fore.RESET 160 | } 161 | 162 | vals.update(frame.f_globals) 163 | vals.update(frame.f_locals) 164 | vals.update(kvargs) 165 | 166 | unfmt = '' 167 | if char is not None: 168 | unfmt += color + '[' + Style.BRIGHT + char + Style.NORMAL + ']' + Fore.RESET + sep 169 | unfmt += sep.join(args) 170 | 171 | fmted = unfmt 172 | 173 | for attempt in range(10): 174 | try: 175 | fmted = string.Formatter().vformat(unfmt, args, vals) 176 | break 177 | except KeyError as err: 178 | key = err.args[0] 179 | unfmt = unfmt.replace('{' + key + '}', '{{' + key + '}}') 180 | 181 | print(fmted, sep=sep, end=end, file=file) 182 | 183 | # try: 184 | # with open(LogsFile, "a") as logFile: 185 | # ts = datetime.now().strftime("%d/%b/%Y:%H:%M:%S") 186 | # tz = datetime.now(timezone.utc).astimezone().strftime('%z') 187 | # hostname = socket.gethostname() 188 | # printable = set(string.printable) 189 | # logStr = ''.join(filter(lambda x: x in printable, fmted)) 190 | # logStr = re.sub(r"\[[0-9]{1,2}m", "", logStr) 191 | # logFile.write("[{0} {1}] {2} Type={3} Log=\"{4}\"\n".format(ts, tz, hostname, type, logStr)) 192 | # except Exception as e: 193 | # 194 | # #sys.exit(1) 195 | 196 | 197 | ##################################################################################################################### 198 | def debug(*args, color=Fore.BLUE, sep=' ', end='\n', file=sys.stdout, **kvargs): 199 | if verbose >= 3: 200 | cprint(*args, type='debug', color=color, char='-', sep=sep, end=end, file=file, frame_index=2, **kvargs) 201 | 202 | 203 | def info(*args, sep=' ', end='\n', file=sys.stdout, **kvargs): 204 | cprint(*args, type='info', color=Fore.GREEN, char='*', sep=sep, end=end, file=file, frame_index=2, **kvargs) 205 | 206 | 207 | def warn(*args, sep=' ', end='\n', file=sys.stderr, **kvargs): 208 | cprint(*args, type='warning', color=Fore.YELLOW, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs) 209 | 210 | 211 | def error(*args, sep=' ', end='\n', file=sys.stderr, **kvargs): 212 | cprint(*args, type='error', color=Fore.RED, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs) 213 | 214 | 215 | def question(*args, sep=' ', end='', file=sys.stderr, **kvargs): 216 | cprint(*args, type='warning', color=Fore.YELLOW, char='?', sep=sep, end=end, file=file, frame_index=2, **kvargs) 217 | 218 | 219 | def fail(*args, sep=' ', end='\n', file=sys.stderr, **kvargs): 220 | cprint(*args, type='failure', color=Fore.RED, char='!', sep=sep, end=end, file=file, frame_index=2, **kvargs) 221 | exit(-1) 222 | 223 | 224 | ##################################################################################################################### 225 | def calculate_elapsed_time(start_time): 226 | elapsed_seconds = round(time.time() - start_time) 227 | 228 | m, s = divmod(elapsed_seconds, 60) 229 | h, m = divmod(m, 60) 230 | 231 | elapsed_time = [] 232 | if h == 1: 233 | elapsed_time.append(str(h) + ' hour') 234 | elif h > 1: 235 | elapsed_time.append(str(h) + ' hours') 236 | 237 | if m == 1: 238 | elapsed_time.append(str(m) + ' minute') 239 | elif m > 1: 240 | elapsed_time.append(str(m) + ' minutes') 241 | 242 | if s == 1: 243 | elapsed_time.append(str(s) + ' second') 244 | elif s > 1: 245 | elapsed_time.append(str(s) + ' seconds') 246 | else: 247 | elapsed_time.append('less than a second') 248 | 249 | return ', '.join(elapsed_time) 250 | 251 | 252 | ##################################################################################################################### 253 | 254 | def loadprofiles(live_host_scan_profiles_file, port_scan_profiles_file): 255 | with open(os.path.join(RootDir, 'profiles', live_host_scan_profiles_file), 'r') as p: 256 | try: 257 | live_host_scan_profiles = toml.load(p) 258 | 259 | if len(live_host_scan_profiles) == 0: 260 | fail( 261 | 'There do not appear to be any port scan profiles configured in the {live_host_scan_profiles_file} ' 262 | 'profiles file.') 263 | 264 | except toml.decoder.TomlDecodeError as e: 265 | fail( 266 | 'Error: Couldn\'t parse {live_host_scan_profiles_file} profiles file. Check syntax and duplicate tags.') 267 | 268 | with open(os.path.join(RootDir, 'profiles', port_scan_profiles_file), 'r') as p: 269 | try: 270 | port_scan_profiles = toml.load(p) 271 | 272 | if len(port_scan_profiles) == 0: 273 | fail( 274 | 'There do not appear to be any port scan profiles configured in the {port_scan_profiles_file} ' 275 | 'profiles file.') 276 | 277 | except toml.decoder.TomlDecodeError as e: 278 | fail('Error: Couldn\'t parse {port_scan_profiles_file} profiles file. Check syntax and duplicate tags.') 279 | 280 | with open(os.path.join(RootDir, 'profiles', 'service-scans-profiles.toml'), 'r') as c: 281 | try: 282 | service_scans_profiles = toml.load(c) 283 | except toml.decoder.TomlDecodeError as e: 284 | fail('Error: Couldn\'t parse service-scans-profiles.toml profiles file. Check syntax and duplicate tags.') 285 | 286 | with open(os.path.join(RootDir, 'profiles', 'global-patterns.toml'), 'r') as p: 287 | try: 288 | global_patterns = toml.load(p) 289 | if 'pattern' in global_patterns: 290 | global_patterns = global_patterns['pattern'] 291 | else: 292 | global_patterns = [] 293 | except toml.decoder.TomlDecodeError as e: 294 | fail('Error: Couldn\'t parse global-patterns.toml profiles file. Check syntax and duplicate tags.') 295 | 296 | if 'username_wordlist' in service_scans_profiles: 297 | if isinstance(service_scans_profiles['username_wordlist'], str): 298 | uw = service_scans_profiles['username_wordlist'] 299 | 300 | if 'password_wordlist' in service_scans_profiles: 301 | if isinstance(service_scans_profiles['password_wordlist'], str): 302 | pw = service_scans_profiles['password_wordlist'] 303 | 304 | return live_host_scan_profiles, port_scan_profiles, service_scans_profiles, global_patterns, uw, pw 305 | 306 | 307 | ##################################################################################################################### 308 | 309 | async def read_stream(stream, target, global_patterns, tag='?', patterns=[], color=Fore.BLUE): 310 | matched_patterns = [] 311 | address = target.address 312 | addressname = target.addressname 313 | 314 | while True: 315 | line = await stream.readline() 316 | if line: 317 | line = str(line.rstrip(), 'utf8', 'ignore') 318 | debug(color + '[' + Style.BRIGHT + address + ' ' + tag + Style.NORMAL + '] ' + Fore.RESET + '{line}', 319 | color=color) 320 | 321 | for p in global_patterns: 322 | matches = re.findall(p['pattern'], line) 323 | 324 | if 'description' in p: 325 | for match in matches: 326 | if verbose >= 1: 327 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} - {bmagenta}' + p[ 328 | 'description'].replace('{match}', '{bblue}{match}{crst}{bmagenta}') + '{rst}') 329 | async with target.lock: 330 | with open(os.path.join(target.reportsdir, 331 | target.address.replace('/', '_') + '_extra-information.txt'), 332 | 'a') as file: 333 | log_line = e('{tag} - {target.address} - ' + p['description'] + '\n\n') 334 | file.writelines(log_line) 335 | mp = e('{target.address} - ' + p['description'] + '\n\n').strip() 336 | if mp not in matched_patterns: 337 | matched_patterns.append(mp) 338 | 339 | 340 | 341 | else: 342 | for match in matches: 343 | if verbose >= 1: 344 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} - {bmagenta} {bblue}{match}{rst}') 345 | async with target.lock: 346 | with open(os.path.join(target.reportsdir, 347 | target.address.replace('/', '_') + '_extra-information.txt'), 348 | 'a') as file: 349 | log_line = e('{tag} - {target.address} - {match}\n\n') 350 | file.writelines(log_line) 351 | mp = e('{target.address}\n\n').strip() 352 | if mp not in matched_patterns: 353 | matched_patterns.append(mp) 354 | 355 | for p in patterns: 356 | matches = re.findall(p['pattern'], line) 357 | if 'description' in p: 358 | for match in matches: 359 | if verbose >= 1: 360 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} - {bmagenta}' + p[ 361 | 'description'].replace('{match}', '{bblue}{match}{crst}{bmagenta}') + '{rst}') 362 | async with target.lock: 363 | with open(os.path.join(target.reportsdir, 364 | target.address.replace('/', '_') + '_extra-information.txt'), 365 | 'a') as file: 366 | log_line = e('{tag} - {target.address} - ' + p['description'] + '\n\n') 367 | file.writelines(log_line) 368 | mp = e('{target.address} - ' + p['description'] + '\n\n').strip() 369 | if mp not in matched_patterns: 370 | matched_patterns.append(mp) 371 | 372 | 373 | else: 374 | for match in matches: 375 | if verbose >= 1: 376 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} - {bmagenta} {bblue}{match}{rst}') 377 | async with target.lock: 378 | with open(os.path.join(target.reportsdir, 379 | target.address.replace('/', '_') + '_extra-information.txt'), 380 | 'a') as file: 381 | log_line = e('{tag} - {target.address} - {match}\n\n') 382 | file.writelines(log_line) 383 | mp = e('{target.address} - ' + p['description'] + '\n\n').strip() 384 | if mp not in matched_patterns: 385 | matched_patterns.append(mp) 386 | 387 | else: 388 | break 389 | 390 | return matched_patterns 391 | 392 | 393 | ##################################################################################################################### 394 | async def run_cmd(semaphore, cmd, target, global_patterns, tag='?', patterns=[]): 395 | async with semaphore: 396 | matched_patterns = [] 397 | address = target.address 398 | addressname = target.addressname 399 | reportsdir = target.reportsdir 400 | scandir = target.scansdir 401 | tcpportsdir = target.tcpportsdir 402 | fulltcpportsdir = target.fulltcpportsdir 403 | toptcpportsdir = target.toptcpportsdir 404 | udpportsdir = target.udpportsdir 405 | fulludpportsdir = target.fulludpportsdir 406 | topudpportsdir = target.topudpportsdir 407 | servicesdir = target.servicesdir 408 | screenshotsdir = target.screenshotsdir 409 | tcpservicesdir = target.tcpservicesdir 410 | udpservicesdir = target.udpservicesdir 411 | niktodir = target.niktodir 412 | dirscandir = target.dirscandir 413 | crackingdir = target.crackingdir 414 | webdir = target.webdir 415 | 416 | info('Running task {bgreen}{tag}{rst} on {byellow}{address}{rst}' + ( 417 | ' with {bblue}{cmd}{rst}' if verbose >= 2 else '')) 418 | 419 | async with target.lock: 420 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_commands.log'), 'a') as file: 421 | file.writelines(e('{cmd}\n\n')) 422 | with open(CommandsFile, 'a') as file: 423 | file.writelines(e('{cmd}\n\n')) 424 | 425 | start_time = time.time() 426 | process = await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE, 427 | stderr=asyncio.subprocess.PIPE, executable='/bin/bash') 428 | async with target.lock: 429 | target.running_tasks.append(tag) 430 | 431 | output = [ 432 | read_stream(process.stdout, target, global_patterns, tag=tag, patterns=patterns), 433 | read_stream(process.stderr, target, global_patterns, tag=tag, patterns=patterns, color=Fore.RED) 434 | ] 435 | 436 | results = await asyncio.gather(*output) 437 | 438 | await process.wait() 439 | async with target.lock: 440 | target.running_tasks.remove(tag) 441 | 442 | elapsed_time = calculate_elapsed_time(start_time) 443 | 444 | if process.returncode != 0: 445 | error('Task {bred}{tag}{rst} on {byellow}{address}{rst} returned non-zero exit code: {process.returncode}') 446 | 447 | async with target.lock: 448 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_errors.log'), 'a') as file: 449 | ts = datetime.now().strftime("%d/%b/%Y:%H:%M:%S") 450 | tz = datetime.now(timezone.utc).astimezone().strftime('%z') 451 | hostname = socket.gethostname() 452 | timestp = "[{0} {1}] {2}".format(ts, tz, hostname) 453 | file.writelines( 454 | e('{timestp} Task {tag} returned non-zero exit code: {process.returncode}. Command: {cmd}\n')) 455 | else: 456 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} finished successfully in {elapsed_time}') 457 | 458 | if results[0]: 459 | matched_patterns = results[0] 460 | 461 | return {'returncode': process.returncode, 'name': 'run_cmd', 'patterns': matched_patterns} 462 | 463 | 464 | ##################################################################################################################### 465 | async def parse_port_scan(stream, tag, target, pattern, global_patterns): 466 | matched_patterns = [] 467 | address = target.address 468 | addressname = target.addressname 469 | ports = [] 470 | 471 | while True: 472 | line = await stream.readline() 473 | if line: 474 | line = str(line.rstrip(), 'utf8', 'ignore') 475 | debug(Fore.BLUE + '[' + Style.BRIGHT + address + ' ' + tag + Style.NORMAL + '] ' + Fore.RESET + '{line}', 476 | color=Fore.BLUE) 477 | 478 | parse_match = re.search(pattern, line) 479 | if parse_match: 480 | ports.append(parse_match.group('port')) 481 | 482 | for p in global_patterns: 483 | matches = re.findall(p['pattern'], line) 484 | 485 | if 'description' in p: 486 | for match in matches: 487 | if verbose >= 1: 488 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} - {bmagenta}' + p[ 489 | 'description'].replace('{match}', '{bblue}{match}{crst}{bmagenta}') + '{rst}') 490 | async with target.lock: 491 | with open(os.path.join(target.reportsdir, 492 | target.address.replace('/', '_') + '_extra-information.txt'), 493 | 'a') as file: 494 | log_line = e('{tag} - {target.address} - ' + p['description'] + '\n\n') 495 | file.writelines(log_line) 496 | mp = e('{target.address} - ' + p['description'] + '\n\n').strip() 497 | if mp not in matched_patterns: 498 | matched_patterns.append(mp) 499 | 500 | else: 501 | for match in matches: 502 | if verbose >= 1: 503 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} - {bmagenta} {bblue}{match}{rst}') 504 | async with target.lock: 505 | with open(os.path.join(target.reportsdir, 506 | target.address.replace('/', '_') + '_extra-information.txt'), 507 | 'a') as file: 508 | log_line = e('{tag} - {target.address} - {match}\n\n') 509 | file.writelines(log_line) 510 | mp = e('{target.address} - ' + p['description'] + '\n\n').strip() 511 | if mp not in matched_patterns: 512 | matched_patterns.append(mp) 513 | else: 514 | break 515 | 516 | return ports, matched_patterns 517 | 518 | 519 | ##################################################################################################################### 520 | async def parse_live_host_detection(stream, tag, target, pattern, global_patterns): 521 | matched_patterns = [] 522 | address = target.address 523 | addressname = target.addressname 524 | host = '' 525 | livehosts = [] 526 | 527 | while True: 528 | line = await stream.readline() 529 | if line: 530 | line = str(line.rstrip(), 'utf8', 'ignore') 531 | debug(Fore.BLUE + '[' + Style.BRIGHT + address + ' ' + tag + Style.NORMAL + '] ' + Fore.RESET + '{line}', 532 | color=Fore.BLUE) 533 | 534 | parse_match = re.search(pattern, line) 535 | 536 | if parse_match: 537 | livehosts.append(parse_match.group('address')) 538 | host = parse_match.group('address') 539 | 540 | for p in global_patterns: 541 | matches = re.findall(p['pattern'], line) 542 | 543 | if 'description' in p: 544 | for match in matches: 545 | if verbose >= 1: 546 | info('Task {bgreen}{tag}{rst} on {byellow}{host}{rst} - {bmagenta}' + p[ 547 | 'description'].replace('{match}', '{bblue}{match}{crst}{bmagenta}') + '{rst}') 548 | async with target.lock: 549 | with open(os.path.join(target.reportsdir, 550 | target.address.replace('/', '_') + '_extra-information.txt'), 551 | 'a') as file: 552 | log_line = e('{tag} - {host} - ' + p['description'] + '\n\n') 553 | file.writelines(log_line) 554 | mp = e('{host} - ' + p['description'] + '\n\n').strip() 555 | if mp not in matched_patterns: 556 | matched_patterns.append(mp) 557 | 558 | 559 | else: 560 | for match in matches: 561 | if verbose >= 1: 562 | info('Task {bgreen}{tag}{rst} on {byellow}{host}{rst} - {bmagenta} {bblue}{match}{rst}') 563 | async with target.lock: 564 | with open(os.path.join(target.reportsdir, 565 | target.address.replace('/', '_') + '_extra-information.txt'), 566 | 'a') as file: 567 | log_line = e('{tag} - {host} - {match}\n\n') 568 | file.writelines(log_line) 569 | mp = e('{host}\n\n').strip() 570 | if mp not in matched_patterns: 571 | matched_patterns.append(mp) 572 | 573 | 574 | else: 575 | break 576 | 577 | return livehosts, matched_patterns 578 | 579 | 580 | ##################################################################################################################### 581 | async def parse_service_detection(stream, tag, target, pattern, global_patterns): 582 | matched_patterns = [] 583 | address = target.address 584 | addressname = target.addressname 585 | services = [] 586 | 587 | while True: 588 | line = await stream.readline() 589 | if line: 590 | line = str(line.rstrip(), 'utf8', 'ignore') 591 | debug(Fore.BLUE + '[' + Style.BRIGHT + address + ' ' + tag + Style.NORMAL + '] ' + Fore.RESET + '{line}', 592 | color=Fore.BLUE) 593 | 594 | parse_match = re.search(pattern, line) 595 | if parse_match: 596 | services.append((parse_match.group('protocol').lower(), int(parse_match.group('port')), 597 | parse_match.group('service'), parse_match.group('version'))) 598 | 599 | for p in global_patterns: 600 | matches = re.findall(p['pattern'], line) 601 | 602 | if 'description' in p: 603 | for match in matches: 604 | if verbose >= 1: 605 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} - {bmagenta}' + p[ 606 | 'description'].replace('{match}', '{bblue}{match}{crst}{bmagenta}') + '{rst}') 607 | async with target.lock: 608 | with open(os.path.join(target.reportsdir, 609 | target.address.replace('/', '_') + '_extra-information.txt'), 610 | 'a') as file: 611 | log_line = e('{tag} - {target.address} - ' + p['description'] + '\n\n') 612 | file.writelines(log_line) 613 | mp = e('{target.address} - ' + p['description'] + '\n\n').strip() 614 | if mp not in matched_patterns: 615 | matched_patterns.append(mp) 616 | 617 | 618 | 619 | else: 620 | for match in matches: 621 | if verbose >= 1: 622 | info('Task {bgreen}{tag}{rst} on {byellow}{address}{rst} - {bmagenta} {bblue}{match}{rst}') 623 | async with target.lock: 624 | with open(os.path.join(target.reportsdir, 625 | target.address.replace('/', '_') + '_extra-information.txt'), 626 | 'a') as file: 627 | log_line = e('{tag} - {target.address} - {match}\n\n') 628 | file.writelines(log_line) 629 | mp = e('{target.address}\n\n').strip() 630 | if mp not in matched_patterns: 631 | matched_patterns.append(mp) 632 | 633 | 634 | else: 635 | break 636 | 637 | return services, matched_patterns 638 | 639 | 640 | ##################################################################################################################### 641 | async def run_livehostscan(semaphore, tag, target, live_host_detection, global_patterns, nmapextra): 642 | async with semaphore: 643 | 644 | address = target.address 645 | addressname = target.addressname 646 | reportsdir = target.reportsdir 647 | scandir = target.scansdir 648 | nmap_speed = target.speed 649 | nmap_extra = nmapextra 650 | tcpportsdir = target.tcpportsdir 651 | fulltcpportsdir = target.fulltcpportsdir 652 | toptcpportsdir = target.toptcpportsdir 653 | udpportsdir = target.udpportsdir 654 | fulludpportsdir = target.fulludpportsdir 655 | topudpportsdir = target.topudpportsdir 656 | servicesdir = target.servicesdir 657 | screenshotsdir = target.screenshotsdir 658 | tcpservicesdir = target.tcpservicesdir 659 | udpservicesdir = target.udpservicesdir 660 | niktodir = target.niktodir 661 | dirscandir = target.dirscandir 662 | crackingdir = target.crackingdir 663 | webdir = target.webdir 664 | 665 | command = e(live_host_detection[0]) 666 | pattern = live_host_detection[1] 667 | 668 | info('Running live hosts detection {bgreen}{tag}{rst} on {byellow}{address}{rst}' + ( 669 | ' with {bblue}{command}{rst}' if verbose >= 2 else '')) 670 | 671 | async with target.lock: 672 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_commands.log'), 'a') as file: 673 | file.writelines(e('{command}\n\n')) 674 | with open(CommandsFile, 'a') as file: 675 | file.writelines(e('{command}\n\n')) 676 | 677 | start_time = time.time() 678 | process = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE, 679 | stderr=asyncio.subprocess.PIPE, executable='/bin/bash') 680 | async with target.lock: 681 | target.running_tasks.append(tag) 682 | 683 | output = [ 684 | parse_live_host_detection(process.stdout, tag, target, pattern, global_patterns), 685 | read_stream(process.stderr, target, global_patterns, tag=tag, color=Fore.RED) 686 | ] 687 | 688 | results = await asyncio.gather(*output) 689 | 690 | await process.wait() 691 | async with target.lock: 692 | target.running_tasks.remove(tag) 693 | 694 | elapsed_time = calculate_elapsed_time(start_time) 695 | 696 | if process.returncode != 0: 697 | error( 698 | 'Live hosts detection {bred}{tag}{rst} on {byellow}{address}{rst} returned non-zero exit code: {process.returncode}') 699 | async with target.lock: 700 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_errors.log'), 'a') as file: 701 | file.writelines(e( 702 | '[*] Live host detection {tag} returned non-zero exit code: {process.returncode}. Command: {command}\n')) 703 | else: 704 | info( 705 | 'Live hosts detection {bgreen}{tag}{rst} on {byellow}{address}{rst} finished successfully in {elapsed_time}') 706 | 707 | livehosts = results[0][0] 708 | matched_patterns = results[0][1] 709 | 710 | return {'returncode': process.returncode, 'name': 'run_livehostscan', 'livehosts': livehosts, 711 | 'patterns': matched_patterns} 712 | 713 | 714 | ##################################################################################################################### 715 | async def run_portscan(semaphore, tag, target, service_detection, global_patterns, nmapextra, port_scan=None): 716 | async with semaphore: 717 | ports_matched_patterns = [] 718 | services_matched_patterns = [] 719 | address = target.address 720 | addressname = target.addressname 721 | reportsdir = target.reportsdir 722 | scandir = target.scansdir 723 | nmap_speed = target.speed 724 | nmap_extra = nmapextra 725 | tcpportsdir = target.tcpportsdir 726 | fulltcpportsdir = target.fulltcpportsdir 727 | toptcpportsdir = target.toptcpportsdir 728 | udpportsdir = target.udpportsdir 729 | fulludpportsdir = target.fulludpportsdir 730 | topudpportsdir = target.topudpportsdir 731 | servicesdir = target.servicesdir 732 | screenshotsdir = target.screenshotsdir 733 | tcpservicesdir = target.tcpservicesdir 734 | udpservicesdir = target.udpservicesdir 735 | niktodir = target.niktodir 736 | dirscandir = target.dirscandir 737 | crackingdir = target.crackingdir 738 | webdir = target.webdir 739 | 740 | ports = '' 741 | if port_scan is not None: 742 | command = e(port_scan[0]) 743 | pattern = port_scan[1] 744 | 745 | info('Running port scan {bgreen}{tag}{rst} on {byellow}{address}{rst}' + ( 746 | ' with {bblue}{command}{rst}' if verbose >= 2 else '')) 747 | 748 | async with target.lock: 749 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_commands.log'), 'a') as file: 750 | file.writelines(e('{command}\n\n')) 751 | with open(CommandsFile, 'a') as file: 752 | file.writelines(e('{command}\n\n')) 753 | 754 | start_time = time.time() 755 | process = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE, 756 | stderr=asyncio.subprocess.PIPE, executable='/bin/bash') 757 | 758 | async with target.lock: 759 | target.running_tasks.append(tag) 760 | 761 | output = [ 762 | parse_port_scan(process.stdout, tag, target, pattern, global_patterns), 763 | read_stream(process.stderr, target, global_patterns, tag=tag, color=Fore.RED) 764 | ] 765 | 766 | results = await asyncio.gather(*output) 767 | 768 | await process.wait() 769 | async with target.lock: 770 | target.running_tasks.remove(tag) 771 | elapsed_time = calculate_elapsed_time(start_time) 772 | 773 | if process.returncode != 0: 774 | error( 775 | 'Port scan {bred}{tag}{rst} on {byellow}{address}{rst} returned non-zero exit code: {process.returncode}') 776 | async with target.lock: 777 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_errors.log'), 'a') as file: 778 | file.writelines(e( 779 | '[*] Port scan {tag} returned non-zero exit code: {process.returncode}. Command: {command}\n')) 780 | return {'returncode': process.returncode} 781 | else: 782 | info('Port scan {bgreen}{tag}{rst} on {byellow}{address}{rst} finished successfully in {elapsed_time}') 783 | 784 | ports = results[0][0] 785 | ports_matched_patterns = results[0][1] 786 | 787 | if len(ports) == 0: 788 | return {'returncode': -1} 789 | 790 | ports = ','.join(ports) 791 | 792 | # add random closed high port for better OS fingerprinting results 793 | ports += ',' + str(randrange(64000, 65534)) 794 | 795 | command = e(service_detection[0]) 796 | pattern = service_detection[1] 797 | 798 | info('Running service detection {bgreen}{tag}{rst} on {byellow}{address}{rst}' + ( 799 | ' with {bblue}{command}{rst}' if verbose >= 2 else '')) 800 | 801 | async with target.lock: 802 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_commands.log'), 'a') as file: 803 | file.writelines(e('{command}\n\n')) 804 | with open(CommandsFile, 'a') as file: 805 | file.writelines(e('{command}\n\n')) 806 | 807 | start_time = time.time() 808 | process = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE, 809 | stderr=asyncio.subprocess.PIPE, executable='/bin/bash') 810 | async with target.lock: 811 | target.running_tasks.append(tag) 812 | 813 | output = [ 814 | parse_service_detection(process.stdout, tag, target, pattern, global_patterns), 815 | read_stream(process.stderr, target, global_patterns, tag=tag, color=Fore.RED) 816 | ] 817 | 818 | results = await asyncio.gather(*output) 819 | 820 | await process.wait() 821 | async with target.lock: 822 | target.running_tasks.remove(tag) 823 | elapsed_time = calculate_elapsed_time(start_time) 824 | 825 | if process.returncode != 0: 826 | error( 827 | 'Service detection {bred}{tag}{rst} on {byellow}{address}{rst} returned non-zero exit ' 828 | 'code: {process.returncode}') 829 | async with target.lock: 830 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_errors.log'), 'a') as file: 831 | file.writelines(e( 832 | '[*] Service detection {tag} returned non-zero exit code: {process.returncode}. ' 833 | 'Command: {command}\n')) 834 | else: 835 | info( 836 | 'Service detection {bgreen}{tag}{rst} on {byellow}{address}{rst} finished successfully ' 837 | 'in {elapsed_time}') 838 | 839 | services = results[0][0] 840 | services_matched_patterns = results[0][1] 841 | 842 | return {'returncode': process.returncode, 'name': 'run_portscan', 'services': services, 843 | 'ports_patterns': ports_matched_patterns, 'services_patterns': services_matched_patterns} 844 | 845 | 846 | ##################################################################################################################### 847 | async def start_heartbeat(target, period=60): 848 | while True: 849 | await asyncio.sleep(period) 850 | async with target.lock: 851 | tasks = target.running_tasks 852 | count = len(tasks) 853 | 854 | tasks_list = '' 855 | if verbose >= 1: 856 | tasks_list = ': {bgreen}' + ', '.join(tasks) + '{rst}' 857 | 858 | current_time = datetime.now().strftime('%H:%M:%S') 859 | 860 | if count > 1: 861 | info( 862 | '{bgreen}[{current_time}]{rst} - There are {byellow}{count}{rst} tasks still running ' 863 | 'on {byellow}{target.address}{rst}' + tasks_list) 864 | elif count == 1: 865 | info( 866 | '{bgreen}[{current_time}]{rst} - There is {byellow}1{rst} task still running ' 867 | 'on {byellow}{target.address}{rst}' + tasks_list) 868 | 869 | 870 | ##################################################################################################################### 871 | async def ping_and_scan(loop, semaphore, target, live_host_scan_profiles, live_host_scan_profile, global_patterns, 872 | nmapextra): 873 | address = target.address 874 | addressname = target.addressname 875 | reportsdir = target.reportsdir 876 | scandir = target.scansdir 877 | pending = [] 878 | tcpportsdir = target.tcpportsdir 879 | fulltcpportsdir = target.fulltcpportsdir 880 | toptcpportsdir = target.toptcpportsdir 881 | udpportsdir = target.udpportsdir 882 | fulludpportsdir = target.fulludpportsdir 883 | topudpportsdir = target.topudpportsdir 884 | servicesdir = target.servicesdir 885 | screenshotsdir = target.screenshotsdir 886 | tcpservicesdir = target.tcpservicesdir 887 | udpservicesdir = target.udpservicesdir 888 | niktodir = target.niktodir 889 | dirscandir = target.dirscandir 890 | crackingdir = target.crackingdir 891 | webdir = target.webdir 892 | 893 | heartbeat = loop.create_task(start_heartbeat(target, period=heartbeat_interval)) 894 | 895 | for profile in live_host_scan_profiles: 896 | if profile == live_host_scan_profile: # default: default 897 | 898 | for scan in live_host_scan_profiles[profile]: 899 | live_host_detection = (live_host_scan_profiles[profile][scan]['live-host-detection']['command'], 900 | live_host_scan_profiles[profile][scan]['live-host-detection']['pattern']) 901 | pending.append(run_livehostscan(semaphore, scan, target, live_host_detection, global_patterns, 902 | nmapextra)) 903 | break 904 | 905 | live_hosts = [] 906 | matched_patterns = [] 907 | 908 | while True: 909 | if not pending: 910 | heartbeat.cancel() 911 | break 912 | 913 | done, pending = await asyncio.wait(pending, return_when=FIRST_COMPLETED) 914 | 915 | for task in done: 916 | result = task.result() 917 | 918 | if result['returncode'] == 0: 919 | if result['name'] == 'run_livehostscan': 920 | 921 | for livehost in result['livehosts']: 922 | if livehost not in live_hosts: 923 | live_hosts.append(livehost) 924 | else: 925 | continue 926 | 927 | info('Found live host {bmagenta}{livehost}{rst} on target {byellow}{address}{rst}') 928 | 929 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_notes.txt'), 930 | 'a') as file: 931 | file.writelines(e('[*] Live host {livehost} found on target {address}.\n\n')) 932 | 933 | for pattern in result['patterns']: 934 | if pattern not in matched_patterns: 935 | matched_patterns.append(pattern) 936 | 937 | return live_hosts, matched_patterns 938 | 939 | 940 | ##################################################################################################################### 941 | async def scan_services(loop, semaphore, target, port_scan_profiles, port_scan_profile, service_scans_profiles, 942 | global_patterns, nmapextra): 943 | address = target.address 944 | addressname = target.addressname 945 | reportsdir = target.reportsdir 946 | scandir = target.scansdir 947 | nmap_speed = target.speed 948 | nmap_extra = '' 949 | pending = [] 950 | tcpportsdir = target.tcpportsdir 951 | fulltcpportsdir = target.fulltcpportsdir 952 | toptcpportsdir = target.toptcpportsdir 953 | udpportsdir = target.udpportsdir 954 | fulludpportsdir = target.fulludpportsdir 955 | topudpportsdir = target.topudpportsdir 956 | servicesdir = target.servicesdir 957 | screenshotsdir = target.screenshotsdir 958 | tcpservicesdir = target.tcpservicesdir 959 | udpservicesdir = target.udpservicesdir 960 | niktodir = target.niktodir 961 | dirscandir = target.dirscandir 962 | crackingdir = target.crackingdir 963 | webdir = target.webdir 964 | 965 | heartbeat = loop.create_task(start_heartbeat(target, period=heartbeat_interval)) 966 | 967 | for profile in port_scan_profiles: 968 | if profile == port_scan_profile: # default: default 969 | 970 | for scan in port_scan_profiles[profile]: 971 | 972 | service_detection = (port_scan_profiles[profile][scan]['service-detection']['command'], 973 | port_scan_profiles[profile][scan]['service-detection']['pattern']) 974 | 975 | if 'port-scan' in port_scan_profiles[profile][scan]: 976 | port_scan = (port_scan_profiles[profile][scan]['port-scan']['command'], 977 | port_scan_profiles[profile][scan]['port-scan']['pattern']) 978 | pending.append(run_portscan(semaphore, scan, target, service_detection, global_patterns, 979 | nmapextra, port_scan)) 980 | else: 981 | pending.append(run_portscan(semaphore, scan, target, service_detection, global_patterns, nmapextra)) 982 | break 983 | 984 | target_services = {} 985 | target_services[target.address] = [] 986 | matched_patterns = [] 987 | 988 | while True: 989 | if not pending: 990 | heartbeat.cancel() 991 | break 992 | 993 | done, pending = await asyncio.wait(pending, return_when=FIRST_COMPLETED) 994 | 995 | for task in done: 996 | result = task.result() 997 | 998 | if result['returncode'] == 0: 999 | 1000 | if result['name'] == 'run_cmd': 1001 | for pattern in result['patterns']: 1002 | if pattern not in matched_patterns: 1003 | matched_patterns.append(pattern) 1004 | 1005 | if result['name'] == 'run_portscan': 1006 | 1007 | for pattern in result['ports_patterns']: 1008 | if pattern not in matched_patterns: 1009 | matched_patterns.append(pattern) 1010 | 1011 | for pattern in result['services_patterns']: 1012 | if pattern not in matched_patterns: 1013 | matched_patterns.append(pattern) 1014 | 1015 | for service_tuple in result['services']: 1016 | if service_tuple not in target_services[target.address]: 1017 | 1018 | target_services[target.address].append(service_tuple) 1019 | else: 1020 | continue 1021 | 1022 | protocol = service_tuple[0] 1023 | port = service_tuple[1] 1024 | service = service_tuple[2] 1025 | version = service_tuple[3] 1026 | 1027 | info( 1028 | 'Found {bmagenta}{service}{rst} ({bmagenta}{version}{rst}) on {bmagenta}{protocol}/{port}{rst} on target {byellow}{address}{rst}') 1029 | 1030 | with open(os.path.join(reportsdir, target.address.replace('/', '_') + '_notes.txt'), 1031 | 'a') as file: 1032 | file.writelines(e('[*] {service} found on {protocol}/{port}.\n\n')) 1033 | 1034 | if protocol == 'udp': 1035 | nmap_extra = nmapextra + " -sU" 1036 | else: 1037 | nmap_extra = nmapextra 1038 | 1039 | secure = True if 'ssl' in service or 'tls' in service else False 1040 | 1041 | # print('service'+service) 1042 | # Special cases for HTTP. used in toml file 1043 | scheme = 'https' if 'https' in service or 'ssl' in service or 'tls' in service else 'http' 1044 | 1045 | if service.startswith('ssl/') or service.startswith('tls/'): 1046 | service = service[4:] 1047 | 1048 | for service_scan in service_scans_profiles: 1049 | # Skip over configurable variables since the python toml parser cannot iterate over tables only. 1050 | if service_scan in ['username_wordlist', 'password_wordlist']: 1051 | continue 1052 | 1053 | ignore_service = False 1054 | if 'ignore-service-names' in service_scans_profiles[service_scan]: 1055 | for ignore_service_name in service_scans_profiles[service_scan]['ignore-service-names']: 1056 | if re.search(ignore_service_name, service): 1057 | ignore_service = True 1058 | break 1059 | 1060 | if ignore_service: 1061 | continue 1062 | 1063 | matched_service = False 1064 | 1065 | if 'service-names' in service_scans_profiles[service_scan]: 1066 | for service_name in service_scans_profiles[service_scan]['service-names']: 1067 | if re.search(service_name, service): 1068 | matched_service = True 1069 | break 1070 | 1071 | if not matched_service: 1072 | continue 1073 | 1074 | if 'manual' in service_scans_profiles[service_scan]: 1075 | heading = False 1076 | 1077 | with open(os.path.join(reportsdir, 1078 | target.address.replace('/', '_') + '_manual_commands.txt'), 1079 | 'a') as file: 1080 | for manual in service_scans_profiles[service_scan]['manual']: 1081 | if 'description' in manual: 1082 | if not heading: 1083 | file.writelines(e('[*] {service} on {protocol}/{port}\n\n')) 1084 | heading = True 1085 | description = manual['description'] 1086 | file.writelines(e('\t[-] {description}\n\n')) 1087 | if 'commands' in manual: 1088 | if not heading: 1089 | file.writelines(e('[*] {service} on {protocol}/{port}\n\n')) 1090 | heading = True 1091 | for manual_command in manual['commands']: 1092 | manual_command = e(manual_command) 1093 | file.writelines('\t\t' + e('{manual_command}\n\n')) 1094 | if heading: 1095 | file.writelines('\n') 1096 | 1097 | shellscript = os.path.join(reportsdir, 1098 | target.address.replace('/', '_') + '_manual_commands.sh') 1099 | exists = os.path.isfile(shellscript) 1100 | 1101 | with open(shellscript, 'a') as file: 1102 | if not exists: 1103 | file.writelines('#!/bin/bash\n\n') 1104 | 1105 | for manual in service_scans_profiles[service_scan]['manual']: 1106 | if 'description' in manual: 1107 | if not heading: 1108 | file.writelines(e('# [*] {service} on {protocol}/{port}\n\n')) 1109 | heading = True 1110 | description = manual['description'] 1111 | file.writelines(e('#\t[-] {description}\n\n')) 1112 | if 'commands' in manual: 1113 | if not heading: 1114 | file.writelines(e('# [*] {service} on {protocol}/{port}\n\n')) 1115 | heading = True 1116 | for manual_command in manual['commands']: 1117 | manual_command = e(manual_command) 1118 | file.writelines(e('{manual_command}\n\n')) 1119 | if heading: 1120 | file.writelines('\n') 1121 | 1122 | with open(ManualCommandsFile, 'a') as file: 1123 | 1124 | for manual in service_scans_profiles[service_scan]['manual']: 1125 | if 'description' in manual: 1126 | if not heading: 1127 | file.writelines(e('# [*] {service} on {protocol}/{port}\n\n')) 1128 | heading = True 1129 | description = manual['description'] 1130 | file.writelines(e('#\t[-] {description}\n\n')) 1131 | if 'commands' in manual: 1132 | if not heading: 1133 | file.writelines(e('# [*] {service} on {protocol}/{port}\n\n')) 1134 | heading = True 1135 | for manual_command in manual['commands']: 1136 | manual_command = e(manual_command) 1137 | file.writelines(e('{manual_command}\n\n')) 1138 | if heading: 1139 | file.writelines('\n') 1140 | 1141 | if 'scan' in service_scans_profiles[service_scan]: 1142 | for scan in service_scans_profiles[service_scan]['scan']: 1143 | 1144 | if 'name' in scan: 1145 | name = scan['name'] 1146 | if 'command' in scan: 1147 | tag = e('{protocol}/{port}/{name}') 1148 | command = scan['command'] 1149 | 1150 | if 'ports' in scan: 1151 | port_match = False 1152 | 1153 | if protocol == 'tcp': 1154 | if 'tcp' in scan['ports']: 1155 | for tcp_port in scan['ports']['tcp']: 1156 | if port == tcp_port: 1157 | port_match = True 1158 | break 1159 | elif protocol == 'udp': 1160 | if 'udp' in scan['ports']: 1161 | for udp_port in scan['ports']['udp']: 1162 | if port == udp_port: 1163 | port_match = True 1164 | break 1165 | 1166 | if port_match == False: 1167 | warn( 1168 | Fore.YELLOW + '[' + Style.BRIGHT + tag + Style.NORMAL + 1169 | '] Scan cannot be run against {protocol} port {port}. ' 1170 | 'Skipping.' + Fore.RESET) 1171 | continue 1172 | 1173 | if 'run_once' in scan and scan['run_once'] == True: 1174 | scan_tuple = (name,) 1175 | if scan_tuple in target.scans: 1176 | warn( 1177 | Fore.YELLOW + '[' + Style.BRIGHT + tag + ' on ' + address + 1178 | Style.NORMAL + '] Scan should only be run once and it appears ' 1179 | 'to have already been queued. Skipping.' + 1180 | Fore.RESET) 1181 | continue 1182 | else: 1183 | target.scans.append(scan_tuple) 1184 | else: 1185 | scan_tuple = (protocol, port, service, name) 1186 | if scan_tuple in target.scans: 1187 | warn( 1188 | Fore.YELLOW + '[' + Style.BRIGHT + tag + ' on ' + address + 1189 | Style.NORMAL + '] Scan appears to have already been queued, ' 1190 | 'but it is not marked as run_once in ' 1191 | 'service-scans-profiles.toml. ' 1192 | 'Possible duplicate tag? Skipping.' + Fore.RESET) 1193 | continue 1194 | else: 1195 | target.scans.append(scan_tuple) 1196 | 1197 | patterns = [] 1198 | if 'pattern' in scan: 1199 | patterns = scan['pattern'] 1200 | 1201 | pending.add(asyncio.ensure_future( 1202 | run_cmd(semaphore, e(command), target, global_patterns, 1203 | tag=tag, patterns=patterns))) 1204 | 1205 | return target_services, matched_patterns 1206 | 1207 | 1208 | ##################################################################################################################### 1209 | def scan_live_hosts(target, concurrent_scans, live_host_scan_profiles, live_host_scan_profile, global_patterns, 1210 | nmapextra): 1211 | start_time = time.time() 1212 | info('Scanning target {byellow}{target.address}{rst} for live hosts') 1213 | 1214 | livehostsdir = os.path.join(TargetsDir, 'scans', 'live-hosts') 1215 | target.scansdir = livehostsdir 1216 | 1217 | reportsdir = os.path.join(TargetsDir, 'reports') 1218 | target.reportsdir = reportsdir 1219 | 1220 | Path(livehostsdir).mkdir(parents=True, exist_ok=True) 1221 | Path(reportsdir).mkdir(parents=True, exist_ok=True) 1222 | 1223 | # Use a lock when writing to specific files that may be written to by other asynchronous functions. 1224 | target.lock = asyncio.Lock() 1225 | 1226 | # Get event loop for current process. 1227 | loop = asyncio.get_event_loop() 1228 | 1229 | # Create a semaphore to limit number of concurrent scans. 1230 | semaphore = asyncio.Semaphore(concurrent_scans) 1231 | 1232 | try: 1233 | results = loop.run_until_complete(asyncio.gather(ping_and_scan(loop, semaphore, target, 1234 | live_host_scan_profiles, 1235 | live_host_scan_profile, 1236 | global_patterns, nmapextra))) 1237 | elapsed_time = calculate_elapsed_time(start_time) 1238 | info('Finished scanning target {byellow}{target.address}{rst} in {elapsed_time}') 1239 | return results 1240 | 1241 | except KeyboardInterrupt: 1242 | sys.exit(1) 1243 | 1244 | 1245 | ##################################################################################################################### 1246 | def scan_host(target, concurrent_scans, port_scan_profiles, port_scan_profile, service_scans_profiles, 1247 | global_patterns, nmapextra): 1248 | start_time = time.time() 1249 | info('Scanning target {byellow}{target.address}{rst}') 1250 | 1251 | scandir = os.path.join(TargetsDir, 'scans') 1252 | target.scansdir = scandir 1253 | 1254 | reportsdir = os.path.join(TargetsDir, 'reports') 1255 | target.reportsdir = reportsdir 1256 | 1257 | tcpportsdir = os.path.join(scandir, 'ports', 'tcp') 1258 | target.tcpportsdir = tcpportsdir 1259 | 1260 | fulltcpportsdir = os.path.join(scandir, 'ports', 'tcp', 'full') 1261 | target.fulltcpportsdir = fulltcpportsdir 1262 | 1263 | toptcpportsdir = os.path.join(scandir, 'ports', 'tcp', 'top') 1264 | target.toptcpportsdir = toptcpportsdir 1265 | 1266 | udpportsdir = os.path.join(scandir, 'ports', 'udp') 1267 | target.udpportsdir = udpportsdir 1268 | 1269 | fulludpportsdir = os.path.join(scandir, 'ports', 'udp', 'full') 1270 | target.fulludpportsdir = fulludpportsdir 1271 | 1272 | topudpportsdir = os.path.join(scandir, 'ports', 'udp', 'top') 1273 | target.topudpportsdir = topudpportsdir 1274 | 1275 | servicesdir = os.path.join(scandir, 'services') 1276 | target.servicesdir = servicesdir 1277 | 1278 | screenshotsdir = os.path.join(TargetsDir, 'screenshots') 1279 | target.screenshotsdir = screenshotsdir 1280 | 1281 | tcpservicesdir = os.path.join(servicesdir, 'nmap', 'tcp') 1282 | target.tcpservicesdir = tcpservicesdir 1283 | 1284 | udpservicesdir = os.path.join(servicesdir, 'nmap', 'udp') 1285 | target.udpservicesdir = udpservicesdir 1286 | 1287 | niktodir = os.path.join(servicesdir, 'nikto') 1288 | target.niktodir = niktodir 1289 | 1290 | dirscandir = os.path.join(servicesdir, 'dirscan') 1291 | target.dirscandir = dirscandir 1292 | 1293 | crackingdir = os.path.join(servicesdir, 'cracking') 1294 | target.crackingdir = crackingdir 1295 | 1296 | webdir = os.path.join(servicesdir, 'web') 1297 | target.webdir = webdir 1298 | 1299 | Path(scandir).mkdir(parents=True, exist_ok=True) 1300 | Path(reportsdir).mkdir(parents=True, exist_ok=True) 1301 | Path(tcpportsdir).mkdir(parents=True, exist_ok=True) 1302 | Path(fulltcpportsdir).mkdir(parents=True, exist_ok=True) 1303 | Path(toptcpportsdir).mkdir(parents=True, exist_ok=True) 1304 | Path(udpportsdir).mkdir(parents=True, exist_ok=True) 1305 | Path(fulludpportsdir).mkdir(parents=True, exist_ok=True) 1306 | Path(topudpportsdir).mkdir(parents=True, exist_ok=True) 1307 | Path(servicesdir).mkdir(parents=True, exist_ok=True) 1308 | Path(screenshotsdir).mkdir(parents=True, exist_ok=True) 1309 | Path(tcpservicesdir).mkdir(parents=True, exist_ok=True) 1310 | Path(udpservicesdir).mkdir(parents=True, exist_ok=True) 1311 | Path(niktodir).mkdir(parents=True, exist_ok=True) 1312 | Path(dirscandir).mkdir(parents=True, exist_ok=True) 1313 | Path(crackingdir).mkdir(parents=True, exist_ok=True) 1314 | Path(webdir).mkdir(parents=True, exist_ok=True) 1315 | 1316 | # Use a lock when writing to specific files that may be written to by other asynchronous functions. 1317 | target.lock = asyncio.Lock() 1318 | 1319 | # Get event loop for current process. 1320 | loop = asyncio.get_event_loop() 1321 | 1322 | # Create a semaphore to limit number of concurrent scans. 1323 | semaphore = asyncio.Semaphore(concurrent_scans) 1324 | 1325 | try: 1326 | results = loop.run_until_complete(asyncio.gather(scan_services(loop, semaphore, target, 1327 | port_scan_profiles, port_scan_profile, 1328 | service_scans_profiles, 1329 | global_patterns, nmapextra))) 1330 | elapsed_time = calculate_elapsed_time(start_time) 1331 | info('Finished scanning target {byellow}{target.address}{rst} in {elapsed_time}') 1332 | return results 1333 | 1334 | except KeyboardInterrupt: 1335 | sys.exit(1) 1336 | 1337 | 1338 | ##################################################################################################################### 1339 | class Target: 1340 | def __init__(self, address): 1341 | self.address = address 1342 | self.addressname = address.replace('/', '_') 1343 | self.screenshotsdir = '' 1344 | self.reportsdir = '' 1345 | self.tcpservicesdir = '' 1346 | self.udpservicesdir = '' 1347 | self.niktodir = '' 1348 | self.dirscandir = '' 1349 | self.crackingdir = '' 1350 | self.webdir = '' 1351 | self.speed = speed 1352 | self.scansdir = '' 1353 | self.tcpportsdir = '' 1354 | self.fulltcpportsdir = '' 1355 | self.toptcpportsdir = '' 1356 | self.udpportsdir = '' 1357 | self.fulludpportsdir = '' 1358 | self.topudpportsdir = '' 1359 | self.servicesdir = '' 1360 | self.scans = [] 1361 | self.lock = None 1362 | self.running_tasks = [] 1363 | 1364 | 1365 | ##################################################################################################################### 1366 | def isroot(): 1367 | if os.geteuid() != 0: 1368 | error("You need root permissions (nmap SYN scan, nmap UDP scan, etc.).") 1369 | return False 1370 | return True 1371 | 1372 | 1373 | ##################################################################################################################### 1374 | def createProjectDirStructure(projName, workingDir): 1375 | global ProjectDir, CommandsDir, DatabaseDir, LogsDir, ReportDir, TargetsDir, LogsFile 1376 | global DatabaseFile, FinalReportMDFile, FinalReportHTMLFile, CommandsFile, ManualCommandsFile 1377 | 1378 | ProjectDir = os.path.join(workingDir, projName) 1379 | CommandsDir = os.path.join(ProjectDir, 'commands', CurrentDateTime) 1380 | DatabaseDir = os.path.join(ProjectDir, 'db', CurrentDateTime) 1381 | LogsDir = os.path.join(ProjectDir, 'logs', CurrentDateTime) 1382 | ReportDir = os.path.join(ProjectDir, 'report', CurrentDateTime) 1383 | TargetsDir = os.path.join(ProjectDir, 'targets', CurrentDateTime) 1384 | 1385 | LogsFile = os.path.join(LogsDir, "logs.txt") 1386 | DatabaseFile = os.path.join(DatabaseDir, "database.db") 1387 | FinalReportMDFile = os.path.join(ReportDir, "final-report.md") 1388 | FinalReportHTMLFile = FinalReportMDFile.replace('.md', '.html') 1389 | CommandsFile = os.path.join(CommandsDir, "commands.log") 1390 | ManualCommandsFile = os.path.join(CommandsDir, "manual_commands.sh") 1391 | 1392 | Path(CommandsDir).mkdir(parents=True, exist_ok=True) 1393 | Path(DatabaseDir).mkdir(parents=True, exist_ok=True) 1394 | Path(LogsDir).mkdir(parents=True, exist_ok=True) 1395 | Path(ReportDir).mkdir(parents=True, exist_ok=True) 1396 | Path(TargetsDir).mkdir(parents=True, exist_ok=True) 1397 | 1398 | with open(ManualCommandsFile, 'w') as file: 1399 | file.writelines('#!/bin/bash\n\n') 1400 | 1401 | info('Creating project directory structure \'{byellow}{ProjectDir}{rst}\'.') 1402 | 1403 | 1404 | ##################################################################################################################### 1405 | def dbconnect(): 1406 | global DbConnection 1407 | 1408 | try: 1409 | DbConnection = sqlite3.connect(DatabaseFile) 1410 | dbcreateTargetsTbl() 1411 | dbcreateServicesTbl() 1412 | 1413 | info('Database connection established. Database file \'{byellow}{DatabaseFile}{rst}\'.') 1414 | except Exception as e: 1415 | error("An error occured during sqlite3 database connection: {0}.".format(str(e))) 1416 | if DbConnection: 1417 | DbConnection.close() 1418 | exit(1) 1419 | 1420 | 1421 | def dbdisconnect(): 1422 | global DbConnection 1423 | 1424 | try: 1425 | if DbConnection: 1426 | DbConnection.close() 1427 | info('Database connection terminated.') 1428 | except Exception as e: 1429 | error("An error occured during sqlite3 database connection: {0}.".format(str(e))) 1430 | exit(1) 1431 | 1432 | 1433 | def dbaddTarget(liveHost): 1434 | global DbConnection 1435 | 1436 | try: 1437 | if DbConnection: 1438 | c = DbConnection.cursor() 1439 | c.execute('''REPLACE INTO targets(Target) 1440 | VALUES(?);''', [liveHost]) 1441 | DbConnection.commit() 1442 | id = c.lastrowid 1443 | c.close() 1444 | return id 1445 | except Exception as e: 1446 | error("An error occured during database data insertion: {0}.".format(str(e))) 1447 | exit(1) 1448 | 1449 | 1450 | def dbaddService(host, protocol, port, service, version): 1451 | global DbConnection 1452 | 1453 | try: 1454 | if DbConnection: 1455 | c = DbConnection.cursor() 1456 | c.execute('''REPLACE INTO services(Target,Protocol,Port,Service,Version) 1457 | VALUES(?,?,?,?,?);''', (host, protocol, port, service, version)) 1458 | DbConnection.commit() 1459 | id = c.lastrowid 1460 | c.close() 1461 | return id 1462 | except Exception as e: 1463 | error("An error occured during database data insertion: {0}.".format(str(e))) 1464 | exit(1) 1465 | 1466 | 1467 | def dbgetTargets(): 1468 | global DbConnection 1469 | 1470 | try: 1471 | if DbConnection: 1472 | c = DbConnection.cursor() 1473 | c.execute('''SELECT Target from targets;''') 1474 | DbConnection.commit() 1475 | rows = c.fetchall() 1476 | c.close() 1477 | return rows 1478 | except Exception as e: 1479 | error("An error occured during database data selection: {0}.".format(str(e))) 1480 | exit(1) 1481 | 1482 | 1483 | def dbcreateTargetsTbl(): 1484 | global DbConnection 1485 | 1486 | try: 1487 | if DbConnection: 1488 | DbConnection.execute('''CREATE TABLE targets 1489 | (ID INTEGER PRIMARY KEY AUTOINCREMENT, 1490 | Target VARCHAR(50) UNIQUE NOT NULL);''') 1491 | except Exception as e: 1492 | error("An error occured during database table creation: {0}.".format(str(e))) 1493 | exit(1) 1494 | 1495 | 1496 | def dbcreateServicesTbl(): 1497 | global DbConnection 1498 | 1499 | try: 1500 | if DbConnection: 1501 | DbConnection.execute('''CREATE TABLE services 1502 | (ID INTEGER PRIMARY KEY AUTOINCREMENT, 1503 | Target VARCHAR(50) NOT NULL, 1504 | Protocol VARCHAR(50) NOT NULL, 1505 | Port VARCHAR(50) NOT NULL, 1506 | Service TEXT NOT NULL, 1507 | Version TEXT NOT NULL);''') 1508 | except Exception as e: 1509 | error("An error occured during database table creation: {0}.".format(str(e))) 1510 | exit(1) 1511 | 1512 | 1513 | ##################################################################################################################### 1514 | def detect_live_hosts(targetRange, concurrent_scans, concurrent_targets, live_host_scan_profiles, 1515 | live_host_scan_profile, global_patterns, nmapextra): 1516 | with ProcessPoolExecutor(max_workers=concurrent_targets) as executor: 1517 | start_time = time.time() 1518 | futures = [] 1519 | 1520 | target = Target(targetRange) 1521 | 1522 | future = executor.submit(scan_live_hosts, target, concurrent_scans, live_host_scan_profiles, 1523 | live_host_scan_profile, global_patterns, nmapextra) 1524 | 1525 | live_hosts = [] 1526 | try: 1527 | if future.result(): 1528 | results_arr = future.result() 1529 | live_hosts = results_arr[0][0] 1530 | matched_patterns = results_arr[0][1] 1531 | except KeyboardInterrupt: 1532 | future.cancel() 1533 | executor.shutdown(wait=False) 1534 | sys.exit(1) 1535 | 1536 | elapsed_time = calculate_elapsed_time(start_time) 1537 | info('{bgreen}Live Hosts scanning completed in {elapsed_time}!{rst}') 1538 | 1539 | return live_hosts, matched_patterns 1540 | 1541 | 1542 | ##################################################################################################################### 1543 | def findProfile(profileName, configList): 1544 | # check if requested profile scan exists and is valid 1545 | 1546 | found_scan_profile = False 1547 | 1548 | for profile in configList: 1549 | if profile == profileName: 1550 | found_scan_profile = True 1551 | 1552 | for scan in configList[profile]: 1553 | 1554 | if 'service-detection' not in configList[profile][scan]: 1555 | error( 1556 | 'The {profile}.{scan} scan does not have a defined service-detection section. ' 1557 | 'Every scan must at least have a service-detection section defined with a command and a ' 1558 | 'corresponding pattern that extracts the protocol (TCP/UDP), port, service and version ' 1559 | 'from the result.') 1560 | errors = True 1561 | else: 1562 | if 'command' not in configList[profile][scan]['service-detection']: 1563 | error( 1564 | 'The {profile}.{scan}.service-detection section does not have a command defined. ' 1565 | 'Every service-detection section must have a command and a corresponding pattern ' 1566 | 'that extracts the protocol (TCP/UDP), port, service and version from the results.') 1567 | errors = True 1568 | else: 1569 | if '{ports}' in configList[profile][scan]['service-detection']['command'] \ 1570 | and 'port-scan' not in \ 1571 | configList[profile][scan]: 1572 | error( 1573 | 'The {profile}.{scan}.service-detection command appears to reference a port list ' 1574 | 'but there is no port-scan section defined in {profile}.{scan}. Define a port-scan ' 1575 | 'section with a command and corresponding pattern that extracts port numbers from the ' 1576 | 'result, or replace the reference with a static list of ports.') 1577 | errors = True 1578 | 1579 | if 'pattern' not in configList[profile][scan]['service-detection']: 1580 | error( 1581 | 'The {profile}.{scan}.service-detection section does not have a pattern defined. ' 1582 | 'Every service-detection section must have a command and a corresponding pattern ' 1583 | 'that extracts the protocol (TCP/UDP), port, service and version from the results.') 1584 | errors = True 1585 | else: 1586 | if not all(x in configList[profile][scan]['service-detection']['pattern'] for x in 1587 | ['(?P', '(?P', '(?P']): 1588 | error( 1589 | 'The {profile}.{scan}.service-detection pattern does not contain one or more of ' 1590 | 'the following matching groups: port, protocol, service. Ensure that all three of ' 1591 | 'these matching groups are defined and capture the relevant data, e.g. (?P\d+)') 1592 | errors = True 1593 | 1594 | if 'port-scan' in configList[profile][scan]: 1595 | if 'command' not in configList[profile][scan]['port-scan']: 1596 | error( 1597 | 'The {profile}.{scan}.port-scan section does not have a command defined. ' 1598 | 'Every port-scan section must have a command and a corresponding pattern that ' 1599 | 'extracts the port from the results.') 1600 | errors = True 1601 | 1602 | if 'pattern' not in configList[profile][scan]['port-scan']: 1603 | error( 1604 | 'The {profile}.{scan}.port-scan section does not have a pattern defined. ' 1605 | 'Every port-scan section must have a command and a corresponding pattern that ' 1606 | 'extracts the port from the results.') 1607 | errors = True 1608 | else: 1609 | if '(?P' not in configList[profile][scan]['port-scan']['pattern']: 1610 | error( 1611 | 'The {profile}.{scan}.port-scan pattern does not contain a port matching group. ' 1612 | 'Ensure that the port matching group is defined and captures the relevant ' 1613 | 'data, e.g. (?P\d+)') 1614 | errors = True 1615 | 1616 | if 'live-host-detection' in configList[profile][scan]: 1617 | if 'command' not in configList[profile][scan]['live-host-detection']: 1618 | error( 1619 | 'The {profile}.{scan}.live-host-detection section does not have a command defined. ' 1620 | 'Every live-host-detection section must have a command and a corresponding pattern ' 1621 | 'that extracts the live host from the results.') 1622 | errors = True 1623 | 1624 | if 'pattern' not in configList[profile][scan]['live-host-detection']: 1625 | error( 1626 | 'The {profile}.{scan}.plive-host-detection section does not have a pattern defined. ' 1627 | 'Every live-host-detection section must have a command and a corresponding pattern ' 1628 | 'that extracts the live host from the results.') 1629 | errors = True 1630 | else: 1631 | if '(?P' not in configList[profile][scan]['live-host-detection']['pattern']: 1632 | error( 1633 | 'The {profile}.{scan}.live-host-detection pattern does not contain a port ' 1634 | 'matching group. Ensure that the port matching group is defined and captures ' 1635 | 'the relevant data, e.g. (?P\d+)') 1636 | errors = True 1637 | 1638 | break 1639 | 1640 | return found_scan_profile 1641 | 1642 | 1643 | ##################################################################################################################### 1644 | def findLiveHostProfile(profileName, configList): 1645 | # check if requested profile scan exists and is valid 1646 | 1647 | found_scan_profile = False 1648 | 1649 | for profile in configList: 1650 | if profile == profileName: 1651 | found_scan_profile = True 1652 | 1653 | for scan in configList[profile]: 1654 | 1655 | if 'live-host-detection' not in configList[profile][scan]: 1656 | error( 1657 | 'The {profile}.{scan} scan does not have a defined live-host-detection section. ' 1658 | 'Every scan must at least have a live-host-detection section defined with a command ' 1659 | 'and a corresponding pattern that extracts the protocol (TCP/UDP), port, service and ' 1660 | 'version from the result.') 1661 | errors = True 1662 | else: 1663 | if 'command' not in configList[profile][scan]['live-host-detection']: 1664 | error( 1665 | 'The {profile}.{scan}.live-host-detection section does not have a command defined. ' 1666 | 'Every live-host-detection section must have a command and a corresponding pattern ' 1667 | 'that extracts the protocol (TCP/UDP), port, service and version from the results.') 1668 | errors = True 1669 | else: 1670 | if '{ports}' in configList[profile][scan]['live-host-detection']['command'] \ 1671 | and 'port-scan' not in configList[profile][scan]: 1672 | error( 1673 | 'The {profile}.{scan}.live-host-detection command appears to reference a ' 1674 | 'port list but there is no port-scan section defined in {profile}.{scan}. ' 1675 | 'Define a port-scan section with a command and corresponding pattern that ' 1676 | 'extracts port numbers from the result, or replace the reference with a ' 1677 | 'static list of ports.') 1678 | errors = True 1679 | 1680 | if 'pattern' not in configList[profile][scan]['live-host-detection']: 1681 | error( 1682 | 'The {profile}.{scan}.live-host-detection section does not have a pattern defined. ' 1683 | 'Every live-host-detection section must have a command and a corresponding pattern ' 1684 | 'that extracts the protocol (TCP/UDP), port, service and version from the results.') 1685 | errors = True 1686 | else: 1687 | if not all(x in configList[profile][scan]['live-host-detection']['pattern'] for x in 1688 | ['(?P
']): 1689 | error( 1690 | 'The {profile}.{scan}.live-host-detection pattern does not contain one or ' 1691 | 'more of the following matching groups: address. Ensure that all three of ' 1692 | 'these matching groups are defined and capture the relevant data, e.g. (?P\d+)') 1693 | errors = True 1694 | break 1695 | 1696 | return found_scan_profile 1697 | 1698 | 1699 | ##################################################################################################################### 1700 | def html(mdfile, htmlfile): 1701 | command = "pandoc -f markdown {0} > {1}".format(mdfile, htmlfile) 1702 | info('Generating HTML report' + (' with {bblue}{command}{rst}' if verbose >= 2 else '')) 1703 | 1704 | with open(CommandsFile, 'a') as file: 1705 | file.writelines(f"{command}\n\n") 1706 | 1707 | try: 1708 | subprocess.run(command, shell=True) 1709 | 1710 | except Exception as e: 1711 | error("An error occured during HTML report generation: {0}.".format(e)) 1712 | 1713 | 1714 | ##################################################################################################################### 1715 | 1716 | def query_yes_no(question, default="no"): 1717 | valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} 1718 | if default is None: 1719 | prompt = " [y/n] " 1720 | elif default == "yes": 1721 | prompt = " [Y/n] " 1722 | elif default == "no": 1723 | prompt = " [y/N] " 1724 | else: 1725 | raise ValueError("invalid default answer: '%s'" % default) 1726 | 1727 | while True: 1728 | sys.stdout.write(question + prompt) 1729 | choice = input().lower() 1730 | if default is not None and choice == '': 1731 | return valid[default] 1732 | elif choice in valid: 1733 | return valid[choice] 1734 | else: 1735 | sys.stdout.write("Please respond with 'yes' or 'no' " 1736 | "(or 'y' or 'n').\n") 1737 | 1738 | 1739 | ##################################################################################################################### 1740 | 1741 | def checktoolsexistence(): 1742 | toolsmissing = False 1743 | for tool in tools: 1744 | exists = shutil.which(tool) 1745 | if exists is None: 1746 | toolsmissing = True 1747 | error('The {tool} tool is missing. Please install it (e.g. \'sudo apt install {tool}\').') 1748 | 1749 | if toolsmissing: 1750 | question('Some tools are missing from your system. ') 1751 | if not query_yes_no('Would you like to continue?'): 1752 | sys.exit(0) 1753 | 1754 | 1755 | ##################################################################################################################### 1756 | 1757 | def analyzetargets(raw_targets, concurrent_scans, concurrent_targets, live_host_scan_profiles, live_host_scan_profile, 1758 | global_patterns, nmapextra): 1759 | targets = [] 1760 | patterns = [] 1761 | err = False 1762 | 1763 | for t in raw_targets: 1764 | try: 1765 | # single ip address e.g. 192.168.1.10 1766 | ip = str(ipaddress.ip_address(t)) 1767 | 1768 | if ip not in targets: 1769 | targets.append(ip) 1770 | except ValueError: 1771 | 1772 | try: 1773 | # ip range(CIDR) e.g. 192.168.1.0/24 1774 | target_range = ipaddress.ip_network(t, strict=False) 1775 | dlh = detect_live_hosts(t, concurrent_scans, concurrent_targets, live_host_scan_profiles, 1776 | live_host_scan_profile, global_patterns, nmapextra) 1777 | live_hosts = dlh[0] 1778 | matchedpatterns = dlh[1] 1779 | patterns += matchedpatterns 1780 | 1781 | if live_hosts: 1782 | for ip in live_hosts: 1783 | ip = str(ip) 1784 | if ip not in targets: 1785 | targets.append(ip) 1786 | except ValueError: 1787 | 1788 | try: 1789 | # domain e.g. example.com 1790 | ip = socket.gethostbyname(t) 1791 | 1792 | if t not in targets: 1793 | targets.append(t) 1794 | 1795 | except socket.gaierror: 1796 | error(t + ' does not appear to be a valid IP address, IP range, or resolvable hostname.') 1797 | err = True 1798 | 1799 | return targets, patterns, err 1800 | 1801 | 1802 | ##################################################################################################################### 1803 | 1804 | def parseargs(psps: [], psp_config_file: string, lhsps: [], lhsp_config_file: string): 1805 | ProgramArgs = namedtuple('ProgramArgs', 'concurrent_scans concurrent_targets exclude errors heartbeat ' 1806 | 'livehost_profile nmap_args portscan_profile project_name ' 1807 | 'raw_targets speed target_file verbose working_dir') 1808 | 1809 | err = False 1810 | 1811 | parser = argparse.ArgumentParser() 1812 | 1813 | parser.add_argument('targets', action='store', 1814 | help='IP addresses (e.g. 10.0.0.1), CIDR notation (e.g. 10.0.0.1/24), or resolvable hostnames ' 1815 | '(e.g. example.com) to scan.', 1816 | nargs="*") 1817 | 1818 | parser.add_argument('-ts', '--targets', action='store', type=str, default='', dest='target_file', 1819 | help='Read targets from file.', required=False) 1820 | 1821 | parser.add_argument('-p', '--project-name', action='store', type=str, 1822 | help='project name', required=True) 1823 | 1824 | parser.add_argument('-w', '--working-dir', action='store', type=str, 1825 | help='working directory', required=True) 1826 | 1827 | parser.add_argument('--exclude', metavar='', 1828 | help='exclude hosts/networks', 1829 | required=False) 1830 | 1831 | parser.add_argument('-s', '--speed', 1832 | help='0-5, set timing template (higher is faster) (default: 4)', 1833 | required=False, default=4) 1834 | 1835 | parser.add_argument('-ct', '--concurrent-targets', action='store', metavar='', type=int, default=5, 1836 | help='The maximum number of target hosts to scan concurrently. Default: %(default)s') 1837 | 1838 | parser.add_argument('-cs', '--concurrent-scans', action='store', metavar='', type=int, default=10, 1839 | help='The maximum number of scans to perform per target host. Default: %(default)s') 1840 | 1841 | parser.add_argument('--profile', action='store', default='default', dest='profile_name', 1842 | help='The port scanning profile to use (defined in port-scan-profiles.toml). ' 1843 | 'Default: %(default)s') 1844 | 1845 | parser.add_argument('--livehost-profile', action='store', default='default', dest='livehost_profile_name', 1846 | help='The live host scanning profile to use (defined in live-host-scan-profiles.toml). ' 1847 | 'Default: %(default)s') 1848 | 1849 | parser.add_argument('--heartbeat', action='store', type=int, default=60, 1850 | help='Specifies the heartbeat interval (in seconds) for task status messages. ' 1851 | 'Default: %(default)s') 1852 | 1853 | parser.add_argument('-v', '--verbose', action='count', default=0, 1854 | help='Enable verbose output. Repeat for more verbosity (-v, -vv, -vvv).') 1855 | 1856 | parser.error = lambda s: fail(s[0].upper() + s[1:]) 1857 | args = parser.parse_args() 1858 | 1859 | if args.concurrent_targets <= 0: 1860 | error('Argument -ct/--concurrent-targets: must be at least 1.') 1861 | err = True 1862 | 1863 | if args.concurrent_scans <= 0: 1864 | error('Argument -cs/--concurrent-scans: must be at least 1.') 1865 | err = True 1866 | 1867 | psp = args.profile_name 1868 | found_scan_profile = findProfile(psp, psps) 1869 | 1870 | if not found_scan_profile: 1871 | error( 1872 | 'Argument --profile: must reference a port scan profile defined in {psp_config_file}. ' 1873 | 'No such profile found: {psp}') 1874 | err = True 1875 | 1876 | lhsp = args.livehost_profile_name 1877 | found_live_host_scan_profile = findLiveHostProfile(lhsp, lhsps) 1878 | 1879 | if not found_live_host_scan_profile: 1880 | error( 1881 | 'Argument --livehost-profile: must reference a live host scan profile defined ' 1882 | 'in {lhsp_config_file}. No such profile found: {lhsp}') 1883 | err = True 1884 | 1885 | nmap_args = '' 1886 | if args.exclude: 1887 | nmap_args = "--exclude {}".format(args.exclude) 1888 | 1889 | raw_targets = args.targets 1890 | 1891 | if len(raw_targets) == 0: 1892 | # error('You must specify at least one target to scan!') 1893 | # err = True 1894 | if len(args.target_file) > 0: 1895 | if not os.path.isfile(args.target_file): 1896 | error('The target file {args.target_file} was not found.') 1897 | sys.exit(1) 1898 | 1899 | try: 1900 | with open(args.target_file, 'r') as f: 1901 | lines = f.read() 1902 | for line in lines.splitlines(): 1903 | line = line.strip() 1904 | if line.startswith('#') or len(line) == 0: continue 1905 | if line not in raw_targets: 1906 | raw_targets.append(line) 1907 | 1908 | except OSError: 1909 | error('The target file {args.target_file} could not be read.') 1910 | sys.exit(1) 1911 | 1912 | else: 1913 | error('You must specify at least one target to scan!') 1914 | err = True 1915 | 1916 | myargs = ProgramArgs(concurrent_scans=args.concurrent_scans, concurrent_targets=args.concurrent_targets, 1917 | exclude=args.exclude, errors=err, heartbeat=args.heartbeat, 1918 | livehost_profile=lhsp, nmap_args=nmap_args, 1919 | portscan_profile=psp, project_name=args.project_name, 1920 | raw_targets=raw_targets, speed=args.speed, 1921 | target_file=args.target_file, verbose=args.verbose, 1922 | working_dir=args.working_dir) 1923 | 1924 | return myargs 1925 | 1926 | 1927 | ##################################################################################################################### 1928 | 1929 | if __name__ == '__main__': 1930 | 1931 | print(message) 1932 | start_time = time.time() 1933 | 1934 | port_scan_profiles_file = 'port-scan-profiles.toml' 1935 | live_host_scan_profiles_file = 'live-host-scan-profiles.toml' 1936 | 1937 | lhsps, psps, ssps, gp, username_wordlist, password_wordlist = loadprofiles(live_host_scan_profiles_file, 1938 | port_scan_profiles_file) 1939 | 1940 | print(username_wordlist) 1941 | intelArgs = parseargs(psps, port_scan_profiles_file, lhsps, live_host_scan_profiles_file) 1942 | 1943 | if intelArgs.errors: 1944 | sys.exit(1) 1945 | 1946 | if not isroot(): 1947 | sys.exit(1) 1948 | 1949 | checktoolsexistence() 1950 | 1951 | warn('Running with root privileges.') 1952 | 1953 | createProjectDirStructure(intelArgs.project_name, intelArgs.working_dir) 1954 | 1955 | dbconnect() 1956 | 1957 | info('Concurrent targets {intelArgs.concurrent_targets}') 1958 | info('Concurrent scans {intelArgs.concurrent_scans}') 1959 | info("Excluding from scans: {0}.".format(intelArgs.exclude)) 1960 | 1961 | targs, patt, aterr = analyzetargets(intelArgs.raw_targets, intelArgs.concurrent_scans, 1962 | intelArgs.concurrent_targets, lhsps, 1963 | intelArgs.livehost_profile, gp, intelArgs.nmap_args) 1964 | 1965 | if aterr: 1966 | sys.exit(1) 1967 | 1968 | Matched_Patterns_Report = patt 1969 | 1970 | with open(FinalReportMDFile, 'w') as file: 1971 | file.write("# Final Report\n\n") 1972 | file.write("## Target/s\n\n") 1973 | for target in targs: 1974 | dbaddTarget(target) 1975 | file.write("* {0}\n".format(target)) 1976 | 1977 | file.write("\n---\n\n") 1978 | file.write("## Services\n\n") 1979 | 1980 | with ProcessPoolExecutor(max_workers=intelArgs.concurrent_targets) as executor: 1981 | st = time.time() 1982 | futures = [] 1983 | 1984 | for address in targs: 1985 | target = Target(address) 1986 | futures.append(executor.submit(scan_host, target, intelArgs.concurrent_scans, 1987 | psps, intelArgs.portscan_profile, ssps, gp, 1988 | intelArgs.nmap_args)) 1989 | 1990 | try: 1991 | with open(FinalReportMDFile, 'a') as file: 1992 | tcpports = [] 1993 | udpports = [] 1994 | for future in as_completed(futures): 1995 | if future.result(): 1996 | 1997 | data = future.result()[0][0] 1998 | matched_patterns = future.result()[0][1] 1999 | Matched_Patterns_Report += matched_patterns 2000 | 2001 | if data: 2002 | 2003 | for host, vals in data.items(): 2004 | file.write("### Target {0}\n\n".format(host)) 2005 | 2006 | for val in vals: 2007 | file.write("* **{0}/{1}** *{2}*\n".format(val[0], val[1], val[2])) 2008 | file.write(" * {0}\n".format(val[3])) 2009 | dbaddService(host, val[0], val[1], val[2], val[3]) 2010 | 2011 | if val[0] == 'tcp': 2012 | if val[1] not in tcpports: 2013 | tcpports.append(val[1]) 2014 | else: 2015 | if val[1] not in udpports: 2016 | udpports.append(val[1]) 2017 | 2018 | file.write("\n---\n\n") 2019 | 2020 | # file.write("\n---\n\n") 2021 | uniqueTcpPorts = sorted(set(tcpports)) 2022 | uniqueUdpPorts = sorted(set(udpports)) 2023 | 2024 | tcpPortscommalist = ','.join(str(s) for s in uniqueTcpPorts) 2025 | udpPortscommalist = ','.join(str(s) for s in uniqueUdpPorts) 2026 | 2027 | file.write("## Hosts & Ports\n") 2028 | file.write("\n* **{0}**\n".format(','.join(targs))) 2029 | file.write("\n* TCP: **{0}**\n".format(tcpPortscommalist)) 2030 | file.write("\n* UDP: **{0}**\n".format(udpPortscommalist)) 2031 | file.write("\n---\n\n") 2032 | 2033 | except KeyboardInterrupt: 2034 | for future in futures: 2035 | future.cancel() 2036 | executor.shutdown(wait=False) 2037 | sys.exit(1) 2038 | 2039 | elapsed_time = calculate_elapsed_time(st) 2040 | info('{bgreen}Finished scanning all targets in {elapsed_time}!{rst}') 2041 | 2042 | with open(FinalReportMDFile, 'a') as file: 2043 | file.write("## Extra Information\n") 2044 | for match in Matched_Patterns_Report: 2045 | file.write("\n* {0}".format(match)) 2046 | file.write("\n\n---\n\n") 2047 | 2048 | html(FinalReportMDFile, FinalReportHTMLFile) 2049 | 2050 | dbdisconnect() 2051 | elapsed_time = calculate_elapsed_time(st) 2052 | info('{bgreen}IntelSpy completed in {elapsed_time}!{rst}') 2053 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maldevel/intelspy/8a97755ff0245e65386535ef42e64b1ad5d76887/logo.png -------------------------------------------------------------------------------- /profiles/global-patterns.toml: -------------------------------------------------------------------------------- 1 | # Patterns defined in this file will be checked against every line of output (e.g. port scans and service scans) 2 | 3 | [[pattern]] 4 | description = 'Nmap script found a potential vulnerability. ({match})' 5 | pattern = 'State: (?:(?:LIKELY\_?)?VULNERABLE)' 6 | 7 | [[pattern]] 8 | pattern = '(?i)unauthorized' 9 | 10 | [[pattern]] 11 | description = 'Hardware Address detected. ({match})' 12 | pattern = 'MAC Address: .*' 13 | 14 | [[pattern]] 15 | description = 'Operating System. ({match})' 16 | pattern = 'OS details: .*' 17 | 18 | [[pattern]] 19 | description = 'Operating System guess. ({match})' 20 | pattern = 'Aggressive OS guesses: .*' 21 | 22 | -------------------------------------------------------------------------------- /profiles/live-host-scan-profiles.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | 3 | [default.nmap-icmp-echo] 4 | 5 | [default.nmap-icmp-echo.live-host-detection] 6 | command = 'nmap {nmap_extra} -vv -n -sn -PE -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_icmp_echo" {address}' 7 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 8 | 9 | [default.nmap-tcp-ack] 10 | 11 | [default.nmap-tcp-ack.live-host-detection] 12 | command = 'nmap {nmap_extra} -vv -n -sn -PA21,22,23,25,53,80,88,110,111,135,139,143,199,443,445,465,587,993,995,1025,1433,1720,1723,3306,3389,5900,8080,8443 -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_tcp_ack" {address}' 13 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 14 | 15 | [default.nmap-tcp-syn] 16 | 17 | [default.nmap-tcp-syn.live-host-detection] 18 | command='nmap {nmap_extra} -vv -n -sn -PS21,22,23,25,53,80,88,110,111,135,139,143,199,443,445,465,587,993,995,1025,1433,1720,1723,3306,3389,5900,8080,8443 -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_tcp_syn" {address}' 19 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 20 | 21 | [default.nmap-sctp] 22 | 23 | [default.nmap-sctp.live-host-detection] 24 | command='nmap {nmap_extra} -vv -n -sn -PY132,2905 -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_sctp" {address}' 25 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 26 | 27 | [default.nmap-udp] 28 | 29 | [default.nmap-udp.live-host-detection] 30 | command='nmap {nmap_extra} -vv -n -sn -PU53,67,68,69,123,135,137,138,139,161,162,445,500,514,520,631,1434,1600,4500,49152 -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_udp" {address}' 31 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 32 | 33 | [default.nmap-protocol-ping] 34 | 35 | [default.nmap-protocol-ping.live-host-detection] 36 | command='nmap {nmap_extra} -vv -n -sn -PO -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_protocol_ping" {address}' 37 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 38 | 39 | [default.nmap-timestamp] 40 | 41 | [default.nmap-timestamp.live-host-detection] 42 | command='nmap {nmap_extra} -vv -n -sn -PP -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_timestamp" {address}' 43 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 44 | 45 | [default.nmap-netmask] 46 | 47 | [default.nmap-netmask.live-host-detection] 48 | command='nmap {nmap_extra} -vv -n -sn -PM -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_netmask" {address}' 49 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 50 | 51 | [default.nmap-top-100-tcp] 52 | 53 | [default.nmap-top-100-tcp.live-host-detection] 54 | command='nmap {nmap_extra} -vv -sS -sV -n -Pn --top-ports 100 --reason --open -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_top_100_tcp" {address}' 55 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 56 | 57 | [quick] 58 | 59 | [quick.nmap-icmp-echo] 60 | 61 | [quick.nmap-icmp-echo.live-host-detection] 62 | command = 'nmap {nmap_extra} -vv -n -sn -PE -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_icmp_echo" {address}' 63 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 64 | 65 | [quick.nmap-sctp] 66 | 67 | [quick.nmap-sctp.live-host-detection] 68 | command='nmap {nmap_extra} -vv -n -sn -PY132,2905 -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_sctp" {address}' 69 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 70 | 71 | [quick.nmap-protocol-ping] 72 | 73 | [quick.nmap-protocol-ping.live-host-detection] 74 | command='nmap {nmap_extra} -vv -n -sn -PO -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_protocol_ping" {address}' 75 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 76 | 77 | [quick.nmap-timestamp] 78 | 79 | [quick.nmap-timestamp.live-host-detection] 80 | command='nmap {nmap_extra} -vv -n -sn -PP -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_timestamp" {address}' 81 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 82 | 83 | [quick.nmap-netmask] 84 | 85 | [quick.nmap-netmask.live-host-detection] 86 | command='nmap {nmap_extra} -vv -n -sn -PM -T{nmap_speed} -oA "{scandir}/{addressname}_nmap_live_hosts_netmask" {address}' 87 | pattern = '^Nmap scan report for (?P
[\d\.]+)$' 88 | -------------------------------------------------------------------------------- /profiles/port-scan-profiles.toml: -------------------------------------------------------------------------------- 1 | [default] 2 | 3 | [default.nmap-top-1000-tcp] 4 | 5 | [default.nmap-top-1000-tcp.service-detection] 6 | command = 'nmap {nmap_extra} -sS -sV -n -Pn -vv --top-ports 1000 --open -T{nmap_speed} -oA "{toptcpportsdir}/{address}_nmap_top_1000_tcp" {address}' 7 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 8 | 9 | [default.nmap-top-1000-udp] 10 | 11 | [default.nmap-top-1000-udp.service-detection] 12 | command = 'nmap {nmap_extra} -sU -sV -n -Pn --defeat-icmp-ratelimit -vv --top-ports 1000 --open -T{nmap_speed} -oA "{topudpportsdir}/{address}_nmap_top_1000_udp" {address}' 13 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 14 | 15 | [default.nmap-full-tcp] 16 | 17 | [default.nmap-full-tcp.port-scan] 18 | command = 'nmap {nmap_extra} -sS -vv -n -Pn -p- --open -T{nmap_speed} -oA "{fulltcpportsdir}/{address}_nmap_full_tcp" {address}' 19 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 20 | 21 | [default.nmap-full-tcp.service-detection] 22 | command = 'nmap {nmap_extra} -sS -vv -A -Pn --osscan-guess --version-all -p{ports} -T{nmap_speed} -oA "{tcpservicesdir}/{address}_nmap_full_tcp_services" {address}' 23 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 24 | 25 | [default.nmap-full-udp] 26 | 27 | [default.nmap-full-udp.port-scan] 28 | command = 'nmap {nmap_extra} -sU -vv -n -Pn --defeat-icmp-ratelimit -p- --open -T{nmap_speed} -oA "{fulludpportsdir}/{address}_nmap_full_udp" {address}' 29 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 30 | 31 | [default.nmap-full-udp.service-detection] 32 | command = 'nmap {nmap_extra} -sU -vv -A -Pn --defeat-icmp-ratelimit --osscan-guess --version-all -p{ports} -T{nmap_speed} -oA "{udpservicesdir}/{address}_nmap_full_udp_services" {address}' 33 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 34 | 35 | [quick] 36 | 37 | [quick.nmap-top-100-tcp] 38 | 39 | [quick.nmap-top-100-tcp.service-detection] 40 | command = 'nmap {nmap_extra} -sS -sV --version-all -n -Pn -vv --top-ports 100 --open -T{nmap_speed} -oA "{toptcpportsdir}/{address}_nmap_top_100_tcp" {address}' 41 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 42 | 43 | [quick.nmap-top-100-udp] 44 | 45 | [quick.nmap-top-100-udp.service-detection] 46 | command = 'nmap {nmap_extra} -sU -A --version-all --defeat-icmp-ratelimit --defeat-icmp-ratelimit -n -Pn -vv --top-ports 100 --open -T{nmap_speed} -oA "{topudpportsdir}/{address}_nmap_top_100_udp" {address}' 47 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 48 | 49 | [quick.nmap-top-3000-tcp] 50 | 51 | [quick.nmap-top-3000-tcp.port-scan] 52 | command = 'nmap {nmap_extra} -sS -vv -n -Pn --top-ports 3000 --open -T{nmap_speed} -oA "{toptcpportsdir}/{address}_nmap_top_3000_tcp" {address}' 53 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 54 | 55 | [quick.nmap-top-3000-tcp.service-detection] 56 | command = 'nmap {nmap_extra} -sS -vv -A -Pn --osscan-guess --version-all -p{ports} -T{nmap_speed} -oA "{tcpservicesdir}/{address}_nmap_top_3000_tcp_services" {address}' 57 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 58 | 59 | [quick.nmap-top-3000-udp] 60 | 61 | [quick.nmap-top-3000-udp.port-scan] 62 | command = 'nmap {nmap_extra} -sU -vv -n -Pn --defeat-icmp-ratelimit --top-ports 3000 --open -T{nmap_speed} -oA "{topudpportsdir}/{address}_nmap_top_3000_udp" {address}' 63 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 64 | 65 | [quick.nmap-top-3000-udp.service-detection] 66 | command = 'nmap {nmap_extra} -sU -vv -A -Pn --defeat-icmp-ratelimit --osscan-guess --version-all -p{ports} -T{nmap_speed} -oA "{udpservicesdir}/{address}_nmap_top_3000_udp_services" {address}' 67 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 68 | 69 | [web] 70 | 71 | [web.nmap-tcp] 72 | 73 | [web.nmap-tcp.port-scan] 74 | command = 'nmap {nmap_extra} -sS -vv -n -Pn -p80,443 --open -T{nmap_speed} -oA "{fulltcpportsdir}/{address}_nmap_web_tcp" {address}' 75 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 76 | 77 | [web.nmap-tcp.service-detection] 78 | command = 'nmap {nmap_extra} -sS -vv -A -Pn --osscan-guess --version-all -p{ports} -T{nmap_speed} -oA "{tcpservicesdir}/{address}_nmap_web_tcp_services" {address}' 79 | pattern = '^(?P\d+)\/(?P(tcp|udp))(.*)open(\s*)(?P[\w\-\/\?]+)(\s*)(?P[\w\-]+)(\s*)ttl(\s*)\d+(\s*)(?P.*)$' 80 | -------------------------------------------------------------------------------- /profiles/service-scans-profiles.toml: -------------------------------------------------------------------------------- 1 | # Configurable Variables 2 | username_wordlist = '/usr/share/seclists/Usernames/top-usernames-shortlist.txt' 3 | password_wordlist = '/usr/share/seclists/Passwords/darkweb2017-top100.txt' 4 | 5 | [all-services] # Define scans here that you want to run against all services. 6 | 7 | service-names = [ 8 | '.+' 9 | ] 10 | 11 | [[all-services.scan]] 12 | name = 'sslscan' 13 | command = 'if [ "{secure}" == "True" ]; then sslscan --show-certificate --no-colour --xml={webdir}/{address}_{protocol}_{port}_sslscan.xml {address}:{port} 2>&1 | tee "{webdir}/{address}_{protocol}_{port}_sslscan.txt"; fi' 14 | 15 | [cassandra] 16 | 17 | service-names = [ 18 | '^apani1' 19 | ] 20 | 21 | [[cassandra.scan]] 22 | name = 'nmap-cassandra' 23 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(cassandra* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_cassandra_nmap" {address}' 24 | 25 | [cups] 26 | 27 | service-names = [ 28 | '^ipp' 29 | ] 30 | 31 | [[cups.scan]] 32 | name = 'nmap-cups' 33 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(cups* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_cups_nmap" {address}' 34 | 35 | [distcc] 36 | 37 | service-names = [ 38 | '^distccd' 39 | ] 40 | 41 | [[distcc.scan]] 42 | name = 'nmap-distcc' 43 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,distcc-cve2004-2687" --script-args="distcc-cve2004-2687.cmd=id" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_distcc_nmap" {address}' 44 | 45 | [dns] 46 | 47 | service-names = [ 48 | '^domain' 49 | ] 50 | 51 | [[dns.scan]] 52 | name = 'nmap-dns' 53 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(dns* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_dns_nmap" {address}' 54 | 55 | [finger] 56 | 57 | service-names = [ 58 | '^finger' 59 | ] 60 | 61 | [[finger.scan]] 62 | nmap = 'nmap-finger' 63 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,finger" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_finger_nmap" {address}' 64 | 65 | [ftp] 66 | 67 | service-names = [ 68 | '^ftp', 69 | '^ftp\-data' 70 | ] 71 | 72 | [[ftp.scan]] 73 | name = 'nmap-ftp' 74 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(ftp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_ftp_nmap" {address}' 75 | 76 | [[ftp.scan.pattern]] 77 | description = 'Anonymous FTP Enabled!' 78 | pattern = 'Anonymous FTP login allowed' 79 | 80 | [[ftp.manual]] 81 | description = 'Bruteforce logins:' 82 | commands = [ 83 | 'hydra -v -L "{username_wordlist}" -P "{password_wordlist}" -e nsr -s {port} -o "{crackingdir}/{address}_{protocol}_{port}_ftp_hydra.txt" ftp://{address}', 84 | 'medusa -v 4 -U "{username_wordlist}" -P "{password_wordlist}" -e ns -n {port} -f -O "{crackingdir}/{address}_{protocol}_{port}_ftp_medusa.txt" -M ftp -h {address}' 85 | ] 86 | 87 | [http] 88 | 89 | service-names = [ 90 | '^http', 91 | ] 92 | 93 | ignore-service-names = [ 94 | '^nacn_http$' 95 | ] 96 | 97 | [[http.scan]] 98 | name = 'nmap-http' 99 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(http* or ssl*) and not (brute or broadcast or dos or external or http-slowloris* or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_http_nmap" {address}' 100 | 101 | [[http.scan.pattern]] 102 | description = 'Identified HTTP Server: {match}' 103 | pattern = 'Server: ([^\n]+)' 104 | 105 | [[http.scan.pattern]] 106 | description = 'WebDAV is enabled' 107 | pattern = 'WebDAV is ENABLED' 108 | 109 | [[http.scan]] 110 | name = 'curl-index' 111 | command = 'curl -sSik {scheme}://{address}:{port}/ -m 10 2>&1 | tee "{webdir}/{address}_{protocol}_{port}_{scheme}_index.html"' 112 | 113 | [[http.scan.pattern]] 114 | pattern = '(?i)Powered by [^\n]+' 115 | 116 | [[http.scan]] 117 | name = 'curl-robots' 118 | command = 'curl -sSik {scheme}://{address}:{port}/robots.txt -m 10 2>&1 | tee "{webdir}/{address}_{protocol}_{port}_{scheme}_robots.txt"' 119 | 120 | [[http.scan]] 121 | name = 'wkhtmltoimage' 122 | command = 'if hash wkhtmltoimage 2> /dev/null; then wkhtmltoimage --format png {scheme}://{address}:{port}/ {screenshotsdir}/{address}_{protocol}_{port}_{scheme}_screenshot.png; fi' 123 | 124 | [[http.scan]] 125 | name = 'whatweb' 126 | command = 'whatweb --color=never --no-errors -a 3 -v {scheme}://{address}:{port} 2>&1 | tee "{webdir}/{address}_{protocol}_{port}_{scheme}_whatweb.txt"' 127 | 128 | [[http.scan]] 129 | name = 'nikto' 130 | command = 'nikto -ask=no -h {scheme}://{address}:{port} -output "{niktodir}/{address}_{protocol}_{port}_{scheme}_nikto.html" 2>&1 | tee "{niktodir}/{address}_{protocol}_{port}_{scheme}_nikto.txt"' 131 | 132 | [[http.scan]] 133 | name = 'gobuster' 134 | command = 'gobuster dir -u {scheme}://{address}:{port}/ -w /usr/share/seclists/Discovery/Web-Content/common.txt -e -z -k -l -o "{dirscandir}/{address}_{protocol}_{port}_{scheme}_gobuster_common.txt"' 135 | 136 | [[http.manual]] 137 | description = '(dirsearch) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:' 138 | commands = [ 139 | 'dirsearch -b -u {scheme}://{address}:{port}/ -t 16 -r -E -f -w /usr/share/seclists/Discovery/Web-Content/big.txt --plain-text-report="{dirscandir}/{address}_{protocol}_{port}_{scheme}_dirsearch_big.txt"', 140 | 'dirsearch -b -u {scheme}://{address}:{port}/ -t 16 -r -E -f -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt --plain-text-report="{dirscandir}/{address}_{protocol}_{port}_{scheme}_dirsearch_small.txt"' 141 | ] 142 | 143 | [[http.manual]] 144 | description = '(dirb) Recursive directory/file enumeration for web servers using various wordlists (same as dirsearch above):' 145 | commands = [ 146 | 'dirb {scheme}://{address}:{port}/ /usr/share/seclists/Discovery/Web-Content/big.txt -l -o "{dirscandir}/{address}_{protocol}_{port}_{scheme}_dirb_big.txt"', 147 | 'dirb {scheme}://{address}:{port}/ /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt -l -o "{dirscandir}/{address}_{protocol}_{port}_{scheme}_dirb_small.txt"' 148 | ] 149 | 150 | [[http.manual]] 151 | description = '(gobuster v3) Directory/file enumeration for web servers using various wordlists (same as dirb above):' 152 | commands = [ 153 | 'gobuster dir -u {scheme}://{address}:{port}/ -w /usr/share/seclists/Discovery/Web-Content/big.txt -e -z -k -l -o "{dirscandir}/{address}_{protocol}_{port}_{scheme}_gobuster_big.txt"', 154 | 'gobuster dir -u {scheme}://{address}:{port}/ -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt -e -z -k -l -o "{dirscandir}/{address}_{protocol}_{port}_{scheme}_gobuster_small.txt"' 155 | ] 156 | 157 | [[http.manual]] 158 | description = '(wpscan) WordPress Security Scanner (useful if WordPress is found):' 159 | commands = [ 160 | 'wpscan -v --url {scheme}://{address}:{port}/ --update -e vp,vt,tt,cb,dbe,u,m --plugins-detection aggressive --plugins-version-detection aggressive -f cli-no-color 2>&1 | tee "{webdir}/{address}_{protocol}_{port}_{scheme}_wpscan.txt"' 161 | ] 162 | 163 | [[http.manual]] 164 | description = "Credential bruteforcing commands (don't run these without modifying them):" 165 | commands = [ 166 | 'hydra -L "{username_wordlist}" -P "{password_wordlist}" -e nsr -s {port} -o "{crackingdir}/{address}_{protocol}_{port}_{scheme}_auth_hydra.txt" {scheme}-get://{address}/path/to/auth/area', 167 | 'medusa -U "{username_wordlist}" -P "{password_wordlist}" -e ns -n {port} -O "{crackingdir}/{address}_{protocol}_{port}_{scheme}_auth_medusa.txt" -M http -h {address} -m DIR:/path/to/auth/area', 168 | 'hydra -L "{username_wordlist}" -P "{password_wordlist}" -e nsr -s {port} -o "{crackingdir}/{address}_{protocol}_{port}_{scheme}_form_hydra.txt" {scheme}-post-form://{address}/path/to/login.php:username=^USER^&password=^PASS^:invalid-login-message', 169 | 'medusa -U "{username_wordlist}" -P "{password_wordlist}" -e ns -n {port} -O "{crackingdir}/{address}_{protocol}_{port}_{scheme}_form_medusa.txt" -M web-form -h {address} -m FORM:/path/to/login.php -m FORM-DATA:"post?username=&password=" -m DENY-SIGNAL:"invalid login message"', 170 | ] 171 | 172 | [imap] 173 | 174 | service-names = [ 175 | '^imap' 176 | ] 177 | 178 | [[imap.scan]] 179 | name = 'nmap-imap' 180 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(imap* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_imap_nmap" {address}' 181 | 182 | [kerberos] 183 | 184 | service-names = [ 185 | '^kerberos', 186 | '^kpasswd' 187 | ] 188 | 189 | [[kerberos.scan]] 190 | name = 'nmap-kerberos' 191 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,krb5-enum-users" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_kerberos_nmap" {address}' 192 | 193 | [ldap] 194 | 195 | service-names = [ 196 | '^ldap' 197 | ] 198 | 199 | [[ldap.scan]] 200 | name = 'nmap-ldap' 201 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(ldap* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_ldap_nmap" {address}' 202 | 203 | [[ldap.scan]] 204 | name = 'enum4linux' 205 | command = 'enum4linux -a -M -l -d {address} 2>&1 | tee "{servicesdir}/{address}_enum4linux.txt"' 206 | run_once = true 207 | ports.tcp = [139, 389, 445] 208 | ports.udp = [137] 209 | 210 | [[ldap.manual]] 211 | description = 'ldapsearch command (modify before running)' 212 | commands = [ 213 | 'ldapsearch -x -D "" -w "" -p {port} -h {address} -b "dc=example,dc=com" -s sub "(objectclass=*) 2>&1 | tee > "{servicesdir}/{address}_{protocol}_{port}_ldap_all-entries.txt"' 214 | ] 215 | 216 | [mongodb] 217 | 218 | service-names = [ 219 | '^mongod' 220 | ] 221 | 222 | [[mongodb.scan]] 223 | name = 'nmap-mongodb' 224 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(mongodb* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_mongodb_nmap" {address}' 225 | 226 | [mssql] 227 | 228 | service-names = [ 229 | '^mssql', 230 | '^ms\-sql' 231 | ] 232 | 233 | [[mssql.scan]] 234 | name = 'nmap-mssql' 235 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(ms-sql* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" --script-args="mssql.instance-port={port},mssql.username=sa,mssql.password=sa" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_mssql_nmap" {address}' 236 | 237 | [[mssql.manual]] 238 | description = '(sqsh) interactive database shell' 239 | commands = [ 240 | 'sqsh -U -P -S {address}:{port}' 241 | ] 242 | 243 | [mysql] 244 | 245 | service-names = [ 246 | '^mysql' 247 | ] 248 | 249 | [[mysql.scan]] 250 | name = 'nmap-mysql' 251 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(mysql* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_mysql_nmap" {address}' 252 | 253 | [nfs] 254 | 255 | service-names = [ 256 | '^nfs', 257 | '^rpcbind' 258 | ] 259 | 260 | [[nfs.scan]] 261 | name = 'nmap-nfs' 262 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(rpcinfo or nfs*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_nfs_nmap" {address}' 263 | 264 | [[nfs.scan]] 265 | name = 'showmount' 266 | command = 'showmount -e {address} 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_showmount.txt"' 267 | 268 | [nntp] 269 | 270 | service-names = [ 271 | '^nntp' 272 | ] 273 | 274 | [[nntp.scan]] 275 | name = 'nmap-nntp' 276 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,nntp-ntlm-info" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_nntp_nmap" {address}' 277 | 278 | [oracle] 279 | 280 | service-names = [ 281 | '^oracle' 282 | ] 283 | 284 | [[oracle.scan]] 285 | name = 'nmap-oracle' 286 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(oracle* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_oracle_nmap" {address}' 287 | 288 | [[oracle.scan]] 289 | name = 'oracle-tnscmd-ping' 290 | command = 'tnscmd10g ping -h {address} -p {port} 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_oracle_tnscmd_ping.txt"' 291 | 292 | [[oracle.scan]] 293 | name = 'oracle-tnscmd-version' 294 | command = 'tnscmd10g version -h {address} -p {port} 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_oracle_tnscmd_version.txt"' 295 | 296 | [[oracle.manual]] 297 | description = 'Oracle assessment framework' 298 | command = 'oscanner -v -s {address} -P {port} 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_oracle_scanner.txt"' 299 | 300 | [[oracle.manual]] 301 | description = 'Brute-force SIDs using Nmap' 302 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,oracle-sid-brute" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_oracle_sid-brute_nmap" {address}' 303 | 304 | [[oracle.manual]] 305 | description = 'Install ODAT (https://github.com/quentinhardy/odat) and run the following commands:' 306 | commands = [ 307 | 'python3 odat.py tnscmd -s {address} -p {port} --ping', 308 | 'python3 odat.py tnscmd -s {address} -p {port} --version', 309 | 'python3 odat.py tnscmd -s {address} -p {port} --status', 310 | 'python3 odat.py sidguesser -s {address} -p {port}', 311 | 'python3 odat.py passwordguesser -s {address} -p {port} -d --accounts-file accounts/accounts_multiple.txt', 312 | 'python3 odat.py tnspoison -s {address} -p {port} -d --test-module' 313 | ] 314 | 315 | [[oracle.manual]] 316 | description = 'Install Oracle Instant Client (https://github.com/rapid7/metasploit-framework/wiki/How-to-get-Oracle-Support-working-with-Kali-Linux) and then bruteforce with patator:' 317 | commands = [ 318 | 'patator oracle_login host={address} port={port} user=COMBO00 password=COMBO01 0=/usr/share/seclists/Passwords/Default-Credentials/oracle-betterdefaultpasslist.txt -x ignore:code=ORA-01017 -x ignore:code=ORA-28000' 319 | ] 320 | 321 | [pop3] 322 | 323 | service-names = [ 324 | '^pop3' 325 | ] 326 | 327 | [[pop3.scan]] 328 | name = 'nmap-pop3' 329 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(pop3* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{servicesdir}/{address}_{protocol}_{port}_pop3_nmap" {address}' 330 | 331 | [rdp] 332 | 333 | service-names = [ 334 | '^rdp', 335 | '^ms\-wbt\-server', 336 | '^ms\-term\-serv' 337 | ] 338 | 339 | [[rdp.scan]] 340 | name = 'nmap-rdp' 341 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(rdp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_rdp_nmap" {address}' 342 | 343 | [[rdp.manual]] 344 | description = 'Bruteforce logins:' 345 | commands = [ 346 | 'hydra -v -L "{username_wordlist}" -P "{password_wordlist}" -e nsr -s {port} -o "{crackingdir}/{address}_{protocol}_{port}_rdp_hydra.txt" rdp://{address}', 347 | 'medusa -v 4 -U "{username_wordlist}" -P "{password_wordlist}" -e ns -n {port} -O "{crackingdir}/{address}_{protocol}_{port}_rdp_medusa.txt" -M rdp -h {address}' 348 | ] 349 | 350 | [rmi] 351 | 352 | service-names = [ 353 | '^java\-rmi', 354 | '^rmiregistry' 355 | ] 356 | 357 | [[rmi.scan]] 358 | name = 'nmap-rmi' 359 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,rmi-vuln-classloader,rmi-dumpregistry" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_rmi_nmap" {address}' 360 | 361 | [rpc] 362 | 363 | service-names = [ 364 | '^msrpc', 365 | '^rpcbind', 366 | '^erpc' 367 | ] 368 | 369 | [[rpc.scan]] 370 | name = 'nmap-msrpc' 371 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,msrpc-enum,rpc-grind,rpcinfo" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_rpc_nmap" {address}' 372 | 373 | [[rpc.manual]] 374 | description = 'RPC Client:' 375 | commands = [ 376 | 'rpcclient -p {port} -U "" {address}' 377 | ] 378 | 379 | [sip] 380 | 381 | service-names = [ 382 | '^asterisk' 383 | ] 384 | 385 | [[sip.scan]] 386 | name = 'nmap-sip' 387 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,sip-enum-users,sip-methods" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_sip_nmap" {address}' 388 | 389 | [[sip.scan]] 390 | name = 'svwar' 391 | command = 'svwar -D -m INVITE -p {port} {address}' 392 | 393 | [ssh] 394 | 395 | service-names = [ 396 | '^ssh' 397 | ] 398 | 399 | [[ssh.scan]] 400 | name = 'nmap-ssh' 401 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,ssh2-enum-algos,ssh-hostkey,ssh-auth-methods" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_ssh_nmap" {address}' 402 | 403 | [[ssh.manual]] 404 | description = 'Bruteforce logins:' 405 | commands = [ 406 | 'hydra -v -L "{username_wordlist}" -P "{password_wordlist}" -e nsr -s {port} -o "{crackingdir}/{address}_{protocol}_{port}_ssh_hydra.txt" ssh://{address}', 407 | 'medusa -v 4 -U "{username_wordlist}" -P "{password_wordlist}" -e ns -n {port} -O "{crackingdir}/{address}_{protocol}_{port}_ssh_medusa.txt" -M ssh -h {address}' 408 | ] 409 | [smb] 410 | 411 | service-names = [ 412 | '^smb', 413 | '^microsoft\-ds', 414 | '^netbios' 415 | ] 416 | 417 | [[smb.scan]] 418 | name = 'nmap-smb' 419 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(nbstat or smb* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" --script-args="unsafe=1" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_smb_nmap" {address}' 420 | 421 | [[smb.scan]] 422 | name = 'enum4linux' 423 | command = 'enum4linux -a -M -l -d {address} 2>&1 | tee "{servicesdir}/{address}_enum4linux.txt"' 424 | run_once = true 425 | ports.tcp = [139, 389, 445] 426 | ports.udp = [137] 427 | 428 | [[smb.scan]] 429 | name = 'nbtscan' 430 | command = 'nbtscan -rvh {address} 2>&1 | tee "{servicesdir}/{address}_nbtscan.txt"' 431 | run_once = true 432 | ports.udp = [137] 433 | 434 | [[smb.scan]] 435 | name = 'smbclient' 436 | command = 'smbclient -L\\ -N -I {address} 2>&1 | tee "{servicesdir}/{address}_smbclient.txt"' 437 | run_once = true 438 | ports.tcp = [139, 445] 439 | 440 | [[smb.scan]] 441 | name = 'smbmap-share-permissions' 442 | command = 'smbmap -H {address} -P {port} 2>&1 | tee -a "{servicesdir}/{address}_smbmap-share-permissions.txt"; smbmap -u null -p "" -H {address} -P {port} 2>&1 | tee -a "{servicesdir}/{address}_smbmap-share-permissions.txt"' 443 | 444 | [[smb.scan]] 445 | name = 'smbmap-list-contents' 446 | command = 'smbmap -H {address} -P {port} -R 2>&1 | tee -a "{servicesdir}/{address}_smbmap-list-contents.txt"; smbmap -u null -p "" -H {address} -P {port} -R 2>&1 | tee -a "{servicesdir}/{address}_smbmap-list-contents.txt"' 447 | 448 | [[smb.scan]] 449 | name = 'smbmap-execute-command' 450 | command = 'smbmap -H {address} -P {port} -x "ipconfig /all" 2>&1 | tee -a "{servicesdir}/{address}_smbmap-execute-command.txt"; smbmap -u null -p "" -H {address} -P {port} -x "ipconfig /all" 2>&1 | tee -a "{servicesdir}/{address}_smbmap-execute-command.txt"' 451 | 452 | [[smb.manual]] 453 | description = 'Nmap scans for SMB vulnerabilities that could potentially cause a DoS if scanned (according to Nmap). Be careful:' 454 | commands = [ 455 | 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="smb-vuln-ms06-025" --script-args="unsafe=1" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_smb_ms06-025" {address}', 456 | 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="smb-vuln-ms07-029" --script-args="unsafe=1" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_smb_ms07-029" {address}', 457 | 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="smb-vuln-ms08-067" --script-args="unsafe=1" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_smb_ms08-067" {address}' 458 | ] 459 | 460 | [smtp] 461 | 462 | service-names = [ 463 | '^smtp' 464 | ] 465 | 466 | [[smtp.scan]] 467 | name = 'nmap-smtp' 468 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(smtp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_smtp_nmap" {address}' 469 | 470 | [[smtp.scan]] 471 | name = 'smtp-user-enum' 472 | command = 'smtp-user-enum -M VRFY -U "{username_wordlist}" -t {address} -p {port} 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_smtp_user-enum.txt"' 473 | 474 | [snmp] 475 | 476 | service-names = [ 477 | '^snmp' 478 | ] 479 | 480 | [[snmp.scan]] 481 | name = 'nmap-snmp' 482 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(snmp* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_snmp-nmap" {address}' 483 | 484 | [[snmp.scan]] 485 | name = 'onesixtyone' 486 | command = 'onesixtyone -c /usr/share/seclists/Discovery/SNMP/common-snmp-community-strings-onesixtyone.txt -dd {address} 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_onesixtyone.txt"' 487 | run_once = true 488 | ports.udp = [161] 489 | 490 | [[snmp.scan]] 491 | name = 'snmpwalk' 492 | command = 'snmpwalk -c public -v 1 {address} 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_snmpwalk.txt"' 493 | run_once = true 494 | ports.udp = [161] 495 | 496 | [[snmp.scan]] 497 | name = 'snmpwalk-system-processes' 498 | command = 'snmpwalk -c public -v 1 {address} 1.3.6.1.2.1.25.1.6.0 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_snmpwalk_system_processes.txt"' 499 | run_once = true 500 | ports.udp = [161] 501 | 502 | [[snmp.scan]] 503 | name = 'snmpwalk-running-processes' 504 | command = 'snmpwalk -c public -v 1 {address} 1.3.6.1.2.1.25.4.2.1.2 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_snmpwalk_running_processes.txt"' 505 | run_once = true 506 | ports.udp = [161] 507 | 508 | [[snmp.scan]] 509 | name = 'snmpwalk-process-paths' 510 | command = 'snmpwalk -c public -v 1 {address} 1.3.6.1.2.1.25.4.2.1.4 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_snmpwalk_process_paths.txt"' 511 | run_once = true 512 | ports.udp = [161] 513 | 514 | [[snmp.scan]] 515 | name = 'snmpwalk-storage-units' 516 | command = 'snmpwalk -c public -v 1 {address} 1.3.6.1.2.1.25.2.3.1.4 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_snmpwalk_storage_units.txt"' 517 | run_once = true 518 | ports.udp = [161] 519 | 520 | [[snmp.scan]] 521 | name = 'snmpwalk-software-names' 522 | command = 'snmpwalk -c public -v 1 {address} 1.3.6.1.2.1.25.6.3.1.2 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_snmpwalk_software_names.txt"' 523 | run_once = true 524 | ports.udp = [161] 525 | 526 | [[snmp.scan]] 527 | name = 'snmpwalk-user-accounts' 528 | command = 'snmpwalk -c public -v 1 {address} 1.3.6.1.4.1.77.1.2.25 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_snmpwalk_user_accounts.txt"' 529 | run_once = true 530 | ports.udp = [161] 531 | 532 | [[snmp.scan]] 533 | name = 'snmpwalk-tcp-ports' 534 | command = 'snmpwalk -c public -v 1 {address} 1.3.6.1.2.1.6.13.1.3 2>&1 | tee "{servicesdir}/{address}_{protocol}_{port}_snmp_snmpwalk_tcp_ports.txt"' 535 | run_once = true 536 | ports.udp = [161] 537 | 538 | [telnet] 539 | 540 | service-names = [ 541 | '^telnet' 542 | ] 543 | 544 | [[telnet.scan]] 545 | name = 'nmap-telnet' 546 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,telnet-encryption,telnet-ntlm-info" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_telnet-nmap" {address}' 547 | 548 | [tftp] 549 | 550 | service-names = [ 551 | '^tftp' 552 | ] 553 | 554 | [[tftp.scan]] 555 | name = 'nmap-tftp' 556 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,tftp-enum" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_tftp-nmap" {address}' 557 | 558 | [vnc] 559 | 560 | service-names = [ 561 | '^vnc' 562 | ] 563 | 564 | [[vnc.scan]] 565 | name = 'nmap-vnc' 566 | command = 'nmap {nmap_extra} -vv -Pn -sV -p {port} --script="banner,(vnc* or realvnc* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" --script-args="unsafe=1" -oA "{tcpservicesdir}/{address}_{protocol}_{port}_vnc_nmap" {address}' 567 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | toml 2 | colorama --------------------------------------------------------------------------------