🔭 Oculus — Full-Spectrum Recon Orchestration
One command. 37 modules. Five concurrent phases. Asset discovery through targeted exploitation — intelligently chained, resumable, and reported.
Inspiration
Security engagements are fragmented by design — but they don't have to be.
A typical bug bounty session means subfinder in one terminal, nuclei in another, manually piping alive hosts into sqlmap, forgetting to screenshot before the session dies, and losing hours re-running what already finished. Every tool is excellent in isolation. The problem is the glue — and the total lack of visibility into what's happening across 30+ tools running simultaneously against a live target.
I built Oculus to be that glue.
One command drives the entire engagement from asset discovery to targeted exploitation — orchestrated intelligently, resumable if interrupted, with four report formats ready whether the scan finishes cleanly or gets killed halfway through.
What It Does
Oculus is a recon-to-exploitation orchestration framework for bug bounty hunters and penetration testers on Kali/Debian Linux.
It doesn't replace your tools — it chains, schedules, and reports them — through both a full CLI/TUI and a real-time web cockpit.
# Core pipeline (modules 1–8)
python3 oculus.py -d target.com --full-recon --no-confirm
# Every module, all 5 phases, set and forget
python3 oculus.py -d target.com --full-spectrum --no-confirm
# Pick modules à la carte
python3 oculus.py -d target.com --module subdomain,alive,vuln,xss,crlfuzz
# Self-update
python3 oculus.py --update
Three Automation Modes
| Mode | Trigger | Scope | Est. Time |
|---|---|---|---|
| Full Auto Recon | --full-recon / [9] |
Core pipeline — subdomain → nuclei | 15–45 min |
| Deep Recon | --deep / [D] |
14 advanced modules, picks up post-enum | 1–3 hrs |
| Full Spectrum Scan | --full-spectrum / [U] |
All 37 modules across 5 concurrent phases | 2–6 hrs |
Full Spectrum — 5-Phase Concurrent Pipeline
Phase 1 — Discovery
[Sequential] Subdomain Enum → DNS Bruteforce → DNS Resolution → Alive Hosts → TLS Certificate Scan
[Concurrent] ASN Mapping · Cloud Assets · OSINT · Shodan · GitHub Dorking
Phase 2 — Infrastructure
[Concurrent] Fast Port Scan · Tech Fingerprint · WAF Detection · Screenshots · InternetDB Lookup
[Background] Full Port Scan (Nmap) · Web Server Scan (Nikto) — run as daemon threads, joined at end
Phase 3 — Content Discovery
[Sequential] URL Collection → Advanced Crawl (hakrawler)
[Background] URL Crawl (Cariddi) — runs as daemon thread
[Concurrent] Parameter Discovery · JS Endpoint + Secret Extraction
[Sequential] Subdomain Takeover Check
Phase 4 — Vulnerability Analysis
[Sequential] Nuclei Vulnerability Scan → GF Pattern Filters
[Background] Jaeles Signature Scan — runs as daemon thread
[Concurrent] Directory Fuzzing · API Route Fuzzing
Phase 5 — Targeted Exploitation
[Concurrent] SQLi · XSS · Open Redirect · CRLF Injection · SSTI · 403 Bypass
[Concurrent] CORS Misconfiguration · HTTP Request Smuggling
FINAL (always runs — even on Ctrl+C abort)
show_diff → summary.txt → report.html → findings.json → report.md
37 Modules. One Framework.
| # | Module | Tools | Output |
|---|---|---|---|
| 1 | Subdomain Enumeration | Subfinder, Amass, Assetfinder | subdomains.txt |
| 2 | DNS Resolution | dnsx | dns_resolved.txt |
| 3 | Alive Hosts | httpx + httprobe (concurrent dual-engine) | alive.txt |
| 4 | Fast Port Scan | Naabu / Nmap CDN fallback | ports_fast.txt |
| 5 | Full Port Scan | Nmap -p- -sV -sC -O (dynamic timeout scaling by host count) |
ports_full.txt |
| 6 | URL Collection | Katana, gau, waybackurls | urls_final.txt |
| 7 | WAF Detection | wafw00f + WhatWaf (deep fingerprint + bypass suggestions) | waf_summary.txt |
| 8 | Vulnerability Scan | Nuclei | nuclei/ |
| 10 | Parameter Discovery | ParamSpider, Arjun | parameters/ |
| 11 | JS Endpoints + Secrets | LinkFinder + 50+ secret regex patterns | js_endpoints/ |
| 12 | Directory Fuzzing | ffuf + nomore403 auto-feed on 403 results | fuzzing/ |
| 13 | API Route Fuzzing | Kiterunner | api_fuzzing/ |
| 14 | Subdomain Takeover | subzy + CNAME audit | takeover/ |
| 15 | Advanced Crawl | hakrawler | merged urls_final.txt |
| 16 | Screenshots | gowitness + EyeWitness (dual-engine) | screenshots/gowitness/ + screenshots/eyewitness/ |
| 17 | DNS Bruteforce | massdns + AlterX permutations + PureDNS wildcard filtering | massdns_out.txt |
| 18 | GF Pattern Filters | gf | gf/ (xss, sqli, ssrf, lfi, redirect, rce) |
| 19 | Tech Fingerprint | WhatWeb | tech_scan/ |
| 20 | SQLi | sqlmap + qsreplace preprocessing | sqlmap/ |
| 21 | XSS | Dalfox + qsreplace preprocessing | xss_findings/ |
| 22 | CORS Misconfiguration | Python worker pool | cors_findings/ |
| 23 | HTTP Smuggling | smuggler.py | smuggling/ |
| 24 | ASN / CIDR Mapping | asnmap | asn/ |
| 25 | Cloud Asset Discovery | S3 / GCS / Azure probes (open vs private differentiated) | cloud/ |
| 26 | GitHub Dorking | GitHub Code Search API | github/ |
| 27 | OSINT Harvesting | theHarvester | osint/ |
| 28 | Shodan Integration | Shodan API | shodan/ |
| 29 | Open Redirect | Python fuzzer + qsreplace preprocessing | redirects/ |
| 30 | Cariddi Crawl | Cariddi | cariddi/ (endpoints + secrets + extensions) |
| 31 | Jaeles Scan | Jaeles | jaeles/ (signature-based, different coverage than Nuclei) |
| 32 | SSTI Scan | Tplmap (safe detection only, no RCE execution) | tplmap/ |
| 33 | CRLF Injection | CRLFuzz | crlfuzz/ |
| 34 | InternetDB Lookup | Shodan InternetDB API (zero-auth, no packets sent) | internetdb/ |
| 35 | Nikto Web Server Scan | Nikto | nikto/ |
| 36 | TLS Certificate Scan | tlsx (SANs merged back into subdomains.txt) | tlsx/ |
| 37 | 403 Bypass | nomore403 | nomore403/ |
Key Engineering Capabilities
| Capability | Detail |
|---|---|
| Dual-engine alive probing | httpx (JSON) and httprobe (raw) run concurrently; results merged and deduplicated — zero dropped targets |
| Dual-engine screenshots | gowitness + EyeWitness both run per target; output segregated into separate subdirs |
| Non-blocking background Nmap | Full port scan runs as daemon=True thread — no UI lag during slow -p- scans |
| Non-blocking background tools | Nikto, Cariddi, and Jaeles also background-threaded; all four joined cleanly at end of pipeline |
| Smart DNS bruteforce chain | AlterX generates permutations → massdns bruteforces → PureDNS wildcard-filters — three-stage pipeline |
| Dynamic resolver fallback | DNS bruteforce auto-generates auto_resolvers.txt with 120+ global public resolvers if massdns resolvers file is missing |
| TLS SAN subdomain extraction | tlsx scans CN/SAN fields across 9 ports and merges discovered subdomains back into subdomains.txt automatically |
| qsreplace parameter injection | All parameter values replaced with FUZZ markers before SQLi, XSS, and open redirect scanning |
| nomore403 auto-feed | After ffuf fuzzes, any 403/401 results are automatically piped into nomore403 for bypass attempts |
| 50+ secret regex patterns | JS endpoint module hunts AWS keys, GitHub tokens, JWTs, Stripe, Slack, Firebase, private keys, DB connection strings, and more |
| Cariddi secret merge | cariddi crawl findings are cross-referenced into Module 11 secret output |
| crt.sh passive subdomain source | Zero-install cert transparency query integrated into Module 1 alongside subfinder/amass |
| InternetDB passive intel | Zero-auth Shodan API returns ports, CVEs, CPEs per IP — no packets sent to target |
| Open vs private cloud buckets | Cloud module separately logs accessible [OPEN] buckets from [EXISTS/PRIVATE] ones |
| Module Return Status Protocol | Modules return MODULE_OK / MODULE_SKIPPED / MODULE_PARTIAL / MODULE_FAILED — drives amber skip indicators in web UI |
| Session state + resume | Every run writes session.json; resume skips steps where result key exists AND non-empty artifact is on disk |
| Graceful Ctrl+C abort | Sets abort flag; remaining phases skipped; all four report formats still generate cleanly from partial data |
| Resilient HTML reporting | Every HTML section wrapped in try/except — aborted scans produce clean partial reports |
| Thread-safe concurrency | ThreadPoolExecutor + threading.Lock on shared state; per-phase scheduling with strict dependency ordering |
| ntfy push notifications | Interactive setup wizard (--setup-ntfy) configures status-tailored push alerts (start, findings, completion, errors, skips) |
| Dynamic Nmap timeout scaling | Full port scan timeout scales with alive host count via configurable base, per_host, and max YAML keys |
| Layered config | DEFAULT_CONFIG → ~/.config/oculus/config.yaml → CLI flags; tune threads, timeouts, rate limits, wordlists, API keys |
| Self-update | python3 oculus.py --update triggers git pull + reruns install.sh |
| Docker-ready | Kali rolling base with full toolchain pre-installed |
| Single-file core | Entire framework in one oculus.py — no framework overhead, drop-in portable |
Real-Time Web Cockpit
The web interface wraps the native Oculus class without touching oculus.py. A thread-safe ScanEngine singleton runs scans in-process — no subprocess spawning overhead.
Architecture
Browser (React 19)
│
├── REST API (FastAPI) ──── /api/scan/start · /api/scan/stop · /api/health
│ /api/config · /api/results/{domain}/* · /api/sessions/{domain}
│
└── WebSocket ─────────── ws://localhost:8000/ws/scan
Streams: logs + status every 500ms
Listens: {"action": "abort"} from client
Output Capture Pipeline
OutputCapture hooks sys.stdout at thread level
→ Strips ANSI escape codes
→ Feeds bounded queue (maxsize=50,000)
→ CLI terminal + backend logs + WebSocket all receive the same clean output
Web UI Features
🟢 Live Connection Monitor — polls /api/health every 3 seconds; pulsing neon dot reflects daemon state (ONLINE / OFFLINE) via CSS @keyframes pulse-dot
⚡ Optimization Presets — one-click execution profiles:
| Preset | Threads | Rate Limit | Timeout | Jitter | Severity |
|---|---|---|---|---|---|
| 🐉 Kali Linux Native | 100 | 300 | 240s | OFF | All |
| ⚡ High Performance | 200 | 800 | 300s | OFF | All |
| 🥷 Stealth Operations | 15 | 50 | 600s | ON | High + Critical |
🎯 Target Scope & Limits — collapsible configurator panel lets you customize max host/URL thresholds for Arjun, ffuf, Nikto, WhatWaf, Tplmap, and nomore403 — defaulting to unlimited for full-spectrum runs
🔁 Smart Resume Detector — /api/sessions/{domain} surfaces Resume Scan vs Start Fresh toggle at config time based on prior artifacts
🛑 Abort Confirmation Modal — requires explicit confirmation before dispatching termination; no accidental kills
📊 Skip-Resume Counter — when a resumed scan completes, progress bar and step counter snap to 100% regardless of skipped steps
📸 Screenshot Workspace — groups captures by inferred domain/subdomain, supports both engines, opens in near full-screen lightbox
⏩ Skipped Step Indicators — modules skipped due to missing binaries or API keys render amber fast-forward chips instead of green checks, keeping the dashboard honest
🔒 Path Traversal Protection — every artifact path is resolved and enforced to start within output-{domain}/ before serving
Multi-Format Reporting
Every run — whether it completes cleanly, resumes, or gets aborted at 40% — generates all four output formats:
| Format | File | Contents |
|---|---|---|
| HTML | report.html |
Dark theme, Chart.js visualizations, screenshot gallery, sortable findings |
| JSON | findings.json |
Machine-readable structured output for downstream tooling |
| Markdown | report.md |
HackerOne-style write-up, ready for submission |
| Summary | summary.txt |
Human-readable plaintext overview of all 37 module results |
Output Directory Structure
output-target.com/
├── session.json # Resume state
├── summary.txt # Quick-read scan summary
├── report.html # Dark-themed visual report
├── findings.json # Full structured export
├── report.md # HackerOne-ready markdown
├── subdomains.txt # All discovered subdomains (merged from all sources)
├── alive.txt # Live hosts (httpx + httprobe merged)
├── dns_resolved.txt # DNS records
├── urls_final.txt # All collected URLs
├── ports_fast.txt / ports_full.txt
├── screenshots/
│ ├── gowitness/
│ └── eyewitness/
├── cariddi/ # Crawl findings, secrets, endpoints
├── jaeles/ # Signature vulnerability findings
├── tplmap/ # SSTI detection results
├── crlfuzz/ # CRLF injection findings
├── internetdb/ # Passive port + vuln data
├── nikto/ # Web server scan results
├── tlsx/ # TLS SANs, cert data
├── nomore403/ # 403 bypass findings
├── gf/ # Pattern-classified URLs
├── nuclei/ # Vulnerability scan output
├── sqlmap/ xss_findings/ cors_findings/ smuggling/ redirects/
├── parameters/ js_endpoints/ fuzzing/ api_fuzzing/ takeover/
├── asn/ cloud/ github/ osint/ shodan/ tech_scan/ waf_summary.txt
└── logs/
├── oculus.log
└── errors.log
How It Was Built
Core (oculus.py, ~5,300 lines)
Single Python 3.8+ class using subprocess.Popen with streaming output, configurable timeouts, retry logic, and optional jitter. Every module method follows the same strict contract:
_require_setup() → _require_tool() → run logic → save_session()
Tool resolution searches PATH (augmented with ~/.local/bin, $GOPATH/bin, ~/go/bin), pip CLIs, /opt/recontools/ scripts, and Go binaries automatically.
Concurrency uses _run_concurrent() for parallel phase steps and _run_step() for sequential ones — both feeding the same session checkpoint with threading.Lock protecting shared state.
Background threading — Nmap, Nikto, Cariddi, and Jaeles run as daemon=True threads during their respective phases and are all joined cleanly at the end of the pipeline before reporting, so slow tools never block the scan.
Web Interface (web/)
The ScanEngine singleton instantiates Oculus directly in a background thread — no subprocess spawning. OutputCapture hooks sys.stdout, strips ANSI codes on the fly, and feeds a bounded queue.Queue(maxsize=50000). The FastAPI WebSocket endpoint polls every 500ms and streams logs + status to React 19.
Challenges
Dual-engine reconciliation — httpx outputs structured JSON; httprobe outputs raw hosts. Merging without dropping targets or introducing duplicates required format-aware parsing, not line concatenation.
37 tools, 37 exit code conventions — exit code 1 means "no results" for some tools and "crashed" for others. Consistent wrappers with tool-specific behavior took serious iteration.
Background thread progress tracking — the four background tools bypass the _run_step wrapper that feeds completed_modules. Needed a separate mechanism to append their names after join so the progress bar reaches 100%.
Resume logic correctness — detecting "already done" required two independent signals: a result key in session.json AND a non-empty artifact on disk. Either alone produced false positive skips.
tplmap false positive prevention — tplmap exits with code 0 whether or not it finds SSTI. Naive if result: would log every scanned URL as vulnerable. Fixed by parsing stdout for actual detection markers ("vulnerable", "[+]", "Engine:", "Injection:") before registering a finding.
nomore403 output preservation — naively passing the same -o file to 50 sequential nomore403 calls caused each run to overwrite the previous. Fixed by writing to unique per-URL temp files and merging.
In-process stdout capture — hooking sys.stdout at the thread level, stripping ANSI on the fly, feeding a bounded queue without blocking the scan thread, while also preserving output to the real terminal — non-trivial to get right simultaneously.
What I Learned
- How the full attack surface lifecycle fits together — and where hunters actually lose time (it's always the wiring, not the tools)
- Designing resumable, stateful CLI workflows with graceful abort and checkpoint recovery at scale
- Concurrent subprocess orchestration and the race conditions that only appear when 8 tools write to the same directory simultaneously
- Building a real-time web wrapper around an existing Python class without modifying it — thread-safe capture, WebSocket streaming, in-process execution
- The value of resilient reporting — a scan that crashes at 80% still needs readable output
- The gap between "tool installed" and "tool findable" across a mixed Go/pip/apt/git environment
- Why naive exit-code-based result detection fails for tools like tplmap — and how to parse actual output markers instead
What's Next
- 🧩 Plugin system — community-contributed modules with a standard interface
- 🎯 Scope-aware filtering — auto-parse in-scope/out-of-scope from HackerOne and Bugcrowd program pages
- 🔍 Cross-session report diffing — compare two scans and surface what changed
- 📊 Interactive finding triage — severity filtering, deduplication, and tagging in the web UI
- 🌍 ARM Docker + WSL2 — first-class support for non-Kali environments
- ⚙️ Rate profile presets — Stealth · Balanced · Aggressive selectable at runtime without YAML edits
Built With
Python 3.8+ · FastAPI · React 19 · WebSocket · Subfinder · Amass · Nuclei · httpx · httprobe · Nmap · Naabu · sqlmap · Dalfox · ffuf · Kiterunner · gowitness · EyeWitness · massdns · PureDNS · AlterX · hakrawler · theHarvester · Cariddi · Jaeles · Tplmap · CRLFuzz · Nikto · tlsx · nomore403 · WhatWaf · qsreplace · Shodan API · GitHub API · crt.sh API · InternetDB API · Docker · Kali Linux
Log in or sign up for Devpost to join the conversation.