From f086edce346130b058b91f850f6c3506f3dc47e8 Mon Sep 17 00:00:00 2001 From: Tib3rius <48113936+Tib3rius@users.noreply.github.com> Date: Fri, 28 Oct 2022 01:41:22 -0400 Subject: [PATCH] Updated plugin check() Return value of check() will deregister the plugin if it is False. Updated several plugins which use check() to return False where appropriate. Added "Report" class to protected classes. --- autorecon/config.py | 2 +- autorecon/default-plugins/dirbuster.py | 45 +++++++++++-------- .../dnsrecon-subdomain-bruteforce.py | 1 + autorecon/default-plugins/dnsrecon.py | 1 + autorecon/default-plugins/oracle-scanner.py | 1 + autorecon/default-plugins/oracle-tnscmd.py | 1 + autorecon/default-plugins/redis-cli.py | 1 + autorecon/default-plugins/wkhtmltoimage.py | 1 + autorecon/main.py | 11 +++-- pyproject.toml | 2 +- 10 files changed, 41 insertions(+), 25 deletions(-) diff --git a/autorecon/config.py b/autorecon/config.py index d4004e9..c8162ce 100644 --- a/autorecon/config.py +++ b/autorecon/config.py @@ -42,7 +42,7 @@ configurable_boolean_keys = [ ] config = { - 'protected_classes': ['autorecon', 'target', 'service', 'commandstreamreader', 'plugin', 'portscan', 'servicescan', 'global', 'pattern'], + 'protected_classes': ['autorecon', 'target', 'service', 'commandstreamreader', 'plugin', 'portscan', 'report', 'servicescan', 'global', 'pattern'], 'service_exceptions': ['mc-nmf', 'ncacn_http', 'smux', 'status', 'tcpwrapped', 'unknown'], 'config_dir': config_dir, 'global_file': None, diff --git a/autorecon/default-plugins/dirbuster.py b/autorecon/default-plugins/dirbuster.py index 99cd998..4180f19 100644 --- a/autorecon/default-plugins/dirbuster.py +++ b/autorecon/default-plugins/dirbuster.py @@ -18,63 +18,70 @@ class DirBuster(ServiceScan): self.add_option('threads', default=10, help='The number of threads to use when directory busting. Default: %(default)s') self.add_option('ext', default='txt,html,php,asp,aspx,jsp', help='The extensions you wish to fuzz (no dot, comma separated). Default: %(default)s') self.add_true_option('recursive', help='Enables recursive searching (where available). Warning: This may cause significant increases to scan times. Default: %(default)s') + self.add_option('extras', default='', help='Any extra options you wish to pass to the tool when it runs. e.g. --dirbuster.extras=\'-s 200,301 --discover-backup\'') self.match_service_name('^http') self.match_service_name('^nacn_http$', negative_match=True) def check(self): tool = self.get_option('tool') - if tool == 'feroxbuster': - if which('feroxbuster') is None: - self.error('The feroxbuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install feroxbuster)') - elif tool == 'gobuster': - if which('gobuster') is None: - self.error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)') - elif tool == 'dirsearch': - if which('dirsearch') is None: - self.error('The dirsearch program could not be found. Make sure it is installed. (On Kali, run: sudo apt install dirsearch)') + if tool == 'feroxbuster' and which('feroxbuster') is None: + self.error('The feroxbuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install feroxbuster)') + return False + elif tool == 'gobuster' and which('gobuster') is None: + self.error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)') + return False + elif tool == 'dirsearch' and which('dirsearch') is None: + self.error('The dirsearch program could not be found. Make sure it is installed. (On Kali, run: sudo apt install dirsearch)') + return False + elif tool == 'ffuf' and which('ffuf') is None: + self.error('The ffuf program could not be found. Make sure it is installed. (On Kali, run: sudo apt install ffuf)') + return False + elif tool == 'dirb' and which('dirb') is None: + self.error('The dirb program could not be found. Make sure it is installed. (On Kali, run: sudo apt install dirb)') + return False async def run(self, service): dot_extensions = ','.join(['.' + x for x in self.get_option('ext').split(',')]) for wordlist in self.get_option('wordlist'): name = os.path.splitext(os.path.basename(wordlist))[0] if self.get_option('tool') == 'feroxbuster': - await service.execute('feroxbuster -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -x "' + self.get_option('ext') + '" -v -k ' + ('' if self.get_option('recursive') else '-n ') + '-q -e -o "{scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_' + name + '.txt"') + await service.execute('feroxbuster -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -x "' + self.get_option('ext') + '" -v -k ' + ('' if self.get_option('recursive') else '-n ') + '-q -e -o "{scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_' + name + '.txt"' + (' ' + self.get_option('extras') if self.get_option('extras') else '')) elif self.get_option('tool') == 'gobuster': - await service.execute('gobuster dir -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -e -k -x "' + self.get_option('ext') + '" -z -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_' + name + '.txt"') + await service.execute('gobuster dir -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -e -k -x "' + self.get_option('ext') + '" -z -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_' + name + '.txt"' + (' ' + self.get_option('extras') if self.get_option('extras') else '')) elif self.get_option('tool') == 'dirsearch': if service.target.ipversion == 'IPv6': service.error('dirsearch does not support IPv6.') else: - await service.execute('dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -e "' + self.get_option('ext') + '" -f -q ' + ('-r ' if self.get_option('recursive') else '') + '-w ' + wordlist + ' --format=plain -o "{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_' + name + '.txt"') + await service.execute('dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -e "' + self.get_option('ext') + '" -f -q ' + ('-r ' if self.get_option('recursive') else '') + '-w ' + wordlist + ' --format=plain -o "{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_' + name + '.txt"' + (' ' + self.get_option('extras') if self.get_option('extras') else '')) elif self.get_option('tool') == 'ffuf': - await service.execute('ffuf -u {http_scheme}://{addressv6}:{port}/FUZZ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -e "' + dot_extensions + '" -v ' + ('-recursion ' if self.get_option('recursive') else '') + '-noninteractive | tee {scandir}/{protocol}_{port}_{http_scheme}_ffuf_' + name + '.txt') + await service.execute('ffuf -u {http_scheme}://{addressv6}:{port}/FUZZ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -e "' + dot_extensions + '" -v ' + ('-recursion ' if self.get_option('recursive') else '') + '-noninteractive' + (' ' + self.get_option('extras') if self.get_option('extras') else '') + ' | tee {scandir}/{protocol}_{port}_{http_scheme}_ffuf_' + name + '.txt') elif self.get_option('tool') == 'dirb': - await service.execute('dirb {http_scheme}://{addressv6}:{port}/ ' + wordlist + ' -l ' + ('' if self.get_option('recursive') else '-r ') + '-S -X ",' + dot_extensions + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_dirb_' + name + '.txt"') + await service.execute('dirb {http_scheme}://{addressv6}:{port}/ ' + wordlist + ' -l ' + ('' if self.get_option('recursive') else '-r ') + '-S -X ",' + dot_extensions + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_dirb_' + name + '.txt"' + (' ' + self.get_option('extras') if self.get_option('extras') else '')) def manual(self, service, plugin_was_run): dot_extensions = ','.join(['.' + x for x in self.get_option('ext').split(',')]) if self.get_option('tool') == 'feroxbuster': service.add_manual_command('(feroxbuster) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [ - 'feroxbuster -u {http_scheme}://{addressv6}:{port} -t ' + str(self.get_option('threads')) + ' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x "' + self.get_option('ext') + '" -v -k ' + ('' if self.get_option('recursive') else '-n ') + '-e -o {scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_dirbuster.txt' + 'feroxbuster -u {http_scheme}://{addressv6}:{port} -t ' + str(self.get_option('threads')) + ' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x "' + self.get_option('ext') + '" -v -k ' + ('' if self.get_option('recursive') else '-n ') + '-e -o {scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_dirbuster.txt' + (' ' + self.get_option('extras') if self.get_option('extras') else '') ]) elif self.get_option('tool') == 'gobuster': service.add_manual_command('(gobuster v3) Multi-threaded directory/file enumeration for web servers using various wordlists:', [ - 'gobuster dir -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -e -k -x "' + self.get_option('ext') + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_dirbuster.txt"' + 'gobuster dir -u {http_scheme}://{addressv6}:{port}/ -t ' + str(self.get_option('threads')) + ' -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -e -k -x "' + self.get_option('ext') + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_dirbuster.txt"' + (' ' + self.get_option('extras') if self.get_option('extras') else '') ]) elif self.get_option('tool') == 'dirsearch': if service.target.ipversion == 'IPv4': service.add_manual_command('(dirsearch) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [ - 'dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -e "' + self.get_option('ext') + '" -f ' + ('-r ' if self.get_option('recursive') else '') + '-w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --format=plain --output="{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_dirbuster.txt"' + 'dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -e "' + self.get_option('ext') + '" -f ' + ('-r ' if self.get_option('recursive') else '') + '-w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --format=plain --output="{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_dirbuster.txt"' + (' ' + self.get_option('extras') if self.get_option('extras') else '') ]) elif self.get_option('tool') == 'ffuf': service.add_manual_command('(ffuf) Multi-threaded recursive directory/file enumeration for web servers using various wordlists:', [ - 'ffuf -u {http_scheme}://{addressv6}:{port}/FUZZ -t ' + str(self.get_option('threads')) + ' -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -e "' + dot_extensions + '" -v ' + ('-recursion ' if self.get_option('recursive') else '') + '-noninteractive | tee {scandir}/{protocol}_{port}_{http_scheme}_ffuf_dirbuster.txt' + 'ffuf -u {http_scheme}://{addressv6}:{port}/FUZZ -t ' + str(self.get_option('threads')) + ' -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -e "' + dot_extensions + '" -v ' + ('-recursion ' if self.get_option('recursive') else '') + '-noninteractive' + (' ' + self.get_option('extras') if self.get_option('extras') else '') + ' | tee {scandir}/{protocol}_{port}_{http_scheme}_ffuf_dirbuster.txt' ]) elif self.get_option('tool') == 'dirb': service.add_manual_command('(dirb) Recursive directory/file enumeration for web servers using various wordlists:', [ - 'dirb {http_scheme}://{addressv6}:{port}/ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -l ' + ('' if self.get_option('recursive') else '-r ') + '-X ",' + dot_extensions + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_dirb_dirbuster.txt"' + 'dirb {http_scheme}://{addressv6}:{port}/ /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -l ' + ('' if self.get_option('recursive') else '-r ') + '-X ",' + dot_extensions + '" -o "{scandir}/{protocol}_{port}_{http_scheme}_dirb_dirbuster.txt"' + (' ' + self.get_option('extras') if self.get_option('extras') else '') ]) diff --git a/autorecon/default-plugins/dnsrecon-subdomain-bruteforce.py b/autorecon/default-plugins/dnsrecon-subdomain-bruteforce.py index b9306fb..8f082bb 100644 --- a/autorecon/default-plugins/dnsrecon-subdomain-bruteforce.py +++ b/autorecon/default-plugins/dnsrecon-subdomain-bruteforce.py @@ -16,6 +16,7 @@ class DnsReconSubdomainBruteforce(ServiceScan): def check(self): if which('dnsrecon') is None: self.error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)') + return False def manual(self, service, plugin_was_run): domain_name = '' diff --git a/autorecon/default-plugins/dnsrecon.py b/autorecon/default-plugins/dnsrecon.py index f53c51d..cfb9edc 100644 --- a/autorecon/default-plugins/dnsrecon.py +++ b/autorecon/default-plugins/dnsrecon.py @@ -16,6 +16,7 @@ class DnsRecon(ServiceScan): def check(self): if which('dnsrecon') is None: self.error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)') + return False def manual(self, service, plugin_was_run): service.add_manual_command('Use dnsrecon to automatically query data from the DNS server. You must specify the target domain name.', [ diff --git a/autorecon/default-plugins/oracle-scanner.py b/autorecon/default-plugins/oracle-scanner.py index c610420..16653cc 100644 --- a/autorecon/default-plugins/oracle-scanner.py +++ b/autorecon/default-plugins/oracle-scanner.py @@ -14,6 +14,7 @@ class OracleScanner(ServiceScan): def check(self): if which('oscanner') is None: self.error('The oscanner program could not be found. Make sure it is installed. (On Kali, run: sudo apt install oscanner)') + return False async def run(self, service): await service.execute('oscanner -v -s {address} -P {port} 2>&1', outfile='{protocol}_{port}_oracle_scanner.txt') diff --git a/autorecon/default-plugins/oracle-tnscmd.py b/autorecon/default-plugins/oracle-tnscmd.py index b43ec12..7ea12c1 100644 --- a/autorecon/default-plugins/oracle-tnscmd.py +++ b/autorecon/default-plugins/oracle-tnscmd.py @@ -14,6 +14,7 @@ class OracleTNScmd(ServiceScan): def check(self): if which('tnscmd10g') is None: self.error('The tnscmd10g program could not be found. Make sure it is installed. (On Kali, run: sudo apt install tnscmd10g)') + return False async def run(self, service): if service.target.ipversion == 'IPv4': diff --git a/autorecon/default-plugins/redis-cli.py b/autorecon/default-plugins/redis-cli.py index a6f6c79..74b3803 100644 --- a/autorecon/default-plugins/redis-cli.py +++ b/autorecon/default-plugins/redis-cli.py @@ -14,6 +14,7 @@ class RedisCli(ServiceScan): def check(self): if which('redis-cli') is None: self.error('The redis-cli program could not be found. Make sure it is installed. (On Kali, run: sudo apt install redis-tools)') + return False async def run(self, service): if which('redis-cli') is not None: diff --git a/autorecon/default-plugins/wkhtmltoimage.py b/autorecon/default-plugins/wkhtmltoimage.py index 7c4890a..d4d30ba 100644 --- a/autorecon/default-plugins/wkhtmltoimage.py +++ b/autorecon/default-plugins/wkhtmltoimage.py @@ -15,6 +15,7 @@ class WkHTMLToImage(ServiceScan): def check(self): if which('wkhtmltoimage') is None: self.error('The wkhtmltoimage program could not be found. Make sure it is installed. (On Kali, run: sudo apt install wkhtmltopdf)') + return False async def run(self, service): if which('wkhtmltoimage') is not None: diff --git a/autorecon/main.py b/autorecon/main.py index dbbec42..5faa654 100644 --- a/autorecon/main.py +++ b/autorecon/main.py @@ -17,7 +17,7 @@ from autorecon.io import slugify, e, fformat, cprint, debug, info, warn, error, from autorecon.plugins import Pattern, PortScan, ServiceScan, Report, AutoRecon from autorecon.targets import Target, Service -VERSION = "2.0.26" +VERSION = "2.0.27" if not os.path.exists(config['config_dir']): shutil.rmtree(config['config_dir'], ignore_errors=True, onerror=None) @@ -809,7 +809,7 @@ async def run(): else: config['plugins_dir'] = None - parser = argparse.ArgumentParser(add_help=False, description='Network reconnaissance tool to port scan and automatically enumerate services found on multiple targets.') + parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False, description='Network reconnaissance tool to port scan and automatically enumerate services found on multiple targets.') parser.add_argument('targets', action='store', help='IP addresses (e.g. 10.0.0.1), CIDR notation (e.g. 10.0.0.1/24), or resolvable hostnames (e.g. foo.bar) to scan.', nargs='*') parser.add_argument('-t', '--target-file', action='store', type=str, default='', help='Read targets from file.') parser.add_argument('-p', '--ports', action='store', type=str, help='Comma separated list of ports / port ranges to scan. Specify TCP/UDP ports by prepending list with T:/U: To scan both TCP/UDP, put port(s) at start or specify B: e.g. 53,T:21-25,80,U:123,B:123. Default: %(default)s') @@ -1081,6 +1081,7 @@ async def run(): autorecon.argparse.set_defaults(**{key: val}) parser.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS, help='Show this help message and exit.') + parser.error = lambda s: fail(s[0].upper() + s[1:]) args = parser.parse_args() args_dict = vars(args) @@ -1138,7 +1139,7 @@ async def run(): else: error('Invalid value provided to --max-plugin-global-instances. Values must be in the format PLUGIN:NUMBER.') - for plugin in autorecon.plugins.values(): + for slug, plugin in autorecon.plugins.items(): if hasattr(plugin, 'max_target_instances') and plugin.slug in max_plugin_target_instances: plugin.max_target_instances = max_plugin_target_instances[plugin.slug] @@ -1147,7 +1148,9 @@ async def run(): for member_name, _ in inspect.getmembers(plugin, predicate=inspect.ismethod): if member_name == 'check': - plugin.check() + if plugin.check() == False: + autorecon.plugins.pop(slug) + continue continue if config['ports']: diff --git a/pyproject.toml b/pyproject.toml index ab8ec7e..9e5d658 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "autorecon" -version = "2.0.26" +version = "2.0.27" description = "A multi-threaded network reconnaissance tool which performs automated enumeration of services." authors = ["Tib3rius"] license = "GNU GPL v3"