├── .gitignore ├── CHANGES.txt ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── README.txt ├── TODO ├── bin └── enumerator ├── enumerator ├── __init__.py ├── lib │ ├── __init__.py │ ├── config.py │ ├── delegator.py │ ├── generic_service.py │ ├── nmap.py │ ├── process_manager.py │ └── services │ │ ├── __init__.py │ │ ├── ftp.py │ │ ├── http.py │ │ ├── nbt.py │ │ ├── rpc.py │ │ └── ssh.py └── static │ ├── __init__.py │ ├── user-password-micro.txt │ └── user-password-tiny.txt ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | MANIFEST 4 | env/ 5 | dist/ 6 | -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- 1 | v0.1, 2014-09-07 -- Initial release of new code. 2 | v0.1.1, 2014-09-10 -- Corrected issue with flooding system with processes, now moved to use multiprocessing.Pool(). 3 | v0.1.2, 2014-09-12 -- Refactored service classification rules out to individual service modules and updated class GenericService to validate new service rules. Created ProcessManager to handle process related tasks. 4 | v0.1.3, 2014-09-14 -- enumerator now takes either a file path or single host parameter to use. 5 | v0.1.4, 2014-09-18 -- Added SSH service module, changed all bruteforce options to use 'tiny' credentials file instead of 'micro', reverted nmap TCP scan options, minor bug fixes. -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2014] [Erik Dominguez] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.txt 2 | recursive-include enumerator *.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | enumerator 2 | ========= 3 | 4 |   5 | #### Contributors: 6 | 7 | - Erik Dominguez (IRC: Maleus | Twitter: @Maleus21) (original concept and script author) - http://overflowsecurity.com 8 | - Steve Coward (IRC: felux | Twitter: @sugarstackio) - http://sugarstack.io 9 | 10 | enumerator is a tool built to assist in automating the often tedious task of enumerating a target or list of targets during a penetration test. 11 | 12 | enumerator is built around the Kali Linux distro. To use this on other Linux distros, please ensure the following tools are installed: 13 | 14 | - nmap 15 | - nikto, dirb (http enumeration) 16 | - hydra (ftp enumeration) 17 | - enum4linux (netbios enumeration) 18 | 19 | **Windows is NOT supported at this time.** 20 | 21 | Available Service Modules 22 | ---- 23 | 24 | - FTP (hydra ftp login enumeration, nmap ftp NSE scripts) 25 | - HTTP (nikto scan, dirb directory enumeration) 26 | - Netbios (enum4linux scan) 27 | - RPC (showmount output) 28 | - SSH (hydra ssh login enumeration, nmap ssh NSE ssh-hostkey enumeration) 29 | 30 | Changelog 31 | ---- 32 | 33 | **v0.1.4** - Added SSH service module, changed all bruteforce options to use 'tiny' credentials file instead of 'micro', reverted nmap TCP scan options, minor bug fixes. 34 | 35 | **v0.1.3** - enumerator now takes either a file path or single host parameter to use. 36 | 37 | **v0.1.2** - Refactored service classification rules out to individual service modules and updated class GenericService to validate new service rules. Created ProcessManager to handle process related tasks. 38 | 39 | **v0.1.1** - Corrected issue with flooding system with processes, now moved to use multiprocessing.Pool(). 40 | 41 | 42 | Installation 43 | ---- 44 | 45 | While not required, it is advised to create a virtualenv for enumerator to avoid conflicts with different versions of required packages. If you're unfamiliar with virtualenv, please follow [this guide] [1]. 46 | 47 | Use [pip] [2] to install the required libraries: 48 | 49 | ```sh 50 | (venv) $ pip install enumerator 51 | ``` 52 | 53 | or alternatively, if you have cloned the enumerator repository: 54 | 55 | ```sh 56 | (venv) $ python setup.py install 57 | ``` 58 | 59 | Usage 60 | ---- 61 | 62 | To run, enumerator takes one of two parameters; either a file path to a text file with a list of IP addresses, one per line. 63 | 64 | - ``-f``, ``--file`` - path to a text file with a list of IP addresses, one per line. 65 | - ``-s``, ``--single`` - a single IP address. 66 | 67 | ```sh 68 | (venv) $ enumerator -f /root/Desktop/hosts.txt 69 | ``` 70 | 71 | ```sh 72 | (venv) $ enumerator -s 10.1.1.215 73 | ``` 74 | 75 | enumerator will then asynchronously begin scanning using nmap. Once nmap finishes, the nmap results are parsed and passed to a system which, based upon a simple set of rules, delegates further service-level enumeration to service-specific modules found in ``lib/``. Each service module defines specific enumeration applications to be run, and will run each process against the target, writing any results to file for review. 76 | 77 | Currently, enumerator output is very minimal, so it's safe to say that when the enumerator script finishes, all hosts have been thoroughly scanned. Future versions of enumerator will have better in-time 78 | reporting of enumeration progress. Results are saved in ``results/``, and each host will have their own folder, within which all enumeration process output is saved for review once enumerator completes. 79 | 80 | Extending enumerator 81 | ---- 82 | 83 | enumerator is designed to be (relatively) easily extended for additional service enumeration! Follow these steps to add your own additional service enumeration: 84 | 85 | #### Creating a NEW service module: 86 | 87 | * Create folder in ``lib/`` for your service module and related files. 88 | * Create service module file and \_\_init\__\.py inside the folder created above. 89 | * The service module should be identical in syntax to existing service modules. 90 | * ``SERVICE_DEFINITION`` is a special set of key:value rules to classify a service. Details below. 91 | * ``PROCESSES`` should contain the literal command(s) to be run. Follow the named parameter syntax for any variable strings. 92 | * Update the ``params`` dictionary within the ``scan()`` method to match parameterized string vars set in ``PROCESSES``. 93 | * In ``lib/delegator.py``, import your new module along with the existing module imports. 94 | * In ``lib/delegator.py``, instantiate your service module and add the object to the ``service_modules`` list. 95 | 96 | In order to test a newly created service module, it is much easier to test by invoking the module directly as opposed to running enumerator. Make sure that your new service module follows the same syntax as existing module scripts at the very bottom of the script. Update those calls to match the syntax required for your new service module. To run, use the following syntax from the root directory of enumerator, replacing names and input parameters as needed: 97 | 98 | ```sh 99 | (venv) $ python -m enumerator.lib.. 100 | ``` 101 | 102 | #### Updating an existing service module: 103 | * To add a new service enumeration command to an existing module, simply update ``PROCESSES`` with the command to be invoked. Be sure that any named parameters are passed in the ``scan()`` call. 104 | 105 | #### Creating and Updating service definitions 106 | ``SERVICE_DEFINITION`` defines what attributes classify a particular service. Two keys, ``service`` and ``port`` are available to define the service. Following two examples and how they translate: 107 | 108 | - ``service:ftp`` - The value ``'ftp'`` should be present in nmap's 'service' value. 109 | - ``service:http,-proxy or port:8081`` - The value ``'http'`` should be in 'service', the value ``'proxy'`` should **not** be in 'service' or the value ``'port'`` should contain the value ``'8081'``. 110 | 111 | 112 | #### Updating nmap process command line parameters: 113 | 114 | Generally speaking, editing these defined parameters may negatively impact the service enumeration modules, so take care with what is being modified! Configurable ``nmap`` options such as type of TCP connection syntax, port ranges may certainly be modified to suit the specific use case. These changes are made in ``lib/nmap.py`` in the ``PROCESSES`` constant defined near the top of the script. 115 | 116 | Additional Information 117 | ==== 118 | 119 | enumerator is being actively maintained! The ``TODO`` file will be kept updated with various known bug fixes, minor or major features to be worked on. If you're interested in working on a new feature or would like to submit new service enumeration modules to the project, by all means fork us! Maleus and felux (Steve Coward) are always around on IRC if you'd like to join us! You can find us on **Freenode** at **#overflowsec**. 120 | 121 | [1]:http://docs.python-guide.org/en/latest/dev/virtualenvs/ 122 | [2]:http://pip.readthedocs.org/en/latest/installing.html -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | enumerator 2 | ========== 3 | 4 | Contributors: 5 | 6 | - Erik Dominguez (IRC: Maleus \| Twitter: @Maleus21) (original concept 7 | and script author, Maleus@overflowsecurity.com) - http://overflowsecurity.com 8 | - Steve Coward (IRC: felux \| Twitter: @sugarstackio) - 9 | http://sugarstack.io 10 | 11 | enumerator is a tool built to assist in automating the often tedious 12 | task of enumerating a target or list of targets during a penetration 13 | test. 14 | 15 | enumerator is built around the Kali Linux distro. To use this on other 16 | Linux distros, please ensure the following tools are installed: 17 | 18 | - nmap 19 | - nikto, dirb (http enumeration) 20 | - hydra (ftp enumeration) 21 | - enum4linux (netbios enumeration) 22 | 23 | **Windows is NOT supported at this time.** 24 | 25 | Available Service Modules 26 | ------------------------- 27 | 28 | - FTP (hydra ftp login enumeration, nmap ftp NSE scripts) 29 | - HTTP (nikto scan, dirb directory enumeration) 30 | - Netbios (enum4linux scan) 31 | - RPC (showmount output) 32 | - SSH (hydra ssh login enumeration, nmap ssh NSE ssh-hostkey 33 | enumeration) 34 | 35 | Changelog 36 | --------- 37 | 38 | **v0.1.4** - Added SSH service module, changed all bruteforce options to 39 | use 'tiny' credentials file instead of 'micro', reverted nmap TCP scan 40 | options, minor bug fixes. 41 | 42 | **v0.1.3** - enumerator now takes either a file path or single host 43 | parameter to use. 44 | 45 | **v0.1.2** - Refactored service classification rules out to individual 46 | service modules and updated class GenericService to validate new service 47 | rules. Created ProcessManager to handle process related tasks. 48 | 49 | **v0.1.1** - Corrected issue with flooding system with processes, now 50 | moved to use multiprocessing.Pool(). 51 | 52 | Installation 53 | ------------ 54 | 55 | While not required, it is advised to create a virtualenv for enumerator 56 | to avoid conflicts with different versions of required packages. If 57 | you're unfamiliar with virtualenv, please follow `this 58 | guide `__. 59 | 60 | Use `pip `__ to 61 | install the required libraries: 62 | 63 | .. code:: sh 64 | 65 | (venv) $ pip install enumerator 66 | 67 | or alternatively, if you have cloned the enumerator repository: 68 | 69 | .. code:: sh 70 | 71 | (venv) $ python setup.py install 72 | 73 | Usage 74 | ----- 75 | 76 | To run, enumerator takes one of two parameters; either a file path to a 77 | text file with a list of IP addresses, one per line. 78 | 79 | - ``-f``, ``--file`` - path to a text file with a list of IP addresses, 80 | one per line. 81 | - ``-s``, ``--single`` - a single IP address. 82 | 83 | .. code:: sh 84 | 85 | (venv) $ enumerator -f /root/Desktop/hosts.txt 86 | 87 | .. code:: sh 88 | 89 | (venv) $ enumerator -s 10.1.1.215 90 | 91 | enumerator will then asynchronously begin scanning using nmap. Once nmap 92 | finishes, the nmap results are parsed and passed to a system which, 93 | based upon a simple set of rules, delegates further service-level 94 | enumeration to service-specific modules found in ``lib/``. Each service 95 | module defines specific enumeration applications to be run, and will run 96 | each process against the target, writing any results to file for review. 97 | 98 | Currently, enumerator output is very minimal, so it's safe to say that 99 | when the enumerator script finishes, all hosts have been thoroughly 100 | scanned. Future versions of enumerator will have better in-time 101 | reporting of enumeration progress. Results are saved in ``results/``, 102 | and each host will have their own folder, within which all enumeration 103 | process output is saved for review once enumerator completes. 104 | 105 | Extending enumerator 106 | -------------------- 107 | 108 | enumerator is designed to be (relatively) easily extended for additional 109 | service enumeration! Follow these steps to add your own additional 110 | service enumeration: 111 | 112 | Creating a NEW service module: 113 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 114 | 115 | - Create folder in ``lib/`` for your service module and related files. 116 | - Create service module file and \_\_init\_\_.py inside the folder 117 | created above. 118 | - The service module should be identical in syntax to existing service 119 | modules. 120 | - ``SERVICE_DEFINITION`` is a special set of key:value rules to 121 | classify a service. Details below. 122 | - ``PROCESSES`` should contain the literal command(s) to be run. Follow 123 | the named parameter syntax for any variable strings. 124 | - Update the ``params`` dictionary within the ``scan()`` method to 125 | match parameterized string vars set in ``PROCESSES``. 126 | - In ``lib/delegator.py``, import your new module along with the 127 | existing module imports. 128 | - In ``lib/delegator.py``, instantiate your service module and add the 129 | object to the ``service_modules`` list. 130 | 131 | In order to test a newly created service module, it is much easier to 132 | test by invoking the module directly as opposed to running enumerator. 133 | Make sure that your new service module follows the same syntax as 134 | existing module scripts at the very bottom of the script. Update those 135 | calls to match the syntax required for your new service module. To run, 136 | use the following syntax from the root directory of enumerator, 137 | replacing names and input parameters as needed: 138 | 139 | .. code:: sh 140 | 141 | (venv) $ python -m enumerator.lib.. 142 | 143 | Updating an existing service module: 144 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 145 | 146 | - To add a new service enumeration command to an existing module, 147 | simply update ``PROCESSES`` with the command to be invoked. Be sure 148 | that any named parameters are passed in the ``scan()`` call. 149 | 150 | Creating and Updating service definitions 151 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 152 | 153 | ``SERVICE_DEFINITION`` defines what attributes classify a particular 154 | service. Two keys, ``service`` and ``port`` are available to define the 155 | service. Following two examples and how they translate: 156 | 157 | - ``service:ftp`` - The value ``'ftp'`` should be present in nmap's 158 | 'service' value. 159 | - ``service:http,-proxy or port:8081`` - The value ``'http'`` should be 160 | in 'service', the value ``'proxy'`` should **not** be in 'service' or 161 | the value ``'port'`` should contain the value ``'8081'``. 162 | 163 | Updating nmap process command line parameters: 164 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 165 | 166 | Generally speaking, editing these defined parameters may negatively 167 | impact the service enumeration modules, so take care with what is being 168 | modified! Configurable ``nmap`` options such as type of TCP connection 169 | syntax, port ranges may certainly be modified to suit the specific use 170 | case. These changes are made in ``lib/nmap.py`` in the ``PROCESSES`` 171 | constant defined near the top of the script. 172 | 173 | Additional Information 174 | ====================== 175 | 176 | enumerator is being actively maintained! The ``TODO`` file will be kept 177 | updated with various known bug fixes, minor or major features to be 178 | worked on. If you're interested in working on a new feature or would 179 | like to submit new service enumeration modules to the project, by all 180 | means fork us! Maleus and felux (Steve Coward) are always around on IRC 181 | if you'd like to join us! You can find us on **Freenode** at 182 | **#overflowsec**. 183 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Add function for saving FTP anonymous login = true to directory 2 | -------------------------------------------------------------------------------- /bin/enumerator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """enumerator is a script built to assist in 3 | automating the tedious task of enumerating 4 | a target or list of targets during a penetration 5 | test. 6 | 7 | @author: Maleus 8 | @date: 2014-07-28 9 | @author: Steve Coward (stevesugarstack.io) 10 | @version: 0.1 11 | @notes: Built for Kali Linux, not tested on other distros. 12 | The current version of enumerator requires the 13 | following applications to be installed: 14 | - nmap 15 | - nikto, dirb (http enumeration) 16 | - hydra (ftp enumeration) 17 | - enum4linux (netbios enumeration) 18 | """ 19 | import argparse 20 | import sys 21 | import multiprocessing 22 | from os.path import expanduser 23 | 24 | from enumerator.lib import nmap, config 25 | 26 | if __name__ == '__main__': 27 | parser = argparse.ArgumentParser(description='This is intended to simplify the common enumeration \ 28 | actions taken during a pentest engagement. The only parameter required is a path to a list of \ 29 | host IP addresses. nmap processes are then kicked off which in turn intelligently kick off ftp \ 30 | scanning (anonymous & hydra), enum4linux, dirb or nikto processes depending on nmap service \ 31 | enumeration output. All output is organized and saved to local folders named by IP address.') 32 | 33 | group = parser.add_mutually_exclusive_group(required=True) 34 | group.add_argument('-f', '--file', metavar='file path', type=argparse.FileType( 35 | 'r'), help='path to file of IP addresses') 36 | group.add_argument( 37 | '-s', '--single', metavar='single IP', type=str, help='Check single IP') 38 | 39 | parser.add_argument('-m', '--mode', metavar='scan mode', type=str, choices=[ 40 | 'normal', 'stealth'], default='normal', help='Type of scan to perform. Default is \ 41 | normal and loud. "stealth" reduces some options for scan timing or IDS evasion.') 42 | 43 | args = parser.parse_args() 44 | 45 | # Make sure to put results in user's home dir rather than where Enumerator is executed. 46 | # expanduser for compatibility. Probably should be configurable via an 47 | # output flag. 48 | results_dir = "{0}/enumerator_results".format(expanduser("~")) 49 | 50 | ip_list = [] 51 | 52 | if args.file: 53 | file_contents = args.file.read() 54 | 55 | # Handle empty file 56 | if file_contents == '': 57 | print '[!] The contents of the provided file are empty.' 58 | sys.exit(1) 59 | else: 60 | # Turn the file contents into a list of ip addresses 61 | # Trim blank lines out of list 62 | ip_list = file_contents.split('\n') 63 | ip_list = [ip for ip in ip_list if ip != ''] 64 | elif args.single: 65 | ip_list = [args.single] 66 | 67 | # Set the scan mode config option. 68 | config.mode = args.mode 69 | 70 | print '[+] IP list parsed, sending hosts to nmap...' 71 | pool = multiprocessing.Pool( 72 | multiprocessing.cpu_count() * 2, maxtasksperchild=2) 73 | pool.map_async(nmap.scan, [(ip, results_dir) 74 | for ip in ip_list]).get(9999999) 75 | pool.close() 76 | pool.join() 77 | -------------------------------------------------------------------------------- /enumerator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Maleus/Enumerator/2937d174c3c66ae6670a2375a52925be21c88fbb/enumerator/__init__.py -------------------------------------------------------------------------------- /enumerator/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Maleus/Enumerator/2937d174c3c66ae6670a2375a52925be21c88fbb/enumerator/lib/__init__.py -------------------------------------------------------------------------------- /enumerator/lib/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # mode - Degree of scanning done by service modules. 4 | # Default is 'normal', 2nd option is 'stealth'. 5 | mode = 'normal' 6 | -------------------------------------------------------------------------------- /enumerator/lib/delegator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """The delegator module 3 | receives nmap scan result data 4 | and, based on a set of rules, will 5 | delegate more service-specific 6 | enumeration. 7 | 8 | @author: Steve Coward (stevesugarstack.io) 9 | @version: 1.0 10 | """ 11 | from .services import service_modules 12 | 13 | 14 | def receive_service_data(sender=None, **flags): 15 | """Receive data either directly (not implemented) or via signal. Delegate 16 | service enumeration depending on reported services. 17 | 18 | @param sender: Name value of where the signal was sent from (default: None) 19 | @param flags: IP scan results are passed as a dict. 20 | """ 21 | 22 | results = flags.get('scan_results') 23 | working_directory = flags.get('directory') 24 | ip = results.keys()[0] 25 | 26 | tcp_services = results[ip]['tcp'] 27 | 28 | for tcp_service in tcp_services: 29 | service, port = tcp_service.get('service'), tcp_service.get('port') 30 | for module in service_modules: 31 | if module.is_valid_service(tcp_service): 32 | module.scan(working_directory, dict(ip=ip, port=port)) 33 | 34 | if __name__ == '__main__': 35 | # TODO: Possibly set up delegator module to accept a json file of 36 | # results if called directly. 37 | pass 38 | -------------------------------------------------------------------------------- /enumerator/lib/generic_service.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """GenericService encapsulates any 3 | methods which are common across all 4 | service modules. 5 | 6 | @author: Steve Coward (stevesugarstack.io) 7 | @version 1.0 8 | """ 9 | import os 10 | import re 11 | 12 | 13 | class GenericService(object): 14 | static_path = '%s/../static' % os.path.dirname(os.path.realpath(__file__)) 15 | compiled_service_definition = None 16 | 17 | def __init__(self): 18 | self.compiled_service_definition = self.compile_service_definition( 19 | self.SERVICE_DEFINITION) 20 | 21 | def compile_service_definition(self, definition): 22 | """Take a string of key:values and parse 23 | the values into a python interpretable 24 | conditional statement. 25 | 26 | @param definition: String used to classify 27 | a service. 28 | """ 29 | rule_parser_pattern = re.compile('([^\s]+\s)?(\w+):([^\s]+)') 30 | rule = [] 31 | for rule_set in rule_parser_pattern.findall(definition): 32 | conditional, key, values = map(str.strip, rule_set) 33 | 34 | # Determine if values need to be split apart. 35 | # Rule: If there are no '-' values at the beginning of each value, we can use a list. 36 | # Rule: If there are '-' values at the beginning of each value, 37 | # split apart. 38 | if len([val for val in values.split(',') if val[0] == '-']): 39 | values_set = values.split(',') 40 | for value in values_set: 41 | if value[0] == '-': 42 | rule.append('"%s" not in %s' % (value[1:], key)) 43 | else: 44 | rule.append('"%s" in %s' % (value, key)) 45 | else: 46 | values_set = values.split(',') 47 | rule.append('%s %s in %s' % (conditional, key, values_set)) 48 | 49 | return ' and '.join(rule).replace('and or', 'or') 50 | 51 | def is_valid_service(self, attributes): 52 | """Returns True or False if the attributes 53 | of a service record match the definition of 54 | a service. 55 | 56 | @param attributes: Dict value of a scanned service 57 | (service,port,state). 58 | """ 59 | service = attributes.get('service') 60 | port = attributes.get('port') 61 | state = attributes.get('state') 62 | 63 | if state != 'open': 64 | return False 65 | 66 | # The keys in rule will map to service, port and status set above. 67 | return eval(self.compiled_service_definition) 68 | -------------------------------------------------------------------------------- /enumerator/lib/nmap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """This module is the first 3 | step in gathering initial 4 | service enumeration data from 5 | a list of hosts. It initializes 6 | the scanning commands and parses 7 | the scan results. The scan results 8 | are then passed to the delegator 9 | module which determines what enumerator 10 | should do next. 11 | 12 | @author: Steve Coward (stevesugarstack.io) 13 | @version: 1.0 14 | """ 15 | import sys 16 | import os 17 | import re 18 | import glob 19 | import subprocess 20 | from blinker import signal 21 | 22 | import config 23 | import delegator 24 | from .process_manager import ProcessManager 25 | 26 | PROCESSES = [{ 27 | 'command': 'nmap -Pn %(scan_mode)s -sS -oN %(output_dir)s/%(host)s-tcp-standard.txt -oG %(output_dir)s/%(host)s-tcp-greppable.txt %(host)s', 28 | 'normal': '-T4 -p- -sV', 29 | 'stealth': '-T2 -sV', 30 | }, { 31 | 'command': 'nmap -Pn %(scan_mode)s -sU --open -oN %(output_dir)s/%(host)s-udp-standard.txt -oG %(output_dir)s/%(host)s-udp-greppable.txt %(host)s', 32 | 'normal': '-T4 --top-ports 100 -sV', 33 | 'stealth': '-T2 --top-ports 10 -sV', 34 | }] 35 | 36 | # Refined regex pattern for greppable nmap output. 37 | SERVICE_PATTERN = re.compile( 38 | '\s(\d+)\/([^/]+)?\/([^/]+)?\/([^/]+)?\/([^/]+)?\/([^/]+)?\/([^/]+)?\/') 39 | 40 | # Instantiate signal to delegate further service enumeration. 41 | delegate_service_enumeration = signal('delegate_service_enumeration') 42 | delegate_service_enumeration.connect(delegator.receive_service_data) 43 | 44 | 45 | def parse_results(ip, directory): 46 | """Find greppable nmap scan output, extract service data. 47 | 48 | @param ip: IP Address 49 | 50 | @param directory: Directory to search for scan input 51 | """ 52 | 53 | # Output structure to store results 54 | results = { 55 | ip: { 56 | 'tcp': [], 57 | 'udp': [], 58 | }, 59 | } 60 | 61 | # Find greppable nmap output files 62 | scan_output = glob.glob('%s/*greppable*' % directory) 63 | for output_file in scan_output: 64 | contents = '' 65 | with open(output_file, 'r') as fh: 66 | contents = fh.read() 67 | 68 | # Locate service-related output from file contents 69 | services = SERVICE_PATTERN.findall(contents) 70 | for service_entry in services: 71 | try: 72 | port, state, protocol, owner, service, rpc_info, version = service_entry 73 | results[ip][protocol].append({ 74 | 'port': port, 75 | 'state': state, 76 | 'owner': owner, 77 | 'service': service, 78 | 'version': version, 79 | }) 80 | except Exception as exception: 81 | pass 82 | 83 | # Clean up scan files used for enumerator, standard nmap output files 84 | # can stay. 85 | os.remove(output_file) 86 | 87 | return results 88 | 89 | 90 | def scan(args): 91 | """Build output folder structure and initiate multiprocessing threads 92 | 93 | @param args: tuple containing IP address and output directory 94 | """ 95 | 96 | ip, directory = args 97 | 98 | # Ensure output directory exists; if it doesn't, create it 99 | output_dir = '%s/%s' % (directory, ip) 100 | if not os.path.exists(output_dir): 101 | os.makedirs(output_dir) 102 | 103 | print ' [-] nmap: running TCP & UDP scans for host: %s' % ip 104 | pm = ProcessManager() 105 | for process in PROCESSES: 106 | pm.start_processes(process.get('command'), params={ 107 | 'host': ip, 108 | 'output_dir': output_dir, 109 | 'scan_mode': process.get(config.mode), 110 | }) 111 | 112 | # nmap scans have completed at this point, send results to delegation 113 | # system. 114 | delegation_result = delegate_service_enumeration.send( 115 | 'enumerator.lib.nmap', scan_results=parse_results(ip, output_dir), directory=output_dir) 116 | 117 | if __name__ == '__main__': 118 | scan(sys.argv[1], sys.argv[2]) 119 | -------------------------------------------------------------------------------- /enumerator/lib/process_manager.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ProcessManager encapsulates any process- 3 | related methods required by enumerator. 4 | 5 | @author: Steve Coward (stevesugarstack.io) 6 | @version 1.0 7 | """ 8 | import subprocess 9 | from subprocess import CalledProcessError 10 | 11 | 12 | class ProcessManager(object): 13 | 14 | def start_processes(self, process, **flags): 15 | """Initiates command line processes. 16 | 17 | @param process: String value of the command 18 | to be run. 19 | 20 | @param flags: Extra values which serve to 21 | replace named parameters in the command line process 22 | as well as a flag to toggle the display of 23 | any exceptions during execution (used for debugging). 24 | """ 25 | params = flags.get('params') 26 | display_exception = flags.get('display_exception') 27 | 28 | try: 29 | devnull = open('/dev/null', 'w') 30 | subprocess.check_output( 31 | process % params, stderr=devnull, shell=True) 32 | except CalledProcessError as process_exception: 33 | print ' [!] File %s does not exist, skipping...' % process.split(' ')[0] 34 | except Exception as exception: 35 | if display_exception: 36 | print ' [!] Error running process %s' % process.split(' ')[0] 37 | print ' [!] Exception: %s' % exception 38 | else: 39 | pass 40 | -------------------------------------------------------------------------------- /enumerator/lib/services/__init__.py: -------------------------------------------------------------------------------- 1 | from .http import HttpEnumeration 2 | from .ftp import FtpEnumeration 3 | from .nbt import NbtEnumeration 4 | from .ssh import SshEnumeration 5 | from .rpc import RpcEnumeration 6 | 7 | http = HttpEnumeration() 8 | ftp = FtpEnumeration() 9 | nbt = NbtEnumeration() 10 | ssh = SshEnumeration() 11 | rpc = RpcEnumeration() 12 | 13 | service_modules = [http, ftp, nbt, ssh, rpc] 14 | -------------------------------------------------------------------------------- /enumerator/lib/services/ftp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | The FTP module performs ftp-related 4 | enumeration tasks. 5 | 6 | @author: Steve Coward (stevesugarstack.io) 7 | @version: 1.0 8 | """ 9 | import sys 10 | from .. import config 11 | from ..process_manager import ProcessManager 12 | from ..generic_service import GenericService 13 | 14 | 15 | class FtpEnumeration(GenericService, ProcessManager): 16 | SERVICE_DEFINITION = 'service:ftp' 17 | PROCESSES = [{ 18 | 'command': 'nmap -Pn -p %(port)s %(scan_mode)s \ 19 | -oN %(output_dir)s/%(host)s-ftp-%(port)s-standard.txt %(host)s', 20 | 'normal': '-T4 --script=ftp-anon,ftp-bounce,ftp-libopie,ftp-proftpd-backdoor,ftp-vsftpd-backdoor,ftp-vuln-cve2010-4221', 21 | 'stealth': '-T2', 22 | }, { 23 | 'command': 'hydra -L %(static_path)s/user-password-%(scan_mode)s.txt -P %(static_path)s/user-password-%(scan_mode)s.txt \ 24 | -o %(output_dir)s/%(host)s-ftp-%(port)s-hydra.txt ftp://%(host)s:%(port)s', 25 | 'normal': 'tiny', 26 | 'stealth': 'micro', 27 | }] 28 | 29 | def scan(self, directory, service_parameters): 30 | """Iterates over PROCESSES and builds 31 | the specific parameters required for 32 | command line execution of each process. 33 | 34 | @param directory: Directory path where 35 | final command output will go. 36 | 37 | @param service_parameters: Dictionary with 38 | key:value pairs of service-related data. 39 | """ 40 | 41 | for process in self.PROCESSES: 42 | self.start_processes(process.get('command'), params={ 43 | 'host': service_parameters.get('ip'), 44 | 'port': service_parameters.get('port'), 45 | 'output_dir': directory, 46 | 'static_path': self.static_path, 47 | 'scan_mode': process.get(config.mode), 48 | }, display_exception=False) 49 | 50 | if __name__ == '__main__': 51 | """For testing purposes, this 52 | module can be executed as a script. 53 | Use the following syntax from the root 54 | directory of enumerator: 55 | 56 | python -m lib.ftp.ftp 57 | """ 58 | ftp = FtpEnumeration() 59 | ftp.scan(sys.argv[3], dict(ip=sys.argv[1], port=sys.argv[2])) 60 | -------------------------------------------------------------------------------- /enumerator/lib/services/http.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | The HTTP module performs http-related 4 | enumeration tasks. 5 | 6 | @author: Steve Coward (stevesugarstack.io) 7 | @version: 1.0 8 | """ 9 | import sys 10 | from .. import config 11 | from ..process_manager import ProcessManager 12 | from ..generic_service import GenericService 13 | 14 | 15 | class HttpEnumeration(GenericService, ProcessManager): 16 | SERVICE_DEFINITION = 'service:http,-proxy or port:8081' 17 | PROCESSES = [{ 18 | 'command': 'nikto -F txt %(scan_mode)s -o %(output_dir)s/%(host)s-http-%(port)s-nikto.txt -h %(host)s -p %(port)s', 19 | 'normal': '', 20 | 'stealth': '-Tuning 1 2', 21 | }, { 22 | 'command': 'dirb %(url)s %(wordlist)s -o %(output_dir)s/%(host)s-http-%(port)s-dirb.txt -r -S -w %(scan_mode)s', 23 | 'normal': '', 24 | 'stealth': '-z 400', 25 | }] 26 | 27 | # TODO: Make these configurable either at runtime or via config file. 28 | # On the Kali distro, both of these files/paths exist. 29 | DIRB_WORDLISTS = '/usr/share/dirb/wordlists/common.txt,/opt/metasploit/apps/pro/msf3/data/wmap/wmap_dirs.txt' 30 | 31 | def scan(self, directory, service_parameters): 32 | """Iterates over PROCESSES and builds 33 | the specific parameters required for 34 | command line execution of each process. 35 | 36 | @param directory: Directory path where 37 | final command output will go. 38 | 39 | @param service_parameters: Dictionary with 40 | key:value pairs of service-related data. 41 | """ 42 | 43 | ip = service_parameters.get('ip') 44 | port = service_parameters.get('port') 45 | 46 | for process in self.PROCESSES: 47 | self.start_processes(process.get('command'), params={ 48 | 'host': ip, 49 | 'port': port, 50 | 'url': 'https://%s/' % ip if port == '443' else 'http://%s:%s/' % (ip, port), 51 | 'output_dir': directory, 52 | 'wordlist': self.DIRB_WORDLISTS, 53 | 'scan_mode': process.get(config.mode), 54 | }, display_exception=False) 55 | 56 | if __name__ == '__main__': 57 | """For testing purposes, this 58 | module can be executed as a script. 59 | Use the following syntax from the root 60 | directory of enumerator: 61 | 62 | python -m lib.http.http 63 | """ 64 | http = HttpEnumeration() 65 | http.scan(sys.argv[3], dict(ip=sys.argv[1], port=sys.argv[2])) 66 | -------------------------------------------------------------------------------- /enumerator/lib/services/nbt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | The Netbios module performs netbios-related 4 | enumeration tasks. 5 | 6 | @author: Steve Coward (stevesugarstack.io) 7 | @author: Erik Dominguez (maleusoverflowsecurity.com) 8 | @version: 1.0 9 | """ 10 | import sys 11 | from .. import config 12 | from ..process_manager import ProcessManager 13 | from ..generic_service import GenericService 14 | 15 | 16 | class NbtEnumeration(GenericService, ProcessManager): 17 | SERVICE_DEFINITION = 'port:139,445' 18 | PROCESSES = [{ 19 | 'command': 'enum4linux %(scan_mode)s %(host)s > %(output_dir)s/%(host)s-nbt-enum4linux.txt', 20 | 'normal': '-a', 21 | 'stealth': '-k -o', 22 | }] 23 | 24 | def scan(self, directory, service_parameters): 25 | """Iterates over PROCESSES and builds 26 | the specific parameters required for 27 | command line execution of each process. 28 | 29 | @param directory: Directory path where 30 | final command output will go. 31 | 32 | @param service_parameters: Dictionary with 33 | key:value pairs of service-related data. 34 | """ 35 | 36 | for process in self.PROCESSES: 37 | self.start_processes(process.get('command'), params={ 38 | 'host': service_parameters.get('ip'), 39 | 'output_dir': directory, 40 | 'scan_mode': process.get(config.mode), 41 | }, display_exception=False) 42 | 43 | if __name__ == '__main__': 44 | """For testing purposes, this 45 | module can be executed as a script. 46 | Use the following syntax from the root 47 | directory of enumerator: 48 | 49 | python -m lib.nbt.nbt 50 | """ 51 | nbt = NbtEnumeration() 52 | nbt.scan(sys.argv[2], dict(ip=sys.argv[1])) 53 | -------------------------------------------------------------------------------- /enumerator/lib/services/rpc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | The Rpc Bind module performs rpcbind-related 4 | enumeration tasks. 5 | 6 | @author: Erik Dominguez(maleusoverflowsecurity.com) 7 | @author: Steve Coward (stevesugarstack.io) 8 | @version: 1.0 9 | """ 10 | import sys 11 | from .. import config 12 | from ..process_manager import ProcessManager 13 | from ..generic_service import GenericService 14 | 15 | 16 | class RpcEnumeration(GenericService, ProcessManager): 17 | SERVICE_DEFINITION = 'port:111' 18 | PROCESSES = [{ 19 | 'command': 'showmount -e %(host)s > %(output_dir)s/%(host)s-rpc-showmount.txt', 20 | 'normal': '', 21 | 'stealth': '', 22 | }] 23 | 24 | def scan(self, directory, service_parameters): 25 | """Iterates over PROCESSES and builds 26 | the specific parameters required for 27 | command line execution of each process. 28 | 29 | @param directory: Directory path where 30 | final command output will go. 31 | 32 | @param service_parameters: Dictionary with 33 | key:value pairs of service-related data. 34 | """ 35 | 36 | for process in self.PROCESSES: 37 | self.start_processes(process.get('command'), params={ 38 | 'host': service_parameters.get('ip'), 39 | 'output_dir': directory, 40 | }, display_exception=False) 41 | 42 | if __name__ == '__main__': 43 | """For testing purposes, this 44 | module can be executed as a script. 45 | Use the following syntax from the root 46 | directory of enumerator: 47 | 48 | python -m lib.rpc.rpc 49 | """ 50 | rpc = RpcEnumeration() 51 | rpc.scan(sys.argv[2], dict(ip=sys.argv[1])) 52 | -------------------------------------------------------------------------------- /enumerator/lib/services/ssh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | The SSH module performs ssh-related 4 | enumeration tasks. 5 | 6 | @author: Steve Coward (stevesugarstack.io) 7 | @author: Erik Dominguez (maleusoverflowsecurity.com) 8 | @version: 1.0 9 | """ 10 | import sys 11 | from .. import config 12 | from ..process_manager import ProcessManager 13 | from ..generic_service import GenericService 14 | 15 | 16 | class SshEnumeration(GenericService, ProcessManager): 17 | SERVICE_DEFINITION = 'service:ssh' 18 | PROCESSES = [{ 19 | 'command': 'nmap -Pn -p %(port)s %(scan_mode)s \ 20 | -oN %(output_dir)s/%(host)s-ssh-%(port)s-standard.txt %(host)s', 21 | 'normal': '-T4 --script=ssh-hostkey', 22 | 'stealth': '-T2' 23 | }, { 24 | 'command': 'hydra -L %(static_path)s/user-password-%(scan_mode)s.txt -P %(static_path)s/user-password-%(scan_mode)s.txt \ 25 | -o %(output_dir)s/%(host)s-ssh-%(port)s-hydra.txt -t 4 %(host)s ssh', 26 | 'normal': 'tiny', 27 | 'stealth': 'micro', 28 | }] 29 | 30 | def scan(self, directory, service_parameters): 31 | """Iterates over PROCESSES and builds 32 | the specific parameters required for 33 | command line execution of each process. 34 | 35 | @param directory: Directory path where 36 | final command output will go. 37 | 38 | @param service_parameters: Dictionary with 39 | key:value pairs of service-related data. 40 | """ 41 | 42 | for process in self.PROCESSES: 43 | self.start_processes(process.get('command'), params={ 44 | 'host': service_parameters.get('ip'), 45 | 'port': service_parameters.get('port'), 46 | 'output_dir': directory, 47 | 'static_path': self.static_path, 48 | 'scan_mode': process.get(config.mode), 49 | }, display_exception=False) 50 | 51 | if __name__ == '__main__': 52 | """For testing purposes, this 53 | module can be executed as a script. 54 | Use the following syntax from the root 55 | directory of enumerator: 56 | 57 | python -m lib.ssh.ssh 58 | """ 59 | ssh = SshEnumeration() 60 | ssh.scan(sys.argv[3], dict(ip=sys.argv[1], port=sys.argv[2])) 61 | -------------------------------------------------------------------------------- /enumerator/static/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Maleus/Enumerator/2937d174c3c66ae6670a2375a52925be21c88fbb/enumerator/static/__init__.py -------------------------------------------------------------------------------- /enumerator/static/user-password-micro.txt: -------------------------------------------------------------------------------- 1 | root 2 | toor 3 | -------------------------------------------------------------------------------- /enumerator/static/user-password-tiny.txt: -------------------------------------------------------------------------------- 1 | root 2 | admin 3 | toor 4 | letmein 5 | changeme 6 | administrator 7 | password 8 | 1 9 | 12 10 | 123 11 | 1234 12 | 12345 13 | 123456 14 | 1234567 15 | 12345678 16 | 1234567890 17 | ftp 18 | user 19 | guest 20 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | blinker==1.3 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup( 4 | name='enumerator', 5 | version='0.1.4', 6 | author='Erik Dominguez, Steve Coward', 7 | author_email='maleus@overflowsecurity.com, steve@sugarstack.io', 8 | maintainer='Steve Coward', 9 | maintainer_email='steve@sugarstack.io', 10 | scripts=['bin/enumerator'], 11 | packages=['enumerator', 'enumerator.static', 'enumerator.lib', 'enumerator.lib.services'], 12 | package_data={ 13 | '': ['*.txt'], 14 | }, 15 | url='http://pypi.python.org/pypi/enumerator/', 16 | license='LICENSE.txt', 17 | description='enumerator is a tool built to assist in automating the often tedious task of enumerating a target or list of targets during a penetration test.', 18 | long_description=open('README.txt').read(), 19 | install_requires=[ 20 | 'blinker==1.3', 21 | ], 22 | ) 23 | --------------------------------------------------------------------------------