I/O Updates, New Subdomain Enumeration Plugin
Plugins can now call info(), warn(), and error() functions from their service / target object which will properly prefix the plugin name, etc. A new subdomain enumeration plugin using gobuster has been developed.
This commit is contained in:
parent
fbe3fb48c3
commit
4912a235ad
|
|
@ -1,5 +1,4 @@
|
||||||
from autorecon.plugins import ServiceScan
|
from autorecon.plugins import ServiceScan
|
||||||
from autorecon.io import error
|
|
||||||
from shutil import which
|
from shutil import which
|
||||||
|
|
||||||
class NmapMongoDB(ServiceScan):
|
class NmapMongoDB(ServiceScan):
|
||||||
|
|
@ -77,7 +76,7 @@ class OracleTNScmd(ServiceScan):
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
if which('tnscmd10g') is None:
|
if which('tnscmd10g') is None:
|
||||||
error('The tnscmd10g program could not be found. Make sure it is installed. (On Kali, run: sudo apt install tnscmd10g)')
|
self.error('The tnscmd10g program could not be found. Make sure it is installed. (On Kali, run: sudo apt install tnscmd10g)')
|
||||||
|
|
||||||
async def run(self, service):
|
async def run(self, service):
|
||||||
if service.target.ipversion == 'IPv4':
|
if service.target.ipversion == 'IPv4':
|
||||||
|
|
@ -96,7 +95,7 @@ class OracleScanner(ServiceScan):
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
if which('oscanner') is None:
|
if which('oscanner') is None:
|
||||||
error('The oscanner program could not be found. Make sure it is installed. (On Kali, run: sudo apt install oscanner)')
|
self.error('The oscanner program could not be found. Make sure it is installed. (On Kali, run: sudo apt install oscanner)')
|
||||||
|
|
||||||
async def run(self, service):
|
async def run(self, service):
|
||||||
await service.execute('oscanner -v -s {address} -P {port} 2>&1', outfile='{protocol}_{port}_oracle_scanner.txt')
|
await service.execute('oscanner -v -s {address} -P {port} 2>&1', outfile='{protocol}_{port}_oracle_scanner.txt')
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
from autorecon.plugins import PortScan
|
from autorecon.plugins import PortScan
|
||||||
from autorecon.io import info, error
|
|
||||||
from autorecon.config import config
|
from autorecon.config import config
|
||||||
import os, re
|
import os, re
|
||||||
|
|
||||||
|
|
@ -56,7 +55,7 @@ class AllTCPPortScan(PortScan):
|
||||||
if line is not None:
|
if line is not None:
|
||||||
match = re.search('^Discovered open port ([0-9]+)/tcp', line)
|
match = re.search('^Discovered open port ([0-9]+)/tcp', line)
|
||||||
if match:
|
if match:
|
||||||
info('Discovered open port {bmagenta}tcp/' + match.group(1) + '{rst} on {byellow}' + target.address + '{rst}', verbosity=1)
|
target.info('Discovered open port {bmagenta}tcp/' + match.group(1) + '{rst} on {byellow}' + target.address + '{rst}', verbosity=1)
|
||||||
service = target.extract_service(line)
|
service = target.extract_service(line)
|
||||||
if service:
|
if service:
|
||||||
services.append(service)
|
services.append(service)
|
||||||
|
|
@ -91,7 +90,7 @@ class Top100UDPPortScan(PortScan):
|
||||||
if line is not None:
|
if line is not None:
|
||||||
match = re.search('^Discovered open port ([0-9]+)/udp', line)
|
match = re.search('^Discovered open port ([0-9]+)/udp', line)
|
||||||
if match:
|
if match:
|
||||||
info('Discovered open port {bmagenta}udp/' + match.group(1) + '{rst} on {byellow}' + target.address + '{rst}', verbosity=1)
|
target.info('Discovered open port {bmagenta}udp/' + match.group(1) + '{rst} on {byellow}' + target.address + '{rst}', verbosity=1)
|
||||||
service = target.extract_service(line)
|
service = target.extract_service(line)
|
||||||
if service:
|
if service:
|
||||||
services.append(service)
|
services.append(service)
|
||||||
|
|
@ -100,4 +99,4 @@ class Top100UDPPortScan(PortScan):
|
||||||
await process.wait()
|
await process.wait()
|
||||||
return services
|
return services
|
||||||
else:
|
else:
|
||||||
error('UDP scan requires AutoRecon be run with root privileges.')
|
target.error('UDP scan requires AutoRecon be run with root privileges.')
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from autorecon.plugins import ServiceScan
|
from autorecon.plugins import ServiceScan
|
||||||
from autorecon.io import error
|
|
||||||
from shutil import which
|
from shutil import which
|
||||||
|
import os
|
||||||
|
|
||||||
class NmapDNS(ServiceScan):
|
class NmapDNS(ServiceScan):
|
||||||
|
|
||||||
|
|
@ -61,51 +61,83 @@ class NmapMulticastDNS(ServiceScan):
|
||||||
|
|
||||||
class DnsReconDefault(ServiceScan):
|
class DnsReconDefault(ServiceScan):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.name = "DnsRecon Default Scan"
|
self.name = "DnsRecon Default Scan"
|
||||||
self.slug = 'dnsrecon'
|
self.slug = 'dnsrecon'
|
||||||
self.priority = 0
|
self.priority = 0
|
||||||
self.tags = ['default', 'safe', 'dns']
|
self.tags = ['default', 'safe', 'dns']
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
self.match_service_name('^domain')
|
self.match_service_name('^domain')
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
if which('dnsrecon') is None:
|
if which('dnsrecon') is None:
|
||||||
error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)')
|
self.error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)')
|
||||||
|
|
||||||
def manual(self, service, plugin_was_run):
|
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.', [
|
service.add_manual_command('Use dnsrecon to automatically query data from the DNS server. You must specify the target domain name.', [
|
||||||
'dnsrecon -n {address} -d <DOMAIN-NAME> 2>&1 | tee {scandir}/{protocol}_{port}_dnsrecon_default_manual.txt'
|
'dnsrecon -n {address} -d <DOMAIN-NAME> 2>&1 | tee {scandir}/{protocol}_{port}_dnsrecon_default_manual.txt'
|
||||||
])
|
])
|
||||||
|
|
||||||
async def run(self, service):
|
async def run(self, service):
|
||||||
if self.get_global('domain'):
|
if self.get_global('domain'):
|
||||||
await service.execute('dnsrecon -n {address} -d ' + self.get_global('domain') + ' 2>&1', outfile='{protocol}_{port}_dnsrecon_default.txt')
|
await service.execute('dnsrecon -n {address} -d ' + self.get_global('domain') + ' 2>&1', outfile='{protocol}_{port}_dnsrecon_default.txt')
|
||||||
else:
|
else:
|
||||||
error('A domain name was not specified in the command line options (--global.domain). If you know the domain name, look in the _manual_commands.txt file for the dnsrecon command.')
|
service.error('A domain name was not specified in the command line options (--global.domain). If you know the domain name, look in the _manual_commands.txt file for the dnsrecon command.')
|
||||||
|
|
||||||
class DnsReconSubdomainBruteforce(ServiceScan):
|
class DnsReconSubdomainBruteforce(ServiceScan):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.name = "DnsRecon Bruteforce Subdomains"
|
self.name = "DnsRecon Bruteforce Subdomains"
|
||||||
self.slug = 'dnsrecon-brute'
|
self.slug = 'dnsrecon-brute'
|
||||||
self.priority = 0
|
self.priority = 0
|
||||||
self.tags = ['default', 'safe', 'long', 'dns']
|
self.tags = ['default', 'safe', 'long', 'dns']
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
self.match_service_name('^domain')
|
self.match_service_name('^domain')
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
if which('dnsrecon') is None:
|
if which('dnsrecon') is None:
|
||||||
error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)')
|
self.error('The program dnsrecon could not be found. Make sure it is installed. (On Kali, run: sudo apt install dnsrecon)')
|
||||||
|
|
||||||
def manual(self, service, plugin_was_run):
|
def manual(self, service, plugin_was_run):
|
||||||
domain_name = '<DOMAIN-NAME>'
|
domain_name = '<DOMAIN-NAME>'
|
||||||
if self.get_global('domain'):
|
if self.get_global('domain'):
|
||||||
domain_name = self.get_global('domain')
|
domain_name = self.get_global('domain')
|
||||||
service.add_manual_command('Use dnsrecon to bruteforce subdomains of a DNS domain.', [
|
service.add_manual_command('Use dnsrecon to bruteforce subdomains of a DNS domain.', [
|
||||||
'dnsrecon -n {address} -d ' + domain_name + ' -D /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -t brt 2>&1 | tee {scandir}/{protocol}_{port}_dnsrecon_subdomain_bruteforce.txt',
|
'dnsrecon -n {address} -d ' + domain_name + ' -D /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -t brt 2>&1 | tee {scandir}/{protocol}_{port}_dnsrecon_subdomain_bruteforce.txt',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
class SubdomainEnumeration(ServiceScan):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.name = "Subdomain Enumeration"
|
||||||
|
self.slug = "subdomain-enum"
|
||||||
|
self.tags = ['default', 'safe', 'long', 'dns']
|
||||||
|
|
||||||
|
def configure(self):
|
||||||
|
self.add_option('domain', help='The domain to use as the base domain (e.g. example.com) for subdomain enumeration. Default: %(default)s')
|
||||||
|
self.add_list_option('wordlist', default=['/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt'], help='The wordlist(s) to use when enumerating subdomains. Separate multiple wordlists with spaces. Default: %(default)s')
|
||||||
|
self.add_option('threads', default=10, help='The number of threads to use when enumerating subdomains. Default: %(default)s')
|
||||||
|
self.match_service_name('^domain')
|
||||||
|
|
||||||
|
async def run(self, service):
|
||||||
|
domains = []
|
||||||
|
|
||||||
|
if self.get_option('domain'):
|
||||||
|
domains.append(self.get_option('domain'))
|
||||||
|
if service.target.type == 'hostname' and service.target.address not in domains:
|
||||||
|
domains.append(service.target.address)
|
||||||
|
if self.get_global('domain') and self.get_global('domain') not in domains:
|
||||||
|
domains.append(self.get_global('domain'))
|
||||||
|
|
||||||
|
if len(domains) > 0:
|
||||||
|
for wordlist in self.get_option('wordlist'):
|
||||||
|
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||||
|
for domain in domains:
|
||||||
|
await service.execute('gobuster dns -d ' + domain + ' -r {addressv6} -w ' + wordlist + ' -o "{scandir}/{protocol}_{port}_' + domain + '_subdomains_' + name + '.txt"')
|
||||||
|
else:
|
||||||
|
service.info('The target was not a domain, nor was a domain provided as an option. Skipping subdomain enumeration.')
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from autorecon.plugins import ServiceScan
|
from autorecon.plugins import ServiceScan
|
||||||
from autorecon.io import error, info, fformat
|
from autorecon.io import fformat
|
||||||
from autorecon.config import config
|
from autorecon.config import config
|
||||||
from shutil import which
|
from shutil import which
|
||||||
import os
|
import os
|
||||||
|
|
@ -78,7 +78,7 @@ class CurlRobots(ServiceScan):
|
||||||
with open(filename, mode='wt', encoding='utf8') as robots:
|
with open(filename, mode='wt', encoding='utf8') as robots:
|
||||||
robots.write('\n'.join(lines))
|
robots.write('\n'.join(lines))
|
||||||
else:
|
else:
|
||||||
info('{bblue}[' + fformat('{tag}') + ']{rst} There did not appear to be a robots.txt file in the webroot (/).')
|
service.info('{bblue}[' + fformat('{tag}') + ']{rst} There did not appear to be a robots.txt file in the webroot (/).')
|
||||||
|
|
||||||
class CurlKnownSecurity(ServiceScan):
|
class CurlKnownSecurity(ServiceScan):
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ class CurlKnownSecurity(ServiceScan):
|
||||||
with open(filename, mode='wt', encoding='utf8') as robots:
|
with open(filename, mode='wt', encoding='utf8') as robots:
|
||||||
robots.write('\n'.join(lines))
|
robots.write('\n'.join(lines))
|
||||||
else:
|
else:
|
||||||
info('{bblue}[' + fformat('{tag}') + ']{rst} There did not appear to be a .well-known/security.txt file in the webroot (/).')
|
service.info('{bblue}[' + fformat('{tag}') + ']{rst} There did not appear to be a .well-known/security.txt file in the webroot (/).')
|
||||||
|
|
||||||
|
|
||||||
class DirBuster(ServiceScan):
|
class DirBuster(ServiceScan):
|
||||||
|
|
@ -126,25 +126,25 @@ class DirBuster(ServiceScan):
|
||||||
tool = self.get_option('tool')
|
tool = self.get_option('tool')
|
||||||
if tool == 'feroxbuster':
|
if tool == 'feroxbuster':
|
||||||
if which('feroxbuster') is None:
|
if which('feroxbuster') is None:
|
||||||
error('The feroxbuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install feroxbuster)')
|
self.error('The feroxbuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install feroxbuster)')
|
||||||
elif tool == 'gobuster':
|
elif tool == 'gobuster':
|
||||||
if which('gobuster') is None:
|
if which('gobuster') is None:
|
||||||
error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)')
|
self.error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)')
|
||||||
elif tool == 'dirsearch':
|
elif tool == 'dirsearch':
|
||||||
if which('dirsearch') is None:
|
if which('dirsearch') is None:
|
||||||
error('The dirsearch program could not be found. Make sure it is installed. (On Kali, run: sudo apt install dirsearch)')
|
self.error('The dirsearch program could not be found. Make sure it is installed. (On Kali, run: sudo apt install dirsearch)')
|
||||||
|
|
||||||
async def run(self, service):
|
async def run(self, service):
|
||||||
dot_extensions = ','.join(['.' + x for x in self.get_option('ext').split(',')])
|
dot_extensions = ','.join(['.' + x for x in self.get_option('ext').split(',')])
|
||||||
for wordlist in self.get_option('wordlist'):
|
for wordlist in self.get_option('wordlist'):
|
||||||
name = os.path.splitext(os.path.basename(wordlist))[0]
|
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||||
if self.get_option('tool') == 'feroxbuster':
|
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 -n -q -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 -n -q -e -o "{scandir}/{protocol}_{port}_{http_scheme}_feroxbuster_' + name + '.txt"')
|
||||||
elif self.get_option('tool') == 'gobuster':
|
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 -d -o "{scandir}/{protocol}_{port}_{http_scheme}_gobuster_' + name + '.txt"')
|
||||||
elif self.get_option('tool') == 'dirsearch':
|
elif self.get_option('tool') == 'dirsearch':
|
||||||
if service.target.ipversion == 'IPv6':
|
if service.target.ipversion == 'IPv6':
|
||||||
error('dirsearch does not support IPv6.')
|
service.error('dirsearch does not support IPv6.')
|
||||||
else:
|
else:
|
||||||
await service.execute('dirsearch -u {http_scheme}://{address}:{port}/ -t ' + str(self.get_option('threads')) + ' -e "' + self.get_option('ext') + '" -f -q -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 -w ' + wordlist + ' --format=plain -o "{scandir}/{protocol}_{port}_{http_scheme}_dirsearch_' + name + '.txt"')
|
||||||
elif self.get_option('tool') == 'ffuf':
|
elif self.get_option('tool') == 'ffuf':
|
||||||
|
|
@ -191,6 +191,42 @@ class Nikto(ServiceScan):
|
||||||
if service.target.ipversion == 'IPv4':
|
if service.target.ipversion == 'IPv4':
|
||||||
service.add_manual_command('(nikto) old but generally reliable web server enumeration tool:', 'nikto -ask=no -h {http_scheme}://{address}:{port} 2>&1 | tee "{scandir}/{protocol}_{port}_{http_scheme}_nikto.txt"')
|
service.add_manual_command('(nikto) old but generally reliable web server enumeration tool:', 'nikto -ask=no -h {http_scheme}://{address}:{port} 2>&1 | tee "{scandir}/{protocol}_{port}_{http_scheme}_nikto.txt"')
|
||||||
|
|
||||||
|
class VirtualHost(ServiceScan):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.name = 'Virtual Host Enumeration'
|
||||||
|
self.slug = 'vhost-enum'
|
||||||
|
self.tags = ['default', 'safe', 'http', 'long']
|
||||||
|
|
||||||
|
def configure(self):
|
||||||
|
self.add_option('hostname', help='The hostname to use as the base host (e.g. example.com) for virtual host enumeration. Default: %(default)s')
|
||||||
|
self.add_list_option('wordlist', default=['/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt'], help='The wordlist(s) to use when enumerating virtual hosts. Separate multiple wordlists with spaces. Default: %(default)s')
|
||||||
|
self.add_option('threads', default=10, help='The number of threads to use when enumerating virtual hosts. Default: %(default)s')
|
||||||
|
self.match_service_name('^http')
|
||||||
|
self.match_service_name('^nacn_http$', negative_match=True)
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
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)')
|
||||||
|
|
||||||
|
async def run(self, service):
|
||||||
|
hostnames = []
|
||||||
|
if self.get_option('hostname'):
|
||||||
|
hostnames.append(self.get_option('hostname'))
|
||||||
|
if service.target.type == 'hostname' and service.target.address not in hostnames:
|
||||||
|
hostnames.append(service.target.address)
|
||||||
|
if self.get_global('domain') and self.get_global('domain') not in hostnames:
|
||||||
|
hostnames.append(self.get_global('domain'))
|
||||||
|
|
||||||
|
if len(hostnames) > 0:
|
||||||
|
for wordlist in self.get_option('wordlist'):
|
||||||
|
name = os.path.splitext(os.path.basename(wordlist))[0]
|
||||||
|
for hostname in hostnames:
|
||||||
|
await service.execute('gobuster vhost -u {http_scheme}://' + hostname + ':{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -r -o "{scandir}/{protocol}_{port}_{http_scheme}_' + hostname + '_vhosts_' + name + '.txt"')
|
||||||
|
else:
|
||||||
|
service.info('The target was not a hostname, nor was a hostname provided as an option. Skipping virtual host enumeration.')
|
||||||
|
|
||||||
class WhatWeb(ServiceScan):
|
class WhatWeb(ServiceScan):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -219,7 +255,7 @@ class WkHTMLToImage(ServiceScan):
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
if which('wkhtmltoimage') is None:
|
if which('wkhtmltoimage') is None:
|
||||||
error('The wkhtmltoimage program could not be found. Make sure it is installed. (On Kali, run: sudo apt install wkhtmltopdf)')
|
self.error('The wkhtmltoimage program could not be found. Make sure it is installed. (On Kali, run: sudo apt install wkhtmltopdf)')
|
||||||
|
|
||||||
async def run(self, service):
|
async def run(self, service):
|
||||||
if which('wkhtmltoimage') is not None:
|
if which('wkhtmltoimage') is not None:
|
||||||
|
|
@ -239,37 +275,3 @@ class WPScan(ServiceScan):
|
||||||
|
|
||||||
def manual(self, service, plugin_was_run):
|
def manual(self, service, plugin_was_run):
|
||||||
service.add_manual_command('(wpscan) WordPress Security Scanner (useful if WordPress is found):', 'wpscan --url {http_scheme}://{addressv6}:{port}/ --no-update -e vp,vt,tt,cb,dbe,u,m --plugins-detection aggressive --plugins-version-detection aggressive -f cli-no-color 2>&1 | tee "{scandir}/{protocol}_{port}_{http_scheme}_wpscan.txt"')
|
service.add_manual_command('(wpscan) WordPress Security Scanner (useful if WordPress is found):', 'wpscan --url {http_scheme}://{addressv6}:{port}/ --no-update -e vp,vt,tt,cb,dbe,u,m --plugins-detection aggressive --plugins-version-detection aggressive -f cli-no-color 2>&1 | tee "{scandir}/{protocol}_{port}_{http_scheme}_wpscan.txt"')
|
||||||
|
|
||||||
class VirtualHost(ServiceScan):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.name = 'Virtual Host Enumeration'
|
|
||||||
self.slug = 'vhost-enum'
|
|
||||||
self.tags = ['default', 'safe', 'http', 'long']
|
|
||||||
|
|
||||||
def configure(self):
|
|
||||||
self.add_option('hostname', help='The hostname to use as the base host (e.g. example.com) for virtual host enumeration. Default: %(default)s')
|
|
||||||
self.add_list_option('wordlist', default=['/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt'], help='The wordlist(s) to use when enumerating virtual hosts. Separate multiple wordlists with spaces. Default: %(default)s')
|
|
||||||
self.add_option('threads', default=10, help='The number of threads to use when enumerating virtual hosts. Default: %(default)s')
|
|
||||||
self.match_service_name('^http')
|
|
||||||
self.match_service_name('^nacn_http$', negative_match=True)
|
|
||||||
|
|
||||||
def check(self):
|
|
||||||
if which('gobuster') is None:
|
|
||||||
error('The gobuster program could not be found. Make sure it is installed. (On Kali, run: sudo apt install gobuster)')
|
|
||||||
|
|
||||||
async def run(self, service):
|
|
||||||
if service.target.type == 'hostname' or self.get_option('hostname') or self.get_global('domain'):
|
|
||||||
if self.get_option('hostname'):
|
|
||||||
hostname = self.get_option('hostname')
|
|
||||||
elif service.target.type == 'hostname':
|
|
||||||
hostname = service.target.address
|
|
||||||
else:
|
|
||||||
hostname = self.get_global('domain')
|
|
||||||
|
|
||||||
for wordlist in self.get_option('wordlist'):
|
|
||||||
name = os.path.splitext(os.path.basename(wordlist))[0]
|
|
||||||
await service.execute('gobuster vhost -u {http_scheme}://' + hostname + ':{port}/ -t ' + str(self.get_option('threads')) + ' -w ' + wordlist + ' -r -o "{scandir}/{protocol}_{port}_{http_scheme}_vhosts_' + name + '.txt"')
|
|
||||||
else:
|
|
||||||
info('The target was not a hostname, nor was a hostname provided as an option. Skipping virtual host enumeration.')
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
from autorecon.plugins import ServiceScan
|
from autorecon.plugins import ServiceScan
|
||||||
from autorecon.io import error
|
|
||||||
from shutil import which
|
from shutil import which
|
||||||
|
|
||||||
class NmapRedis(ServiceScan):
|
class NmapRedis(ServiceScan):
|
||||||
|
|
@ -27,7 +26,7 @@ class RedisCli(ServiceScan):
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
if which('redis-cli') is None:
|
if which('redis-cli') is None:
|
||||||
error('The redis-cli program could not be found. Make sure it is installed. (On Kali, run: sudo apt install redis-tools)')
|
self.error('The redis-cli program could not be found. Make sure it is installed. (On Kali, run: sudo apt install redis-tools)')
|
||||||
|
|
||||||
async def run(self, service):
|
async def run(self, service):
|
||||||
if which('redis-cli') is not None:
|
if which('redis-cli') is not None:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
from autorecon.plugins import ServiceScan
|
from autorecon.plugins import ServiceScan
|
||||||
from autorecon.io import error, warn
|
|
||||||
|
|
||||||
class NmapRPC(ServiceScan):
|
class NmapRPC(ServiceScan):
|
||||||
|
|
||||||
|
|
@ -35,7 +34,7 @@ class RPCDump(ServiceScan):
|
||||||
self.tags = ['default', 'safe', 'rpc']
|
self.tags = ['default', 'safe', 'rpc']
|
||||||
|
|
||||||
def configure(self):
|
def configure(self):
|
||||||
self.match_service_name(['^msrpc', '^rpcbind', '^erpc'])
|
self.match_service_name(['^msrpc', '^rpcbind', '^erpc', '^ncacn_http$'])
|
||||||
self.match_port('tcp', [135, 139, 443, 445, 593])
|
self.match_port('tcp', [135, 139, 443, 445, 593])
|
||||||
|
|
||||||
async def run(self, service):
|
async def run(self, service):
|
||||||
|
|
|
||||||
|
|
@ -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.plugins import Pattern, PortScan, ServiceScan, Report, AutoRecon
|
||||||
from autorecon.targets import Target, Service
|
from autorecon.targets import Target, Service
|
||||||
|
|
||||||
VERSION = "2.0.11"
|
VERSION = "2.0.12"
|
||||||
|
|
||||||
if not os.path.exists(config['config_dir']):
|
if not os.path.exists(config['config_dir']):
|
||||||
shutil.rmtree(config['config_dir'], ignore_errors=True, onerror=None)
|
shutil.rmtree(config['config_dir'], ignore_errors=True, onerror=None)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import asyncio, inspect, os, re, sys
|
import asyncio, inspect, os, re, sys
|
||||||
from typing import final
|
from typing import final
|
||||||
from autorecon.config import config
|
from autorecon.config import config
|
||||||
from autorecon.io import slugify, error, fail, CommandStreamReader
|
from autorecon.io import slugify, info, warn, error, fail, CommandStreamReader
|
||||||
from autorecon.targets import Service
|
from autorecon.targets import Service
|
||||||
|
|
||||||
class Pattern:
|
class Pattern:
|
||||||
|
|
@ -90,6 +90,18 @@ class Plugin(object):
|
||||||
except re.error:
|
except re.error:
|
||||||
fail('Error: The pattern "' + pattern + '" in the plugin "' + self.name + '" is invalid regex.')
|
fail('Error: The pattern "' + pattern + '" in the plugin "' + self.name + '" is invalid regex.')
|
||||||
|
|
||||||
|
@final
|
||||||
|
def info(self, msg, verbosity=0):
|
||||||
|
info('{bright}[{bgreen}' + self.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
|
@final
|
||||||
|
def warn(self, msg, verbosity=0):
|
||||||
|
warn('{bright}[{bgreen}' + self.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
|
@final
|
||||||
|
def error(self, msg, verbosity=0):
|
||||||
|
error('{bright}[{bgreen}' + self.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
class PortScan(Plugin):
|
class PortScan(Plugin):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import asyncio, inspect, os
|
import asyncio, inspect, os
|
||||||
from typing import final
|
from typing import final
|
||||||
from autorecon.config import config
|
from autorecon.config import config
|
||||||
from autorecon.io import e, info
|
from autorecon.io import e, info, warn, error
|
||||||
|
|
||||||
class Target:
|
class Target:
|
||||||
|
|
||||||
|
|
@ -31,6 +31,21 @@ class Target:
|
||||||
async def extract_services(self, stream, regex=None):
|
async def extract_services(self, stream, regex=None):
|
||||||
return await self.autorecon.extract_services(stream, regex)
|
return await self.autorecon.extract_services(stream, regex)
|
||||||
|
|
||||||
|
@final
|
||||||
|
def info(self, msg, verbosity=0):
|
||||||
|
plugin = inspect.currentframe().f_back.f_locals['self']
|
||||||
|
info('{bright}[{yellow}' + self.address + '{crst}/{bgreen}' + plugin.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
|
@final
|
||||||
|
def warn(self, msg, verbosity=0):
|
||||||
|
plugin = inspect.currentframe().f_back.f_locals['self']
|
||||||
|
warn('{bright}[{yellow}' + self.address + '{crst}/{bgreen}' + plugin.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
|
@final
|
||||||
|
def error(self, msg, verbosity=0):
|
||||||
|
plugin = inspect.currentframe().f_back.f_locals['self']
|
||||||
|
error('{bright}[{yellow}' + self.address + '{crst}/{bgreen}' + plugin.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
async def execute(self, cmd, blocking=True, outfile=None, errfile=None, future_outfile=None):
|
async def execute(self, cmd, blocking=True, outfile=None, errfile=None, future_outfile=None):
|
||||||
target = self
|
target = self
|
||||||
|
|
||||||
|
|
@ -120,6 +135,21 @@ class Service:
|
||||||
def add_manual_command(self, description, command):
|
def add_manual_command(self, description, command):
|
||||||
self.add_manual_commands(description, command)
|
self.add_manual_commands(description, command)
|
||||||
|
|
||||||
|
@final
|
||||||
|
def info(self, msg):
|
||||||
|
plugin = inspect.currentframe().f_back.f_locals['self']
|
||||||
|
info('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag() + '/' + plugin.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
|
@final
|
||||||
|
def warn(self, msg):
|
||||||
|
plugin = inspect.currentframe().f_back.f_locals['self']
|
||||||
|
warn('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag() + '/' + plugin.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
|
@final
|
||||||
|
def error(self, msg):
|
||||||
|
plugin = inspect.currentframe().f_back.f_locals['self']
|
||||||
|
error('{bright}[{yellow}' + self.target.address + '{crst}/{bgreen}' + self.tag() + '/' + plugin.slug + '{crst}]{rst} ' + msg)
|
||||||
|
|
||||||
@final
|
@final
|
||||||
async def execute(self, cmd, blocking=True, outfile=None, errfile=None, future_outfile=None):
|
async def execute(self, cmd, blocking=True, outfile=None, errfile=None, future_outfile=None):
|
||||||
target = self.target
|
target = self.target
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "autorecon"
|
name = "autorecon"
|
||||||
version = "2.0.11"
|
version = "2.0.12"
|
||||||
description = "A multi-threaded network reconnaissance tool which performs automated enumeration of services."
|
description = "A multi-threaded network reconnaissance tool which performs automated enumeration of services."
|
||||||
authors = ["Tib3rius"]
|
authors = ["Tib3rius"]
|
||||||
license = "GNU GPL v3"
|
license = "GNU GPL v3"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue