parent
62db07d099
commit
8cb40ad564
97
autorecon.py
97
autorecon.py
|
@ -27,6 +27,7 @@ class Target:
|
|||
self.reportdir = ''
|
||||
self.scandir = ''
|
||||
self.lock = asyncio.Lock()
|
||||
self.ports = None
|
||||
self.pending_services = []
|
||||
self.services = []
|
||||
self.scans = []
|
||||
|
@ -326,6 +327,7 @@ class PortScan(Plugin):
|
|||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.type = None
|
||||
|
||||
async def run(self, target):
|
||||
raise NotImplementedError
|
||||
|
@ -440,6 +442,7 @@ class AutoRecon(object):
|
|||
self.excluded_tags = []
|
||||
self.patterns = []
|
||||
self.configurable_keys = [
|
||||
'ports',
|
||||
'max_scans',
|
||||
'max_port_scans',
|
||||
'tags',
|
||||
|
@ -463,6 +466,7 @@ class AutoRecon(object):
|
|||
self.config = {
|
||||
'protected_classes': ['autorecon', 'target', 'service', 'commandstreamreader', 'plugin', 'portscan', 'servicescan', 'global', 'pattern'],
|
||||
'global_file': os.path.dirname(os.path.realpath(__file__)) + '/global.toml',
|
||||
'ports': None,
|
||||
'max_scans': 50,
|
||||
'max_port_scans': None,
|
||||
'tags': 'default',
|
||||
|
@ -819,6 +823,23 @@ def handle_keyboard(key):
|
|||
info('{bgreen}' + current_time + '{rst} - There is {byellow}1{rst} scan still running against {byellow}' + target.address + '{rst}' + tasks_list)
|
||||
|
||||
async def port_scan(plugin, target):
|
||||
if autorecon.config['ports']['tcp'] or autorecon.config['ports']['udp']:
|
||||
target.ports = {'tcp':None, 'udp':None}
|
||||
if autorecon.config['ports']['tcp']:
|
||||
target.ports['tcp'] = ','.join(autorecon.config['ports']['tcp'])
|
||||
if autorecon.config['ports']['udp']:
|
||||
target.ports['udp'] = ','.join(autorecon.config['ports']['udp'])
|
||||
if plugin.type is None:
|
||||
warn('Port scan {bblue}' + plugin.name + ' (' + plugin.slug + '){rst} does not have a type set, and --ports was used. Skipping.')
|
||||
return {'type':'port', 'plugin':plugin, 'result':[]}
|
||||
else:
|
||||
if plugin.type == 'tcp' and not autorecon.config['ports']['tcp']:
|
||||
warn('Port scan {bblue}' + plugin.name + ' (' + plugin.slug + '){rst} is a TCP port scan but no TCP ports were set using --ports. Skipping')
|
||||
return {'type':'port', 'plugin':plugin, 'result':[]}
|
||||
elif plugin.type == 'udp' and not autorecon.config['ports']['udp']:
|
||||
warn('Port scan {bblue}' + plugin.name + ' (' + plugin.slug + '){rst} is a UDP port scan but no UDP ports were set using --ports. Skipping')
|
||||
return {'type':'port', 'plugin':plugin, 'result':[]}
|
||||
|
||||
async with target.autorecon.port_scan_semaphore:
|
||||
info('Port scan {bblue}' + plugin.name + ' (' + plugin.slug + '){rst} running against {byellow}' + target.address + '{rst}')
|
||||
|
||||
|
@ -1257,6 +1278,7 @@ async def main():
|
|||
parser = argparse.ArgumentParser(add_help=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', '--targets', action='store', type=str, default='', dest='target_file', 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')
|
||||
parser.add_argument('-m', '--max-scans', action='store', type=int, help='The maximum number of concurrent scans to run. Default: %(default)s')
|
||||
parser.add_argument('-mp', '--max-port-scans', action='store', type=int, help='The maximum number of concurrent port scans to run. Default: 10 (approx 20%% of max-scans unless specified)')
|
||||
parser.add_argument('-c', '--config', action='store', type=str, default=os.path.dirname(os.path.realpath(__file__)) + '/config.toml', dest='config_file', help='Location of AutoRecon\'s config file. Default: %(default)s')
|
||||
|
@ -1465,6 +1487,81 @@ async def main():
|
|||
autorecon.config[key] = args_dict[key]
|
||||
autorecon.args = args
|
||||
|
||||
if autorecon.config['ports']:
|
||||
ports_to_scan = {'tcp':[], 'udp':[]}
|
||||
unique = {'tcp':[], 'udp':[]}
|
||||
|
||||
ports = autorecon.config['ports'].split(',')
|
||||
mode = 'both'
|
||||
for port in ports:
|
||||
port = port.strip()
|
||||
if port == '':
|
||||
continue
|
||||
|
||||
if port.startswith('B:'):
|
||||
mode = 'both'
|
||||
port = port.split('B:')[1]
|
||||
elif port.startswith('T:'):
|
||||
mode = 'tcp'
|
||||
port = port.split('T:')[1]
|
||||
elif port.startswith('U:'):
|
||||
mode = 'udp'
|
||||
port = port.split('U:')[1]
|
||||
|
||||
match = re.search('^([0-9]+)\-([0-9]+)$', port)
|
||||
if match:
|
||||
num1 = int(match.group(1))
|
||||
num2 = int(match.group(2))
|
||||
|
||||
if num1 > 65535:
|
||||
fail('Error: A provided port number was too high: ' + str(num1))
|
||||
|
||||
if num2 > 65535:
|
||||
fail('Error: A provided port number was too high: ' + str(num2))
|
||||
|
||||
if num1 == num2:
|
||||
port_range = [num1]
|
||||
|
||||
if num2 > num1:
|
||||
port_range = list(range(num1, num2 + 1, 1))
|
||||
else:
|
||||
port_range = list(range(num2, num1 + 1, 1))
|
||||
num1 = num1 + num2
|
||||
num2 = num1 - num2
|
||||
num1 = num1 - num2
|
||||
|
||||
if mode == 'tcp' or mode == 'both':
|
||||
for num in port_range:
|
||||
if num in ports_to_scan['tcp']:
|
||||
ports_to_scan['tcp'].remove(num)
|
||||
ports_to_scan['tcp'].append(str(num1) + '-' + str(num2))
|
||||
unique['tcp'] = list(set(unique['tcp'] + port_range))
|
||||
|
||||
if mode == 'udp' or mode == 'both':
|
||||
for num in port_range:
|
||||
if num in ports_to_scan['udp']:
|
||||
ports_to_scan['udp'].remove(num)
|
||||
ports_to_scan['udp'].append(str(num1) + '-' + str(num2))
|
||||
unique['udp'] = list(set(unique['tcp'] + port_range))
|
||||
else:
|
||||
match = re.search('^[0-9]+$', port)
|
||||
if match:
|
||||
num = int(port)
|
||||
|
||||
if num > 65535:
|
||||
fail('Error: A provided port number was too high: ' + str(num))
|
||||
|
||||
if mode == 'tcp' or mode == 'both':
|
||||
ports_to_scan['tcp'].append(str(num)) if num not in unique['tcp'] else ports_to_scan['tcp']
|
||||
unique['tcp'].append(num)
|
||||
|
||||
if mode == 'udp' or mode == 'both':
|
||||
ports_to_scan['udp'].append(str(num)) if num not in unique['udp'] else ports_to_scan['udp']
|
||||
unique['udp'].append(num)
|
||||
else:
|
||||
fail('Error: Invalid port number: ' + str(port))
|
||||
autorecon.config['ports'] = ports_to_scan
|
||||
|
||||
if autorecon.config['max_scans'] <= 0:
|
||||
error('Argument -m/--max-scans must be at least 1.')
|
||||
errors = True
|
||||
|
|
|
@ -6,11 +6,18 @@ class QuickTCPPortScan(PortScan):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Top TCP Ports"
|
||||
self.type = 'tcp'
|
||||
self.tags = ["default", "default-port-scan"]
|
||||
self.priority = 0
|
||||
|
||||
async def run(self, target):
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sV -sC --version-all -oN "{scandir}/_quick_tcp_nmap.txt" -oX "{scandir}/xml/_quick_tcp_nmap.xml" {address}', blocking=False)
|
||||
if target.ports:
|
||||
if target.ports['tcp']:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -A --osscan-guess --version-all -p ' + target.ports['tcp'] + ' -oN "{scandir}/_custom_ports_tcp_nmap.txt" -oX "{scandir}/xml/_custom_ports_tcp_nmap.xml" {address}', blocking=False)
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -A --osscan-guess --version-all -oN "{scandir}/_quick_tcp_nmap.txt" -oX "{scandir}/xml/_quick_tcp_nmap.xml" {address}', blocking=False)
|
||||
services = await target.extract_services(stdout)
|
||||
await process.wait()
|
||||
return services
|
||||
|
@ -20,9 +27,12 @@ class AllTCPPortScan(PortScan):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "All TCP Ports"
|
||||
self.type = 'tcp'
|
||||
self.tags = ["default", "default-port-scan", "long"]
|
||||
|
||||
async def run(self, target):
|
||||
if target.ports: # Don't run this plugin if there are custom ports.
|
||||
return []
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -A --osscan-guess --version-all -p- -oN "{scandir}/_full_tcp_nmap.txt" -oX "{scandir}/xml/_full_tcp_nmap.xml" {address}', blocking=False)
|
||||
services = await target.extract_services(stdout)
|
||||
await process.wait()
|
||||
|
@ -33,12 +43,19 @@ class Top100UDPPortScan(PortScan):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "Top 100 UDP Ports"
|
||||
self.type = 'udp'
|
||||
self.tags = ["default", "default-port-scan", "long"]
|
||||
|
||||
async def run(self, target):
|
||||
# Only run UDP scan if user is root.
|
||||
if os.getuid() == 0:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sU -A --version-all --top-ports 100 -oN "{scandir}/_top_20_udp_nmap.txt" -oX "{scandir}/xml/_top_20_udp_nmap.xml" {address}', blocking=False)
|
||||
if target.ports:
|
||||
if target.ports['udp']:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sU -A --version-all -p ' + target.ports['udp'] + ' -oN "{scandir}/_custom_ports_udp_nmap.txt" -oX "{scandir}/xml/_custom_ports_udp_nmap.xml" {address}', blocking=False)
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
process, stdout, stderr = await target.execute('nmap {nmap_extra} -sU -A --version-all --top-ports 100 -oN "{scandir}/_top_100_udp_nmap.txt" -oX "{scandir}/xml/_top_100_udp_nmap.xml" {address}', blocking=False)
|
||||
services = await target.extract_services(stdout)
|
||||
await process.wait()
|
||||
return services
|
||||
|
|
Loading…
Reference in New Issue