├── .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 | 
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
--------------------------------------------------------------------------------