Update autorecon.py
Added ability to force service scans.
This commit is contained in:
parent
d1863a1cd3
commit
98037302f7
191
autorecon.py
191
autorecon.py
|
@ -412,6 +412,7 @@ class AutoRecon(object):
|
||||||
'nmap',
|
'nmap',
|
||||||
'nmap_append',
|
'nmap_append',
|
||||||
'disable_sanity_checks',
|
'disable_sanity_checks',
|
||||||
|
'force_services',
|
||||||
'accessible',
|
'accessible',
|
||||||
'verbose'
|
'verbose'
|
||||||
]
|
]
|
||||||
|
@ -434,6 +435,7 @@ class AutoRecon(object):
|
||||||
'nmap': '-vv --reason -Pn',
|
'nmap': '-vv --reason -Pn',
|
||||||
'nmap_append': '',
|
'nmap_append': '',
|
||||||
'disable_sanity_checks': False,
|
'disable_sanity_checks': False,
|
||||||
|
'force_services': None,
|
||||||
'accessible': False,
|
'accessible': False,
|
||||||
'verbose': 0
|
'verbose': 0
|
||||||
}
|
}
|
||||||
|
@ -787,36 +789,37 @@ async def service_scan(plugin, service):
|
||||||
from autorecon import PortScan
|
from autorecon import PortScan
|
||||||
semaphore = service.target.autorecon.service_scan_semaphore
|
semaphore = service.target.autorecon.service_scan_semaphore
|
||||||
|
|
||||||
# If service scan semaphore is locked, see if we can use port scan semaphore.
|
if not service.target.autorecon.config['force_services']:
|
||||||
while True:
|
# If service scan semaphore is locked, see if we can use port scan semaphore.
|
||||||
if semaphore.locked():
|
while True:
|
||||||
if semaphore != service.target.autorecon.port_scan_semaphore: # This will be true unless user sets max_scans == max_port_scans
|
if semaphore.locked():
|
||||||
|
if semaphore != service.target.autorecon.port_scan_semaphore: # This will be true unless user sets max_scans == max_port_scans
|
||||||
|
|
||||||
port_scan_task_count = 0
|
port_scan_task_count = 0
|
||||||
for targ in service.target.autorecon.scanning_targets:
|
for targ in service.target.autorecon.scanning_targets:
|
||||||
for process_list in targ.running_tasks.values():
|
for process_list in targ.running_tasks.values():
|
||||||
if issubclass(process_list['plugin'].__class__, PortScan):
|
if issubclass(process_list['plugin'].__class__, PortScan):
|
||||||
port_scan_task_count += 1
|
port_scan_task_count += 1
|
||||||
|
|
||||||
if not service.target.autorecon.pending_targets and (service.target.autorecon.config['max_port_scans'] - port_scan_task_count) >= 1: # If no more targets, and we have room, use port scan semaphore.
|
if not service.target.autorecon.pending_targets and (service.target.autorecon.config['max_port_scans'] - port_scan_task_count) >= 1: # If no more targets, and we have room, use port scan semaphore.
|
||||||
if service.target.autorecon.port_scan_semaphore.locked():
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
continue
|
|
||||||
semaphore = service.target.autorecon.port_scan_semaphore
|
|
||||||
break
|
|
||||||
else: # Do some math to see if we can use the port scan semaphore.
|
|
||||||
if (service.target.autorecon.config['max_port_scans'] - (port_scan_task_count + (len(service.target.autorecon.pending_targets) * service.target.autorecon.config['port_scan_plugin_count']))) >= 1:
|
|
||||||
if service.target.autorecon.port_scan_semaphore.locked():
|
if service.target.autorecon.port_scan_semaphore.locked():
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
continue
|
continue
|
||||||
semaphore = service.target.autorecon.port_scan_semaphore
|
semaphore = service.target.autorecon.port_scan_semaphore
|
||||||
break
|
break
|
||||||
else:
|
else: # Do some math to see if we can use the port scan semaphore.
|
||||||
await asyncio.sleep(1)
|
if (service.target.autorecon.config['max_port_scans'] - (port_scan_task_count + (len(service.target.autorecon.pending_targets) * service.target.autorecon.config['port_scan_plugin_count']))) >= 1:
|
||||||
|
if service.target.autorecon.port_scan_semaphore.locked():
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
continue
|
||||||
|
semaphore = service.target.autorecon.port_scan_semaphore
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
else:
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
async with semaphore:
|
async with semaphore:
|
||||||
# Create variables for fformat references.
|
# Create variables for fformat references.
|
||||||
|
@ -917,23 +920,41 @@ async def scan_target(target):
|
||||||
|
|
||||||
heartbeat = asyncio.create_task(start_heartbeat(target, period=target.autorecon.config['heartbeat']))
|
heartbeat = asyncio.create_task(start_heartbeat(target, period=target.autorecon.config['heartbeat']))
|
||||||
|
|
||||||
for plugin in target.autorecon.plugin_types['port']:
|
services = []
|
||||||
plugin_tag_set = set(plugin.tags)
|
if autorecon.config['force_services']:
|
||||||
|
forced_services = [x.strip().lower() for x in autorecon.config['force_services']]
|
||||||
|
|
||||||
matching_tags = False
|
for forced_service in forced_services:
|
||||||
for tag_group in target.autorecon.tags:
|
match = re.search('(?P<protocol>(tcp|udp))\/(?P<port>\d+)\/(?P<service>[\w\-\/]+)\/(?P<secure>secure|insecure)', forced_service)
|
||||||
if set(tag_group).issubset(plugin_tag_set):
|
if match:
|
||||||
matching_tags = True
|
protocol = match.group('protocol')
|
||||||
break
|
port = int(match.group('port'))
|
||||||
|
service = match.group('service')
|
||||||
|
secure = True if match.group('secure') == 'secure' else False
|
||||||
|
service = Service(protocol, port, service, secure)
|
||||||
|
service.target = target
|
||||||
|
services.append(service)
|
||||||
|
|
||||||
excluded_tags = False
|
if services:
|
||||||
for tag_group in target.autorecon.excluded_tags:
|
pending.append(asyncio.create_task(asyncio.sleep(0)))
|
||||||
if set(tag_group).issubset(plugin_tag_set):
|
else:
|
||||||
excluded_tags = True
|
for plugin in target.autorecon.plugin_types['port']:
|
||||||
break
|
plugin_tag_set = set(plugin.tags)
|
||||||
|
|
||||||
if matching_tags and not excluded_tags:
|
matching_tags = False
|
||||||
pending.append(asyncio.create_task(port_scan(plugin, target)))
|
for tag_group in target.autorecon.tags:
|
||||||
|
if set(tag_group).issubset(plugin_tag_set):
|
||||||
|
matching_tags = True
|
||||||
|
break
|
||||||
|
|
||||||
|
excluded_tags = False
|
||||||
|
for tag_group in target.autorecon.excluded_tags:
|
||||||
|
if set(tag_group).issubset(plugin_tag_set):
|
||||||
|
excluded_tags = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if matching_tags and not excluded_tags:
|
||||||
|
pending.append(asyncio.create_task(port_scan(plugin, target)))
|
||||||
|
|
||||||
async with autorecon.lock:
|
async with autorecon.lock:
|
||||||
autorecon.scanning_targets.append(target)
|
autorecon.scanning_targets.append(target)
|
||||||
|
@ -953,23 +974,25 @@ async def scan_target(target):
|
||||||
timed_out = True
|
timed_out = True
|
||||||
break
|
break
|
||||||
|
|
||||||
# Extract Services
|
if not autorecon.config['force_services']:
|
||||||
services = []
|
# Extract Services
|
||||||
async with target.lock:
|
services = []
|
||||||
while target.pending_services:
|
|
||||||
services.append(target.pending_services.pop(0))
|
|
||||||
|
|
||||||
for task in done:
|
async with target.lock:
|
||||||
try:
|
while target.pending_services:
|
||||||
if task.exception():
|
services.append(target.pending_services.pop(0))
|
||||||
print(task.exception())
|
|
||||||
continue
|
|
||||||
except asyncio.InvalidStateError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if task.result()['type'] == 'port':
|
for task in done:
|
||||||
for service in (task.result()['result'] or []):
|
try:
|
||||||
services.append(service)
|
if task.exception():
|
||||||
|
print(task.exception())
|
||||||
|
continue
|
||||||
|
except asyncio.InvalidStateError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if task.result()['type'] == 'port':
|
||||||
|
for service in (task.result()['result'] or []):
|
||||||
|
services.append(service)
|
||||||
|
|
||||||
for service in services:
|
for service in services:
|
||||||
if service.full_tag() not in target.services:
|
if service.full_tag() not in target.services:
|
||||||
|
@ -1150,6 +1173,7 @@ async def main():
|
||||||
nmap_group.add_argument('--nmap', action='store', help='Override the {nmap_extra} variable in scans. Default: %(default)s')
|
nmap_group.add_argument('--nmap', action='store', help='Override the {nmap_extra} variable in scans. Default: %(default)s')
|
||||||
nmap_group.add_argument('--nmap-append', action='store', help='Append to the default {nmap_extra} variable in scans. Default: %(default)s')
|
nmap_group.add_argument('--nmap-append', action='store', help='Append to the default {nmap_extra} variable in scans. Default: %(default)s')
|
||||||
parser.add_argument('--disable-sanity-checks', action='store_true', help='Disable sanity checks that would otherwise prevent the scans from running. Default: %(default)s')
|
parser.add_argument('--disable-sanity-checks', action='store_true', help='Disable sanity checks that would otherwise prevent the scans from running. Default: %(default)s')
|
||||||
|
parser.add_argument('--force-services', action='store', nargs='+', help='A space separated list of services in the following style: tcp/80/http/insecure tcp/443/https/secure')
|
||||||
parser.add_argument('--accessible', action='store_true', help='Attempts to make AutoRecon output more accessible to screenreaders. Default: %(default)s')
|
parser.add_argument('--accessible', action='store_true', help='Attempts to make AutoRecon output more accessible to screenreaders. Default: %(default)s')
|
||||||
parser.add_argument('-v', '--verbose', action='count', help='Enable verbose output. Repeat for more verbosity.')
|
parser.add_argument('-v', '--verbose', action='count', help='Enable verbose output. Repeat for more verbosity.')
|
||||||
parser.add_argument('--version', action='store_true', help='Prints the AutoRecon version and exits.')
|
parser.add_argument('--version', action='store_true', help='Prints the AutoRecon version and exits.')
|
||||||
|
@ -1161,7 +1185,7 @@ async def main():
|
||||||
autorecon.argparse = parser
|
autorecon.argparse = parser
|
||||||
|
|
||||||
if args.version:
|
if args.version:
|
||||||
print('AutoRecon v2.0-beta1')
|
print('AutoRecon v2.0-beta2')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Parse config file and args for global.toml first.
|
# Parse config file and args for global.toml first.
|
||||||
|
@ -1332,7 +1356,6 @@ async def main():
|
||||||
if key in autorecon.configurable_boolean_keys and autorecon.config[key]:
|
if key in autorecon.configurable_boolean_keys and autorecon.config[key]:
|
||||||
continue
|
continue
|
||||||
autorecon.config[key] = args_dict[key]
|
autorecon.config[key] = args_dict[key]
|
||||||
|
|
||||||
autorecon.args = args
|
autorecon.args = args
|
||||||
|
|
||||||
if autorecon.config['max_scans'] <= 0:
|
if autorecon.config['max_scans'] <= 0:
|
||||||
|
@ -1367,12 +1390,15 @@ async def main():
|
||||||
errors = True
|
errors = True
|
||||||
|
|
||||||
if not errors:
|
if not errors:
|
||||||
autorecon.port_scan_semaphore = asyncio.Semaphore(autorecon.config['max_port_scans'])
|
if autorecon.config['force_services']:
|
||||||
# If max scans and max port scans is the same, the service scan semaphore and port scan semaphore should be the same object
|
autorecon.service_scan_semaphore = asyncio.Semaphore(autorecon.config['max_scans'])
|
||||||
if autorecon.config['max_scans'] == autorecon.config['max_port_scans']:
|
|
||||||
autorecon.service_scan_semaphore = autorecon.port_scan_semaphore
|
|
||||||
else:
|
else:
|
||||||
autorecon.service_scan_semaphore = asyncio.Semaphore(autorecon.config['max_scans'] - autorecon.config['max_port_scans'])
|
autorecon.port_scan_semaphore = asyncio.Semaphore(autorecon.config['max_port_scans'])
|
||||||
|
# If max scans and max port scans is the same, the service scan semaphore and port scan semaphore should be the same object
|
||||||
|
if autorecon.config['max_scans'] == autorecon.config['max_port_scans']:
|
||||||
|
autorecon.service_scan_semaphore = autorecon.port_scan_semaphore
|
||||||
|
else:
|
||||||
|
autorecon.service_scan_semaphore = asyncio.Semaphore(autorecon.config['max_scans'] - autorecon.config['max_port_scans'])
|
||||||
|
|
||||||
tags = []
|
tags = []
|
||||||
for tag_group in list(set(filter(None, args.tags.lower().split(',')))):
|
for tag_group in list(set(filter(None, args.tags.lower().split(',')))):
|
||||||
|
@ -1450,26 +1476,29 @@ async def main():
|
||||||
error('A total of ' + str(len(autorecon.pending_targets)) + ' targets would be scanned. If this is correct, re-run with the --disable-sanity-checks option to suppress this check.')
|
error('A total of ' + str(len(autorecon.pending_targets)) + ' targets would be scanned. If this is correct, re-run with the --disable-sanity-checks option to suppress this check.')
|
||||||
errors = True
|
errors = True
|
||||||
|
|
||||||
port_scan_plugin_count = 0
|
if not autorecon.config['force_services']:
|
||||||
for plugin in autorecon.plugin_types['port']:
|
port_scan_plugin_count = 0
|
||||||
matching_tags = False
|
for plugin in autorecon.plugin_types['port']:
|
||||||
for tag_group in autorecon.tags:
|
matching_tags = False
|
||||||
if set(tag_group).issubset(set(plugin.tags)):
|
for tag_group in autorecon.tags:
|
||||||
matching_tags = True
|
if set(tag_group).issubset(set(plugin.tags)):
|
||||||
break
|
matching_tags = True
|
||||||
|
break
|
||||||
|
|
||||||
excluded_tags = False
|
excluded_tags = False
|
||||||
for tag_group in autorecon.excluded_tags:
|
for tag_group in autorecon.excluded_tags:
|
||||||
if set(tag_group).issubset(set(plugin.tags)):
|
if set(tag_group).issubset(set(plugin.tags)):
|
||||||
excluded_tags = True
|
excluded_tags = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if matching_tags and not excluded_tags:
|
if matching_tags and not excluded_tags:
|
||||||
port_scan_plugin_count += 1
|
port_scan_plugin_count += 1
|
||||||
|
|
||||||
if port_scan_plugin_count == 0:
|
if port_scan_plugin_count == 0:
|
||||||
error('There are no port scan plugins that match the tags specified.')
|
error('There are no port scan plugins that match the tags specified.')
|
||||||
errors = True
|
errors = True
|
||||||
|
else:
|
||||||
|
port_scan_plugin_count = autorecon.config['max_port_scans'] / 5
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -1487,13 +1516,13 @@ async def main():
|
||||||
i+=1
|
i+=1
|
||||||
if i >= num_initial_targets:
|
if i >= num_initial_targets:
|
||||||
break
|
break
|
||||||
|
|
||||||
# This makes it possible to capture keypresses without <enter> and without displaying them.
|
# This makes it possible to capture keypresses without <enter> and without displaying them.
|
||||||
tty.setcbreak(sys.stdin.fileno())
|
tty.setcbreak(sys.stdin.fileno())
|
||||||
|
|
||||||
verbosity_monitor = keyboard.Listener(on_press=change_verbosity)
|
verbosity_monitor = keyboard.Listener(on_press=change_verbosity)
|
||||||
verbosity_monitor.start()
|
verbosity_monitor.start()
|
||||||
|
|
||||||
timed_out = False
|
timed_out = False
|
||||||
while pending:
|
while pending:
|
||||||
done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED, timeout=1)
|
done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED, timeout=1)
|
||||||
|
@ -1514,8 +1543,12 @@ async def main():
|
||||||
port_scan_task_count = 0
|
port_scan_task_count = 0
|
||||||
for targ in autorecon.scanning_targets:
|
for targ in autorecon.scanning_targets:
|
||||||
for process_list in targ.running_tasks.values():
|
for process_list in targ.running_tasks.values():
|
||||||
if issubclass(process_list['plugin'].__class__, PortScan):
|
if autorecon.config['force_services']:
|
||||||
port_scan_task_count += 1
|
if issubclass(process_list['plugin'].__class__, ServiceScan):
|
||||||
|
port_scan_task_count += 1
|
||||||
|
else:
|
||||||
|
if issubclass(process_list['plugin'].__class__, PortScan):
|
||||||
|
port_scan_task_count += 1
|
||||||
|
|
||||||
num_new_targets = math.ceil((autorecon.config['max_port_scans'] - port_scan_task_count) / port_scan_plugin_count)
|
num_new_targets = math.ceil((autorecon.config['max_port_scans'] - port_scan_task_count) / port_scan_plugin_count)
|
||||||
if num_new_targets > 0:
|
if num_new_targets > 0:
|
||||||
|
|
Loading…
Reference in New Issue