Updates & Bug Fixes

Updated global option parsing to allow default None values by removing the "default=" setting.
Added a match_service() function to ServiceScan plugins to match combinations of protocol/port/name.
Fixed bug in status times.
Removed defaul from global.domain.
Added new WinRM detection plugin.
This commit is contained in:
Tib3rius 2021-08-27 15:16:26 -04:00
parent 182b071444
commit b60fcfc9ca
3 changed files with 84 additions and 7 deletions

View File

@ -288,7 +288,13 @@ class Plugin(object):
name = 'global.' + slugify(name).replace('-', '_')
if name in vars(self.autorecon.args):
return vars(self.autorecon.args)[name]
if vars(self.autorecon.args)[name] is None:
if default:
return default
else:
return None
else:
return vars(self.autorecon.args)[name]
else:
if default:
return default
@ -323,12 +329,42 @@ class ServiceScan(Plugin):
super().__init__()
self.ports = {'tcp':[], 'udp':[]}
self.ignore_ports = {'tcp':[], 'udp':[]}
self.services = []
self.service_names = []
self.ignore_service_names = []
self.match_all_service_names_boolean = False
self.run_once_boolean = False
self.require_ssl_boolean = False
@final
def match_service(self, protocol, port, name, negative_match=False):
protocol = protocol.lower()
if protocol not in ['tcp', 'udp']:
print('Invalid protocol.')
sys.exit(1)
if not isinstance(port, list):
port = [port]
port = list(map(int, port))
if not isinstance(name, list):
name = [name]
valid_regex = True
for r in name:
try:
re.compile(r)
except re.error:
print('Invalid regex: ' + r)
valid_regex = False
if not valid_regex:
sys.exit(1)
service = {'protocol': protocol, 'port': port, 'name': name, 'negative_match': negative_match}
self.services.append(service)
@final
def match_port(self, protocol, port, negative_match=False):
protocol = protocol.lower()
@ -673,7 +709,7 @@ def calculate_elapsed_time(start_time, short=False):
elapsed_time = []
if short:
elapsed_time.append(str(h))
elapsed_time.append(str(h).zfill(2))
else:
if h == 1:
elapsed_time.append(str(h) + ' hour')
@ -681,7 +717,7 @@ def calculate_elapsed_time(start_time, short=False):
elapsed_time.append(str(h) + ' hours')
if short:
elapsed_time.append(str(m))
elapsed_time.append(str(m).zfill(2))
else:
if m == 1:
elapsed_time.append(str(m) + ' minute')
@ -689,7 +725,7 @@ def calculate_elapsed_time(start_time, short=False):
elapsed_time.append(str(m) + ' minutes')
if short:
elapsed_time.append(str(s))
elapsed_time.append(str(s).zfill(2))
else:
if s == 1:
elapsed_time.append(str(s) + ' second')
@ -1069,6 +1105,18 @@ async def scan_target(target):
plugin_service_match = False
plugin_tag = service.tag() + '/' + plugin.slug
for service_dict in plugin.services:
if service_dict['protocol'] == protocol and port in service_dict['port']:
for name in service_dict['name']:
if service_dict['negative_match']:
if name not in plugin.ignore_service_names:
plugin.ignore_service_names.append(name)
else:
if name not in plugin.service_names:
plugin.service_names.append(name)
else:
continue
for s in plugin.service_names:
if re.search(s, service.name):
plugin_service_match = True

View File

@ -7,5 +7,4 @@ default = '/usr/share/seclists/Passwords/darkweb2017-top100.txt'
help = 'A wordlist of passwords, useful for bruteforcing. Default: %(default)s'
[global.domain]
default = false
help = 'The domain to use (if known). Used for DNS and/or Active Directory.'
help = 'The domain to use (if known). Used for DNS and/or Active Directory. Default: %(default)s'

View File

@ -1,4 +1,4 @@
from autorecon import ServiceScan
from autorecon import ServiceScan, fformat
class NmapCassandra(ServiceScan):
@ -142,3 +142,33 @@ class NmapVNC(ServiceScan):
async def run(self, service):
await service.execute('nmap {nmap_extra} -sV -p {port} --script="banner,(vnc* or realvnc* or ssl*) and not (brute or broadcast or dos or external or fuzzer)" --script-args="unsafe=1" -oN "{scandir}/{protocol}_{port}_vnc_nmap.txt" -oX "{scandir}/xml/{protocol}_{port}_vnc_nmap.xml" {address}')
class WinRMDetection(ServiceScan):
def __init__(self):
super().__init__()
self.name = 'WinRM Detection'
self.tags = ['default', 'safe', 'winrm']
def configure(self):
self.match_service_name('^wsman')
self.match_service('tcp', [5985, 5986], '^http')
async def run(self, service):
filename = fformat('{scandir}/{protocol}_{port}_winrm-detection.txt')
with open(filename, mode='wt', encoding='utf8') as winrm:
winrm.write('WinRM was possibly detected running on ' + service.protocol + ' port ' + str(service.port) + '.\nCheck _manual_commands.txt for manual commands you can run against this service.')
def manual(self, service, plugin_was_run):
service.add_manual_commands('Bruteforce logins:', [
'crackmapexec winrm {address} -d ' + self.get_global('domain', default='<domain>') + ' -u ' + self.get_global('username_wordlist', default='/usr/share/seclists/Usernames/top-usernames-shortlist.txt') + ' -p ' + self.get_global('password_wordlist', default='/usr/share/seclists/Passwords/darkweb2017-top100.txt')
])
service.add_manual_commands('Check login (requires credentials):', [
'crackmapexec winrm {address} -d ' + self.get_global('domain', default='<domain>') + ' -u <username> -p <password> -x "whoami"'
])
service.add_manual_commands('Evil WinRM (gem install evil-winrm):', [
'evil-winrm -u <user> -p <password> -i {address}',
'evil-winrm -u <user> -H <hash> -i {address}'
])