Files
PentestPilot/bin/web/httpx_tech_route.py
PentestPilot Bot 461c14d676 feat: bootstrap PentestPilot toolkit, docs, and orchestrators
Initial commit of PentestPilot — AI‑assisted pentest recon and orchestration toolkit.\n\nHighlights:\n- Resumeable pipelines (full_pipeline) with manifest state and elapsed timings\n- Rich dashboard (colors, severity bars, durations, compact/json modes)\n- Web helpers: httpx→nuclei auto, tech routing + quick scanners\n- Agents: multi‑task orchestrator (web/full/ad/notes/post) with resume\n- AD/SMB, password utils, shells, transfer, privesc, tunnels\n- QoL scripts: proxy toggle, cleanup, tmux init, URL extractor\n- Docs: README (Quick Start + Docs Index), HOWTO (deep guide), TOOLKIT (catalog with examples)\n\nStructure:\n- bin/automation: pipelines, dashboard, manifest, resume, tech_actions\n- bin/web: routing, scanners, helpers\n- bin/ai: orchestrators + robust AI utils\n- bin/ad, bin/passwords, bin/shells, bin/transfer, bin/privesc, bin/misc, bin/dns, bin/scan, bin/windows, bin/hashes\n- HOWTO.md and TOOLKIT.md cross‑linked with examples\n\nUse:\n- settarget <target>; agent full <domain|hosts.txt>; dashboard --compact\n- See HOWTO.md for setup, semantics, and examples.
2025-10-08 16:00:22 +02:00

135 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python3
import sys, os, json, subprocess, tempfile
HELP = """Usage: httpx_tech_route.py <host|file> [--tech list] [--severity sevlist] [--wpscan] [--wpscan-limit N] [--extra] [--extra-limit N] [--dry-run]
Runs httpx -json -tech-detect, groups URLs by technologies, and runs nuclei per tech presets.
Tech presets map:
wordpress -> nuclei tags: wordpress (+ optional wpscan_quick)
drupal, joomla, laravel, aspnet, spring, tomcat, iis, exchange, sharepoint, grafana, kibana, gitlab, confluence, jupyter -> nuclei tag same as tech
"""
if len(sys.argv) < 2:
print(HELP, file=sys.stderr); sys.exit(1)
arg = sys.argv[1]
dry = '--dry-run' in sys.argv
tech_filter = None
severity = 'medium,high,critical'
wpscan = '--wpscan' in sys.argv
wpscan_limit = 5
extra = '--extra' in sys.argv
extra_limit = 5
if '--tech' in sys.argv:
i = sys.argv.index('--tech')
if i+1 < len(sys.argv): tech_filter = set(sys.argv[i+1].lower().split(','))
if '--severity' in sys.argv:
i = sys.argv.index('--severity')
if i+1 < len(sys.argv): severity = sys.argv[i+1]
if '--wpscan-limit' in sys.argv:
i = sys.argv.index('--wpscan-limit')
if i+1 < len(sys.argv): wpscan_limit = int(sys.argv[i+1])
if '--extra-limit' in sys.argv:
i = sys.argv.index('--extra-limit')
if i+1 < len(sys.argv): extra_limit = int(sys.argv[i+1])
def run(cmd):
try:
return subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode()
except Exception:
return ''
if not shutil := __import__('shutil') or True:
pass
if not shutil.which('httpx'):
print('[!] httpx not found', file=sys.stderr); sys.exit(2)
if not shutil.which('nuclei') and not dry:
print('[!] nuclei not found', file=sys.stderr); sys.exit(2)
json_lines = ''
if os.path.isfile(arg):
json_lines = run(['httpx','-silent','-l',arg,'-ports','80,81,88,443,3000,5000,7001,7002,8000,8008,8080,8081,8088,8443,8888,9000','-tech-detect','-json'])
else:
json_lines = run(['bash','-lc',f'printf %s\\n {arg} | httpx -silent -ports 80,81,88,443,3000,5000,7001,7002,8000,8008,8080,8081,8088,8443,8888,9000 -tech-detect -json'])
by_tech = {}
for line in json_lines.splitlines():
try:
o = json.loads(line)
url = o.get('url')
techs = [t.lower() for t in o.get('technologies', [])]
for t in techs:
if tech_filter and t not in tech_filter: continue
by_tech.setdefault(t, set()).add(url)
except Exception:
continue
presets = {
'wordpress': {'tags': 'wordpress', 'wpscan': True},
'drupal': {'tags': 'drupal'},
'joomla': {'tags': 'joomla'},
'laravel': {'tags': 'laravel'},
'aspnet': {'tags': 'aspnet'},
'spring': {'tags': 'spring'},
'tomcat': {'tags': 'tomcat'},
'iis': {'tags': 'iis'},
'exchange': {'tags': 'exchange'},
'sharepoint': {'tags': 'sharepoint'},
'grafana': {'tags': 'grafana'},
'kibana': {'tags': 'kibana'},
'gitlab': {'tags': 'gitlab'},
'confluence': {'tags': 'confluence'},
'jupyter': {'tags': 'jupyter'},
'jenkins': {'tags': 'jenkins'},
'magento': {'tags': 'magento'},
'sonarqube': {'tags': 'sonarqube'},
}
for t, urls in sorted(by_tech.items(), key=lambda x: (-len(x[1]), x[0])):
if not urls: continue
print(f"[+] Tech: {t} ({len(urls)} urls)")
tf = tempfile.NamedTemporaryFile(delete=False, mode='w')
for u in sorted(urls): tf.write(u+'\n')
tf.close()
tag = presets.get(t, {'tags': t}).get('tags', t)
if dry:
print(f"nuclei -l {tf.name} -tags {tag} -severity {severity} -o scans/nuclei_{t}.txt -silent")
else:
outdir = os.environ.get('OUTDIR','scans')
os.makedirs(outdir, exist_ok=True)
out = os.path.join(outdir, f'nuclei_{t}.txt')
subprocess.call(['nuclei','-l',tf.name,'-tags',tag,'-severity',severity,'-o',out,'-silent'])
print(f" nuclei -> {out}")
# Optional WordPress scan
if t == 'wordpress' and wpscan and shutil.which('wpscan') and not dry:
limit = 0
with open(tf.name,'r') as f:
for line in f:
u = line.strip()
if not u: continue
subprocess.call(['bin/web/wpscan_quick.sh', u])
limit += 1
if limit >= wpscan_limit: break
# Optional extra tech-specific quick wrappers
if extra and not dry:
limit = 0
with open(tf.name,'r') as f:
for line in f:
u=line.strip();
if not u: continue
if t == 'drupal' and shutil.which('droopescan'):
subprocess.call(['bin/web/droopescan_quick.sh', u])
elif t == 'joomla' and shutil.which('joomscan'):
subprocess.call(['bin/web/joomscan_quick.sh', u])
elif t == 'jenkins':
subprocess.call(['bin/web/jenkins_quick.sh', u])
elif t == 'sonarqube':
subprocess.call(['bin/web/sonarqube_quick.sh', u])
elif t == 'magento':
subprocess.call(['bin/web/magento_quick.sh', u])
elif t == 'jira':
subprocess.call(['bin/web/jira_quick.sh', u])
elif t == 'confluence':
subprocess.call(['bin/web/confluence_quick.sh', u])
limit += 1
if limit >= extra_limit: break