This commit is contained in:
MrMatch246 2025-09-17 09:49:24 +00:00 committed by GitHub
commit f10e28772d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 94 additions and 26 deletions

View File

@ -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)

View File

@ -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"',

View File

@ -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,
)

View File

@ -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```')

View File

@ -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>'
])

View File

@ -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