Merge 8af0595cd6
into fd87c99abc
This commit is contained in:
commit
f10e28772d
|
@ -87,7 +87,7 @@ whatweb
|
|||
On Kali Linux, you can ensure these are all installed using the following commands:
|
||||
|
||||
```bash
|
||||
sudo apt install seclists curl dnsrecon enum4linux feroxbuster gobuster impacket-scripts nbtscan nikto nmap onesixtyone oscanner redis-tools smbclient smbmap snmp sslscan sipvicious tnscmd10g whatweb
|
||||
sudo apt install seclists curl dnsrecon enum4linux feroxbuster gobuster impacket-scripts nbtscan nuclei nikto nmap onesixtyone oscanner redis-tools smbclient smbmap snmp sslscan sipvicious tnscmd10g whatweb
|
||||
```
|
||||
|
||||
### Installation Method #1: pipx (Recommended)
|
||||
|
|
|
@ -12,7 +12,7 @@ class BruteforceHTTP(ServiceScan):
|
|||
self.match_service_name('^nacn_http$', negative_match=True)
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_commands('Credential bruteforcing commands (don\'t run these without modifying them):', [
|
||||
service.add_manual_commands('Credential bruteforcing commands (dont run these without modifying them):', [
|
||||
'hydra -L "' + 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') + '" -e nsr -s {port} -o "{scandir}/{protocol}_{port}_{http_scheme}_auth_hydra.txt" {http_scheme}-get://{addressv6}/path/to/auth/area',
|
||||
'medusa -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') + '" -e ns -n {port} -O "{scandir}/{protocol}_{port}_{http_scheme}_auth_medusa.txt" -M http -h {addressv6} -m DIR:/path/to/auth/area',
|
||||
'hydra -L "' + 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') + '" -e nsr -s {port} -o "{scandir}/{protocol}_{port}_{http_scheme}_form_hydra.txt" {http_scheme}-post-form://{addressv6}/path/to/login.php:"username=^USER^&password=^PASS^":"invalid-login-message"',
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
from autorecon.plugins import ServiceScan
|
||||
from shutil import which
|
||||
|
||||
|
||||
class Nuclei(ServiceScan):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.name = "nuclei"
|
||||
self.tags = ["default", "safe", "long"]
|
||||
|
||||
self.cmd = 'nuclei -disable-update-check -no-color -target {address}:{port} -scan-all-ips -o "{scandir}/{protocol}_{port}_nuclei.txt"'
|
||||
|
||||
def configure(self):
|
||||
self.match_all_service_names(True)
|
||||
self.add_pattern(
|
||||
r"(.*\[(critical|high)\].*)",
|
||||
description="Nuclei {match2} finding: {match1}",
|
||||
)
|
||||
|
||||
def check(self):
|
||||
if which("nuclei") is None:
|
||||
self.error(
|
||||
"The program nuclei could not be found. Make sure it is installed. (On Kali, run: sudo apt install nuclei)"
|
||||
)
|
||||
return False
|
||||
|
||||
async def run(self, service):
|
||||
if service.target.ipversion == "IPv4":
|
||||
await service.execute(self.cmd)
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
if service.target.ipversion == "IPv4" and not plugin_was_run:
|
||||
service.add_manual_command(
|
||||
f"({self.name}) Fast and customizable vulnerability scanner based on simple YAML based DSL:",
|
||||
self.cmd,
|
||||
)
|
|
@ -10,24 +10,31 @@ class Markdown(Report):
|
|||
|
||||
async def run(self, targets):
|
||||
if len(targets) > 1:
|
||||
report = os.path.join(config['output'], 'report.md')
|
||||
report = os.path.join(config['output'], 'Full_Report.md')
|
||||
single_target = False
|
||||
elif len(targets) == 1:
|
||||
report = os.path.join(targets[0].reportdir, 'report.md')
|
||||
report = targets[0].reportdir
|
||||
single_target = True
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
os.makedirs(report, exist_ok=True)
|
||||
|
||||
for target in targets:
|
||||
os.makedirs(os.path.join(report, target.address), exist_ok=True)
|
||||
# Use target.address subdirectory only if multiple targets exist
|
||||
target_root = report if single_target else os.path.join(report, target.address)
|
||||
os.makedirs(target_root, exist_ok=True)
|
||||
|
||||
files = [os.path.abspath(filename) for filename in glob.iglob(os.path.join(target.scandir, '**/*'), recursive=True) if os.path.isfile(filename) and filename.endswith(('.txt', '.html'))]
|
||||
|
||||
# --- Port Scans ---
|
||||
if target.scans['ports']:
|
||||
os.makedirs(os.path.join(report, target.address, 'Port Scans'), exist_ok=True)
|
||||
ports_dir = os.path.join(target_root, 'Port Scans')
|
||||
os.makedirs(ports_dir, exist_ok=True)
|
||||
for scan in target.scans['ports'].keys():
|
||||
if len(target.scans['ports'][scan]['commands']) > 0:
|
||||
with open(os.path.join(report, target.address, 'Port Scans', 'PortScan - ' + target.scans['ports'][scan]['plugin'].name + '.md'), 'w') as output:
|
||||
with open(os.path.join(ports_dir, 'PortScan - ' + target.scans['ports'][scan]['plugin'].name + '.md'), 'w') as output:
|
||||
for command in target.scans['ports'][scan]['commands']:
|
||||
output.writelines('```bash\n' + command[0] + '\n```')
|
||||
for filename in files:
|
||||
|
@ -35,13 +42,17 @@ class Markdown(Report):
|
|||
output.writelines('\n\n[' + filename + '](file://' + filename + '):\n\n')
|
||||
with open(filename, 'r') as file:
|
||||
output.writelines('```\n' + file.read() + '\n```\n')
|
||||
|
||||
# --- Services ---
|
||||
if target.scans['services']:
|
||||
os.makedirs(os.path.join(report, target.address, 'Services'), exist_ok=True)
|
||||
services_dir = os.path.join(target_root, 'Services')
|
||||
os.makedirs(services_dir, exist_ok=True)
|
||||
for service in target.scans['services'].keys():
|
||||
os.makedirs(os.path.join(report, target.address, 'Services', 'Service - ' + service.tag().replace('/', '-')), exist_ok=True)
|
||||
service_dir = os.path.join(services_dir, 'Service - ' + service.tag().replace('/', '-'))
|
||||
os.makedirs(service_dir, exist_ok=True)
|
||||
for plugin in target.scans['services'][service].keys():
|
||||
if len(target.scans['services'][service][plugin]['commands']) > 0:
|
||||
with open(os.path.join(report, target.address, 'Services', 'Service - ' + service.tag().replace('/', '-'), target.scans['services'][service][plugin]['plugin'].name + '.md'), 'w') as output:
|
||||
with open(os.path.join(service_dir, target.scans['services'][service][plugin]['plugin'].name + '.md'), 'w') as output:
|
||||
for command in target.scans['services'][service][plugin]['commands']:
|
||||
output.writelines('```bash\n' + command[0] + '\n```')
|
||||
for filename in files:
|
||||
|
@ -50,26 +61,30 @@ class Markdown(Report):
|
|||
with open(filename, 'r') as file:
|
||||
output.writelines('```\n' + file.read() + '\n```\n')
|
||||
|
||||
# --- Manual Commands ---
|
||||
manual_commands = os.path.join(target.scandir, '_manual_commands.txt')
|
||||
if os.path.isfile(manual_commands):
|
||||
with open(os.path.join(report, target.address, 'Manual Commands' + '.md'), 'w') as output:
|
||||
with open(os.path.join(target_root, 'Manual Commands.md'), 'w') as output:
|
||||
with open(manual_commands, 'r') as file:
|
||||
output.writelines('```bash\n' + file.read() + '\n```')
|
||||
|
||||
# --- Patterns ---
|
||||
patterns = os.path.join(target.scandir, '_patterns.log')
|
||||
if os.path.isfile(patterns):
|
||||
with open(os.path.join(report, target.address, 'Patterns' + '.md'), 'w') as output:
|
||||
with open(os.path.join(target_root, 'Patterns.md'), 'w') as output:
|
||||
with open(patterns, 'r') as file:
|
||||
output.writelines(file.read())
|
||||
|
||||
# --- Commands ---
|
||||
commands = os.path.join(target.scandir, '_commands.log')
|
||||
if os.path.isfile(commands):
|
||||
with open(os.path.join(report, target.address, 'Commands' + '.md'), 'w') as output:
|
||||
with open(os.path.join(target_root, 'Commands.md'), 'w') as output:
|
||||
with open(commands, 'r') as file:
|
||||
output.writelines('```bash\n' + file.read() + '\n```')
|
||||
|
||||
# --- Errors ---
|
||||
errors = os.path.join(target.scandir, '_errors.log')
|
||||
if os.path.isfile(errors):
|
||||
with open(os.path.join(report, target.address, 'Errors' + '.md'), 'w') as output:
|
||||
with open(os.path.join(target_root, 'Errors.md'), 'w') as output:
|
||||
with open(errors, 'r') as file:
|
||||
output.writelines('```\n' + file.read() + '\n```')
|
||||
|
|
|
@ -15,6 +15,6 @@ class SMTPUserEnum(ServiceScan):
|
|||
await service.execute('hydra smtp-enum://{addressv6}:{port}/expn -L "' + self.get_global('username_wordlist', default='/usr/share/seclists/Usernames/top-usernames-shortlist.txt') + '" 2>&1', outfile='{protocol}_{port}_smtp_user-enum_hydra_expn.txt')
|
||||
|
||||
def manual(self, service, plugin_was_run):
|
||||
service.add_manual_command('Try User Enumeration using "RCPT TO". Replace <TARGET-DOMAIN> with the target\'s domain name:', [
|
||||
service.add_manual_command('Try User Enumeration using "RCPT TO". Replace <TARGET-DOMAIN> with the target domain name:', [
|
||||
'hydra smtp-enum://{addressv6}:{port}/rcpt -L "' + self.get_global('username_wordlist', default='/usr/share/seclists/Usernames/top-usernames-shortlist.txt') + '" -o "{scandir}/{protocol}_{port}_smtp_user-enum_hydra_rcpt.txt" -p <TARGET-DOMAIN>'
|
||||
])
|
||||
|
|
|
@ -41,8 +41,9 @@ if not os.path.exists(config['data_dir']):
|
|||
shutil.copytree(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'default-plugins'), os.path.join(config['data_dir'], 'plugins'))
|
||||
shutil.copytree(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'wordlists'), os.path.join(config['data_dir'], 'wordlists'))
|
||||
else:
|
||||
if not os.path.exists(os.path.join(config['data_dir'], 'plugins')):
|
||||
shutil.copytree(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'default-plugins'), os.path.join(config['data_dir'], 'plugins'))
|
||||
develop =False
|
||||
if not os.path.exists(os.path.join(config['data_dir'], 'plugins')) or develop:
|
||||
shutil.copytree(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'default-plugins'), os.path.join(config['data_dir'], 'plugins'), dirs_exist_ok=True)
|
||||
if not os.path.exists(os.path.join(config['data_dir'], 'wordlists')):
|
||||
shutil.copytree(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'wordlists'), os.path.join(config['data_dir'], 'wordlists'))
|
||||
if not os.path.exists(os.path.join(config['data_dir'], 'VERSION-' + VERSION)):
|
||||
|
@ -329,6 +330,7 @@ async def port_scan(plugin, target):
|
|||
target.running_tasks.pop(plugin.slug, None)
|
||||
|
||||
info('Port scan {bblue}' + plugin.name + ' {green}(' + plugin.slug + '){rst} against {byellow}' + target.address + '{rst} finished in ' + elapsed_time, verbosity=2)
|
||||
os.system ('touch ' + os.path.join(target.scandir, '.port_scans', f".{plugin.slug}"))
|
||||
return {'type':'port', 'plugin':plugin, 'result':result}
|
||||
|
||||
async def service_scan(plugin, service):
|
||||
|
@ -453,6 +455,7 @@ async def service_scan(plugin, service):
|
|||
service.target.running_tasks.pop(tag, None)
|
||||
|
||||
info('Service scan {bblue}' + plugin.name + ' {green}(' + tag + '){rst} against {byellow}' + service.target.address + '{rst} finished in ' + elapsed_time, verbosity=2)
|
||||
os.system ('touch ' + os.path.join(scandir, '.service_scans', f".{plugin.slug}"))
|
||||
return {'type':'service', 'plugin':plugin, 'result':result}
|
||||
|
||||
async def generate_report(plugin, targets):
|
||||
|
@ -485,6 +488,7 @@ async def scan_target(target):
|
|||
os.makedirs(scandir, exist_ok=True)
|
||||
|
||||
os.makedirs(os.path.join(scandir, 'xml'), exist_ok=True)
|
||||
os.makedirs(os.path.join(scandir, '.port_scans'), exist_ok=True)
|
||||
|
||||
if not config['only_scans_dir']:
|
||||
exploitdir = os.path.join(basedir, 'exploit')
|
||||
|
@ -496,8 +500,8 @@ async def scan_target(target):
|
|||
reportdir = os.path.join(basedir, 'report')
|
||||
os.makedirs(reportdir, exist_ok=True)
|
||||
|
||||
open(os.path.join(reportdir, 'local.txt'), 'a').close()
|
||||
open(os.path.join(reportdir, 'proof.txt'), 'a').close()
|
||||
#open(os.path.join(reportdir, 'local.txt'), 'a').close()
|
||||
#open(os.path.join(reportdir, 'proof.txt'), 'a').close()
|
||||
|
||||
screenshotdir = os.path.join(reportdir, 'screenshots')
|
||||
os.makedirs(screenshotdir, exist_ok=True)
|
||||
|
@ -506,7 +510,7 @@ async def scan_target(target):
|
|||
|
||||
target.reportdir = reportdir
|
||||
|
||||
pending = []
|
||||
pending = set()
|
||||
|
||||
heartbeat = asyncio.create_task(start_heartbeat(target, period=config['heartbeat']))
|
||||
|
||||
|
@ -515,7 +519,7 @@ async def scan_target(target):
|
|||
forced_services = [x.strip().lower() for x in config['force_services']]
|
||||
|
||||
for forced_service in forced_services:
|
||||
match = re.search('(?P<protocol>(tcp|udp))\/(?P<port>\d+)\/(?P<service>[\w\-]+)(\/(?P<secure>secure|insecure))?', forced_service)
|
||||
match = re.search(r'(?P<protocol>(tcp|udp))/(?P<port>\d+)/(?P<service>[\w\-]+)(/(?P<secure>secure|insecure))?', forced_service)
|
||||
if match:
|
||||
protocol = match.group('protocol')
|
||||
if config['proxychains'] and protocol == 'udp':
|
||||
|
@ -529,7 +533,7 @@ async def scan_target(target):
|
|||
services.append(service)
|
||||
|
||||
if services:
|
||||
pending.append(asyncio.create_task(asyncio.sleep(0)))
|
||||
pending.add(asyncio.create_task(asyncio.sleep(0)))
|
||||
else:
|
||||
error('No services were defined. Please check your service syntax: [tcp|udp]/<port>/<service-name>/[secure|insecure]')
|
||||
heartbeat.cancel()
|
||||
|
@ -539,6 +543,11 @@ async def scan_target(target):
|
|||
for plugin in target.autorecon.plugin_types['port']:
|
||||
if config['proxychains'] and plugin.type == 'udp':
|
||||
continue
|
||||
processed_marker = os.path.join(scandir, '.port_scans', f".{plugin.slug}")
|
||||
# If the plugin has already been run against this target, skip it.
|
||||
if os.path.exists(processed_marker):
|
||||
info(f"Port Plugin {plugin.name} ({plugin.slug}) has already been run against {target.address}. Skipping.")
|
||||
continue
|
||||
|
||||
if config['port_scans'] and plugin.slug in config['port_scans']:
|
||||
matching_tags = True
|
||||
|
@ -560,7 +569,7 @@ async def scan_target(target):
|
|||
|
||||
if matching_tags and not excluded_tags:
|
||||
target.scans['ports'][plugin.slug] = {'plugin':plugin, 'commands':[]}
|
||||
pending.append(asyncio.create_task(port_scan(plugin, target)))
|
||||
pending.add(asyncio.create_task(port_scan(plugin, target)))
|
||||
|
||||
async with autorecon.lock:
|
||||
autorecon.scanning_targets.append(target)
|
||||
|
@ -627,6 +636,7 @@ async def scan_target(target):
|
|||
scandir = os.path.join(scandir, protocol + str(port))
|
||||
os.makedirs(scandir, exist_ok=True)
|
||||
os.makedirs(os.path.join(scandir, 'xml'), exist_ok=True)
|
||||
os.makedirs(os.path.join(scandir, '.service_scans'), exist_ok=True)
|
||||
|
||||
# Special cases for HTTP.
|
||||
http_scheme = 'https' if 'https' in service.name or service.secure is True else 'http'
|
||||
|
@ -656,6 +666,13 @@ async def scan_target(target):
|
|||
plugin_service_match = False
|
||||
plugin_tag = service.tag() + '/' + plugin.slug
|
||||
|
||||
processed_marker = os.path.join(scandir, '.service_scans', f".{plugin.slug}")
|
||||
# If the plugin has already been run against this service, skip it.
|
||||
if os.path.exists(processed_marker):
|
||||
info(f"Service Plugin {plugin.name} ({plugin.slug}) has already been run against {service.name} on {target.address}. Skipping.")
|
||||
continue
|
||||
|
||||
|
||||
for service_dict in plugin.services:
|
||||
if service_dict['protocol'] == protocol and port in service_dict['port']:
|
||||
for name in service_dict['name']:
|
||||
|
@ -1250,7 +1267,7 @@ async def run():
|
|||
mode = 'udp'
|
||||
port = port.split('U:')[1]
|
||||
|
||||
match = re.search('^([0-9]+)\-([0-9]+)$', port)
|
||||
match = re.search(r'^([0-9]+)-([0-9]+)$', port)
|
||||
if match:
|
||||
num1 = int(match.group(1))
|
||||
num2 = int(match.group(2))
|
||||
|
@ -1533,10 +1550,10 @@ async def run():
|
|||
if not config['disable_keyboard_control']:
|
||||
terminal_settings = termios.tcgetattr(sys.stdin.fileno())
|
||||
|
||||
pending = []
|
||||
pending = set()
|
||||
i = 0
|
||||
while autorecon.pending_targets:
|
||||
pending.append(asyncio.create_task(scan_target(autorecon.pending_targets.pop(0))))
|
||||
pending.add(asyncio.create_task(scan_target(autorecon.pending_targets.pop(0))))
|
||||
i+=1
|
||||
if i >= num_initial_targets:
|
||||
break
|
||||
|
|
Loading…
Reference in New Issue