MrCl0wnLab/SimpleReconSubdomain
GitHub: MrCl0wnLab/SimpleReconSubdomain
Stars: 31 | Forks: 7
# SimpleReconSubdomain v2

Passive and active subdomain enumeration tool for OSINT and reconnaissance workflows.
Built with async Python - queries **47 sources** (39 passive + 8 active) in parallel with no external shell dependencies.
Techniques inspired by **subfinder**, **amass**, **puredns** and **subjack**:
multi-probe wildcard detection, DNSSEC NSEC zone walking, TLS SAN extraction, SRV record mining, two-pass trusted-resolver validation, recursive enumeration, JavaScript link extraction, and subdomain-takeover fingerprinting.
Author: MrCl0wn
Blog: https://blog.mrcl0wn.com
GitHub: https://github.com/MrCl0wnLab
Twitter: https://twitter.com/MrCl0wnLab
## WARNING
+------------------------------------------------------------------------------+
| [!] Legal disclaimer: Usage of SimpleReconSubdomain for attacking |
| targets without prior mutual consent is illegal. |
| It is the end user's responsibility to obey all applicable |
| local, state and federal laws. |
| Developers assume no liability and are not responsible for any misuse or |
| damage caused by this program. |
+------------------------------------------------------------------------------+
## Table of Contents
- [Installation](#installation)
- [API Keys](#api-keys)
- [Usage](#usage)
- [Profiles](#profiles)
- [Run-Config Presets](#run-config-presets)
- [Passive vs Active Modules](#passive-vs-active-modules)
- [Sources](#sources)
- [DNS Brute-force](#dns-brute-force)
- [TLD Brute-force](#tld-brute-force)
- [Advanced Techniques](#advanced-techniques)
- [Subdomain Takeover Detection](#subdomain-takeover-detection)
- [Output Formats](#output-formats)
- [Chaining with Other Tools](#chaining-with-other-tools)
- [Creating a New Module](#creating-a-new-module)
## Installation
git clone https://github.com/MrCl0wnLab/SimpleReconSubdomain
cd SimpleReconSubdomain
pip install -r requirements.txt
**Dependencies** (`requirements.txt`):
| Package | Purpose |
|---|---|
| `httpx` | Async HTTP client for all passive sources and resolver URL download |
| `aiodns` | Async DNS resolver for brute-force and validation |
| `dnspython` | Zone transfer (AXFR), DNS record mining, NSEC zone walking, SRV enumeration |
## API Keys
API keys are stored in `config/api_keys.json` (gitignored to prevent leaks).
{
"alienvault_otx": "",
"hackertarget": "",
"urlscan": "",
"virustotal": "",
"securitytrails": "",
"shodan": "",
"github_token": "",
"censys_id": "",
"censys_secret": "",
"grayhatwarfare_token": "",
"leakix_token": "",
"fullhunt_token": "",
"chaos_key": "",
"c99_key": "",
"netlas_key": "",
"onyphe_key": "",
"greynoise_key": "",
"fofa_key": "",
"pulsedive_key": "",
"intelx_key": "",
"publicwww_key": "",
"merklemap_key": "",
"bevigil_key": "",
"hunterhow_key": "",
"circl_user": "",
"circl_pass": ""
}
**Where to get each key:**
| Key | URL |
|---|---|
| `alienvault_otx` | https://otx.alienvault.com → Settings → API Integration |
| `hackertarget` | https://hackertarget.com/membership |
| `urlscan` | https://urlscan.io/user/signup |
| `virustotal` | https://www.virustotal.com/gui/join-us |
| `securitytrails` | https://securitytrails.com/app/account |
| `shodan` | https://account.shodan.io |
| `censys_id` / `censys_secret` | https://search.censys.io/account/api |
| `github_token` | https://github.com/settings/tokens (scope: `public_repo`) |
| `grayhatwarfare_token` | https://grayhatwarfare.com/account |
| `leakix_token` | https://leakix.net/login → API Keys |
| `fullhunt_token` | https://fullhunt.io/user/api |
| `chaos_key` | https://chaos.projectdiscovery.io → API Key |
| `c99_key` | https://api.c99.nl → Sign up |
| `netlas_key` | https://app.netlas.io/profile/ → API Keys |
| `onyphe_key` | https://www.onyphe.io/login/ → API |
| `greynoise_key` | https://viz.greynoise.io/account/ |
| `fofa_key` | https://fofa.so/userInfo |
| `pulsedive_key` | https://pulsedive.com/api/ |
| `intelx_key` | https://intelx.io/account?tab=developer |
| `publicwww_key` | https://publicwww.com/api.html |
| `merklemap_key` | https://www.merklemap.com/dashboard/api (paid subscription required) |
| `bevigil_key` | https://bevigil.com/osint-api → Sign up |
| `hunterhow_key` | https://hunter.how/api → Get API key |
| `circl_user` / `circl_pass` | https://www.circl.lu/services/passive-dns/ → Request access (optional; free unauthenticated tier available) |
## Usage
### Basic
# Single domain
python simplerecon.py -d target.com
# List of domains
python simplerecon.py -l domains.txt
# List available sources
python simplerecon.py --list-sources
# List available profiles (curated source groups)
python simplerecon.py --list-profiles
# Print built-in usage examples and exit
python simplerecon.py --list-examples
# Run a predefined profile (no need to spell out sources)
python simplerecon.py -d target.com --profile fast
python simplerecon.py -d target.com --profile osint --verify-live

### OSINT Context Examples
**Bug bounty - map external attack surface (passive only):**
python simplerecon.py -d megacorp.com \
--sources crtsh,virustotal,shodan,censys,github,chaos \
--output json --outfile megacorp_subs.json
**Full enumeration - passive + brute-force + live verification:**
python simplerecon.py -d target.com \
--brute wordlists/subdomains-top1million-20000.txt \
--resolvers config/resolvers.txt \
--wildcard-tests 5 \
--validate-resolvers \
--verify-live \
--output json \
--outfile target_full.json
python simplerecon.py -d target.com \
--brute wordlists/all.txt \
--resolvers https://public-dns.info/nameservers-all.txt \
--check-resolvers \
--validate-resolvers \
--threads 40
**Deep recon - include active sources and recursive enumeration:**
python simplerecon.py -d target.com \
--sources crtsh,certspotter,github,chaos,nsec_walk,srv_enum \
--brute wordlists/top5000.txt \
--recursive --recursive-depth 2 \
--verify-live \
--output json --outfile deep_recon.json
**DNSSEC zone walking (requires NSEC, not NSEC3):**
python simplerecon.py -d target.com --sources nsec_walk -v
**Asset discovery from a domain list:**
python simplerecon.py -l scope.txt --output json --outfile all_subs.json --timeout 60
**Quiet mode - pipe subdomains directly to another tool:**
python simplerecon.py -d target.com --no-banner | httpx -silent
### All Flags
Target:
-d DOMAIN Single target domain
-l FILE File with one domain per line
--stdin Read domains from stdin (one per line); enables pipe-friendly use
Output:
-o {txt,json,csv,ndjson}
Output format (default: txt).
ndjson = one compact JSON line per subdomain - ideal for jq piping
--outfile FILE Write output to file
Performance:
-t N Thread multiplier for brute-force concurrency (default: 8)
--timeout N HTTP/DNS timeout in seconds (default: 30)
--rate-limit N Max concurrent HTTP requests per source (0 = unlimited)
Network:
--proxy URL Route all HTTP requests through a proxy
(e.g. http://127.0.0.1:8080 or socks5://host:port)
--user-agent UA Override User-Agent for all source HTTP requests
Source control:
--profile PROFILE Run a predefined source group (fast, stealth, osint,
code, active, full). Overrides --sources.
--sources LIST Comma-separated sources (default: all)
--exclude LIST Comma-separated sources to exclude (applied after --sources/--profile)
--no-passive Skip passive sources; run active/brute only
--list-sources Print all sources with descriptions and exit
--list-profiles Print all profiles with their source sets and exit
--list-examples Print built-in usage examples and exit
Run-config:
--config FILE Load CLI argument defaults from a JSON preset file.
Only keys absent from the command line are applied;
explicit CLI flags always win.
Template: config/run_config.example.json
Brute-force:
--brute WORDLIST Wordlist path for DNS brute-force
--resolvers FILE_OR_URL
DNS resolver IPs - local file or https:// URL
(e.g. config/resolvers.txt or https://public-dns.info/nameservers-all.txt)
--check-resolvers Test each resolver against example.com before brute-force;
remove non-responsive ones (PureDNS technique)
--wildcard-tests N Random probes for wildcard detection (default: 3)
Higher values reduce false negatives on load-balanced DNS
--validate-resolvers Re-validate results against Google/Cloudflare after brute-force
to eliminate DNS-poisoned false positives (PureDNS two-pass)
--permute Generate Altdns-style permutations from found subdomains
--tld-brute [FILE] Discover live TLD variants of the target (e.g. target.net, target.io).
Strips the current TLD, resolves {base}.{tld} for every entry in the
wordlist. Optional FILE overrides the default config/tlds.txt (~250 TLDs).
Results are stored separately as tld_variants in all output formats.
Post-processing:
--verify-live HTTP/HTTPS probe; also extracts TLS certificate SANs (Amass technique)
and fingerprints potential subdomain takeovers (Subjack technique)
--recursive Re-enumerate discovered subdomains as new targets (Subfinder technique)
--recursive-depth N Max recursion depth when --recursive is enabled (default: 1)
Display:
-v [LEVEL] Verbose level 1–4 (1=zero results, 2=+HTTP codes, 3=+body, 4=+exceptions)
-q, --quiet Results only; suppress all process messages
--no-banner Suppress banner and all process output (clean pipe mode)
--no-color Disable ANSI colors

## Profiles
Profiles are curated source groups defined in [config/profiles.json](config/profiles.json). Use `--profile NAME` instead of typing long `--sources` lists. Profiles may also set defaults (e.g. `rate_limit`) automatically.
python simplerecon.py --list-profiles
python simplerecon.py -d target.com --profile fast
| Profile | Description | Sources |
|---|---|---|
| `fast` | Quick scan - fastest no-auth sources only | `crtsh`, `certspotter`, `hackertarget`, `rapiddns`, `jldc`, `alienvault`, `anubisdb`, `subdomaincenter`, `urlhaus`, `circl`, `bing` |
| `stealth` | Minimal footprint - passive only, rate-limited (`rate_limit=2`) | `crtsh`, `certspotter`, `wayback`, `commoncrawl`, `robtex`, `anubisdb` |
| `osint` | Code repos + threat intel + CT logs + asset DBs | `crtsh`, `certspotter`, `alienvault`, `virustotal`, `shodan`, `github`, `grep_app`, `threatminer`, `anubisdb`, `subdomaincenter`, `hackertarget`, `rapiddns`, `urlscan`, `bevigil`, `hunterhow`, `urlhaus`, `circl`, `bing` |
| `code` | Code search only | `github`, `grep_app` |
| `active` | Active techniques only | `zone_transfer`, `dns_mining`, `nsec_walk`, `srv_enum`, `js_scrape`, `ptr_sweep`, `vhost_probe` |
| `full` | All available passive and active sources | `all` |
Add or edit profiles by modifying [config/profiles.json](config/profiles.json):
{
"myprofile": {
"description": "My custom set",
"sources": ["crtsh", "github", "shodan"],
"options": {"rate_limit": 5}
}
}
## Run-Config Presets
A run-config is a JSON file that stores CLI argument defaults, allowing you to run repeatable scans without long command lines.
python simplerecon.py -d target.com --config config/run_config.example.json
python simplerecon.py -d target.com --config my_scan.json
**Precedence (highest → lowest):**
1. Explicit CLI flags (always win)
2. Values from the `--config` JSON file
3. Built-in argparse defaults
Only keys present in the JSON are applied; unknown keys are silently ignored so configs stay forward/backward compatible. A minimal config is perfectly valid — you only need to include the keys you want to set:
{
"profile": "osint",
"verify_live": true,
"output": "json",
"outfile": "results.json"
}
The annotated template at [config/run_config.example.json](config/run_config.example.json) documents every available key. Copy and edit it to create your own preset.
# List-examples shows ready-to-copy command patterns
python simplerecon.py --list-examples
## Passive vs Active Modules
### Passive
Passive sources query **third-party databases, APIs, and public indexes**. No packet is sent to the target's infrastructure.
- Safe to run during passive recon phases
- Invisible to the target's security monitoring
- Examples: Certificate Transparency logs, Shodan, VirusTotal, GitHub code search, Common Crawl
### Active
Active sources **communicate directly with the target's DNS servers**. The target can observe this traffic.
| Module | What it does | Detection level |
|---|---|---|
| `zone_transfer` | AXFR attempt on all nameservers | **High** - connects to target NS |
| `dns_mining` | SPF / DMARC / MX / TXT record queries | **Moderate** - DNS queries to target NS |
| `nsec_walk` | DNSSEC NSEC chain walking to enumerate entire zone | **High** - queries authoritative NS directly |
| `srv_enum` | SRV record enumeration for ~70 common service prefixes | **Moderate** - DNS queries to public resolvers |
| `js_scrape` | Fetches the target's root HTML, downloads every linked `.js` file, and regex-extracts subdomains hardcoded in JS bundles | **High** - direct HTTP requests to target |
| `spider` | Crawls the target site following `` links (max depth 2, 50 pages), extracts subdomains from every page | **High** - direct HTTP requests to target |
| `ptr_sweep` | Reverse-DNS PTR sweep on /24 blocks containing target IPs | **Moderate** - DNS queries to public resolvers |
| `vhost_probe` | Virtual-host brute-force via HTTP Host-header fuzzing | **High** - direct HTTP requests to target |
Active modules are included in `--sources all`. To run them explicitly:
# Run only active sources
python simplerecon.py -d target.com --no-passive --sources zone_transfer,dns_mining,nsec_walk,srv_enum,js_scrape,spider
# Mix passive + specific active
python simplerecon.py -d target.com --sources crtsh,shodan,nsec_walk,srv_enum,js_scrape
# Or just use the curated active profile
python simplerecon.py -d target.com --profile active
## Sources
python simplerecon.py --list-sources
### Passive Sources (39)
| Source | Requires key | Notes |
|---|---|---|
| `rapiddns` | No | DNS dataset |
| `jldc` | No | Anubis subdomain DB |
| `crtsh` | No | Certificate Transparency |
| `certspotter` | No | Certificate Transparency |
| `merklemap` | Required | CT log aggregator (alternative to crt.sh) - paid subscription required |
| `anubisdb` | No | jonlu.ca passive DNS subdomain database |
| `subdomaincenter` | No | Netcraft-backed free subdomain index |
| `threatminer` | No | ThreatMiner passive DNS / threat intel |
| `urlscan` | Optional | Higher rate limit with key |
| `hackertarget` | Optional | Higher rate limit with key |
| `wayback` | No | web.archive.org CDX API (paginated, up to 200k entries) |
| `commoncrawl` | No | Common Crawl CDX API - independent historical crawl data |
| `robtex` | No | Passive DNS |
| `alienvault` | Optional | OTX threat intelligence |
| `bufferover` | No | Rapid7 FDNS via TLS |
| `dnsdumpster` | No | DNS recon tool (web scraping) |
| `github` | Required | Code search for hardcoded domain references |
| `grep_app` | No | grep.app GitHub code search |
| `virustotal` | Required | VT subdomains endpoint |
| `securitytrails` | Required | DNS history |
| `censys` | Required | Certificate search |
| `shodan` | Required | DNS domain lookup |
| `grayhatwarfare` | Required | Public cloud buckets (AWS/Azure/GCP) |
| `leakix` | Optional | Exposed services and cloud assets |
| `fullhunt` | Required | Full internet host & subdomain index |
| `chaos` | Required | ProjectDiscovery continuously updated subdomain DB |
| `c99` | Required | C99.nl subdomain finder |
| `netlas` | Required | Internet-wide asset and subdomain discovery |
| `onyphe` | Required | Cyber defense search engine |
| `greynoise` | Required | Internet noise / passive scanner data |
| `fofa` | Optional | FOFA internet asset search (free scrape fallback when no key) |
| `pulsedive` | Optional | Threat-intel observable lookup |
| `intelx` | Required | IntelligenceX leaked data search |
| `publicwww` | Required | Source-code search across the public web |
| `bevigil` | Required | BeVigil OSINT - subdomains extracted from mobile apps |
| `hunterhow` | Required | Hunter.how global asset database |
| `urlhaus` | No | URLhaus abuse.ch malicious URL database - no auth needed |
| `circl` | No (Optional Basic auth) | CIRCL Passive DNS - public free tier; key gives higher rate |
| `bing` | No | Bing search - multi-template UA-rotating anti-bot scraping |
### Active Sources (8)
| Source | Requires key | Notes |
|---|---|---|
| `zone_transfer` | No | DNS Zone Transfer (AXFR) |
| `dns_mining` | No | SPF / DMARC / MX record mining |
| `nsec_walk` | No | DNSSEC NSEC zone walking |
| `srv_enum` | No | SRV record enumeration (~70 service prefixes) |
| `js_scrape` | No | Fetches target HTML + linked JS files, extracts subdomains via regex |
| `spider` | No | HTML link crawler — follows `` links up to depth 2 (max 50 pages), extracts subdomains from every visited page; complements `js_scrape` |
| `ptr_sweep` | No | Reverse-DNS PTR sweep on /24 blocks containing target IPs |
| `vhost_probe` | No | Virtual-host brute-force via HTTP Host-header fuzzing (130+ word built-in list) |

## DNS Brute-force
### Recommended Wordlists
| Wordlist | Size | Use case |
|---|---|---|
| `subdomains-top1million-5000.txt` | 5k | Fast initial scan |
| `subdomains-top1million-20000.txt` | 20k | Standard bug bounty |
| `subdomains-top1million-110000.txt` | 110k | Thorough enumeration |
| `best-dns-wordlist.txt` (Assetnote) | ~9M | Deep pentest |
# Clone SecLists
git clone --depth 1 https://github.com/danielmiessler/SecLists.git
# Or download a single file
wget https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/subdomains-top1million-20000.txt
# Assetnote wordlist (generated from real CT log data)
wget https://wordlists-cdn.assetnote.io/data/manual/best-dns-wordlist.txt
### Custom DNS Resolvers
By default the tool uses 6 built-in resolvers (Google, Cloudflare, Quad9, OpenDNS). For large-scale brute-force, supply a bigger list:
# Bundled list (~30 verified public resolvers)
python simplerecon.py -d target.com --brute wordlist.txt \
--resolvers config/resolvers.txt
# Download a community list on-the-fly (7000+ resolvers)
python simplerecon.py -d target.com --brute wordlist.txt \
--resolvers https://public-dns.info/nameservers-all.txt
# With health check - filters dead resolvers before brute-force
python simplerecon.py -d target.com --brute wordlist.txt \
--resolvers https://public-dns.info/nameservers-all.txt \
--check-resolvers
`--resolvers` accepts:
- A local file path (`config/resolvers.txt`, one IP per line, comments with `#` supported, `ip:port` format accepted)
- An `http://` or `https://` URL (downloaded automatically via `httpx`)
The list is deduplicated and **shuffled** automatically to distribute load across all resolvers.
Other public resolver sources:
- https://github.com/trickest/resolvers
- https://public-dns.info/nameservers-all.txt
### Full Brute-force Example
# Fast - bundled resolvers, no validation
python simplerecon.py -d target.com \
--brute wordlists/top5000.txt \
--resolvers config/resolvers.txt \
--threads 20
# Thorough - community resolvers, health check, two-pass validation
python simplerecon.py -d target.com \
--brute wordlists/subdomains-top1million-20000.txt \
--resolvers https://public-dns.info/nameservers-all.txt \
--check-resolvers \
--wildcard-tests 5 \
--validate-resolvers \
--threads 30
## TLD Brute-force
`--tld-brute` discovers live registrations of the target domain under other TLDs (e.g. `target.net`, `target.io`, `target.com.br`). Useful for brand protection, typosquatting detection, and mapping the full domain portfolio of a target.
# Use the built-in wordlist (~250 TLDs)
python simplerecon.py -d target.com --tld-brute
# Use a custom TLD list
python simplerecon.py -d target.com --tld-brute custom_tlds.txt
# Combine with passive enumeration and live verification
python simplerecon.py -d target.com --tld-brute --verify-live -o json --outfile results.json
The tool strips the current TLD from the target (handling compound TLDs like `.co.uk` and `.com.br` automatically), then resolves `{base}.{tld}` for every entry in the wordlist. Only variants that resolve in DNS are returned.
Results appear in a separate `tld_variants` field in JSON/CSV/NDJSON output and are printed to the terminal at the end of each run.
The default wordlist is [config/tlds.txt](config/tlds.txt). Edit it or supply your own file with `--tld-brute FILE`.
## Advanced Techniques
### Multi-probe Wildcard Detection (PureDNS)
Instead of a single random-subdomain probe (unreliable under DNS load balancing), the tool fires `--wildcard-tests N` probes and confirms wildcard only when ≥ ceil(N/2) resolve. The **union of all returned IPs** is used as the filter set during brute-force.
python simplerecon.py -d target.com --brute wordlist.txt --wildcard-tests 5
### Two-pass Trusted Resolver Validation (PureDNS)
After mass brute-force with cheap public resolvers, re-validate against Google/Cloudflare only. Eliminates false positives from DNS poisoning on untrusted resolvers.
python simplerecon.py -d target.com --brute wordlist.txt --validate-resolvers
### TLS Certificate SAN Extraction (Amass)
During `--verify-live`, the tool performs a raw SSL handshake on port 443 and extracts **Subject Alternative Names** from the server certificate. Newly discovered hostnames are added back to the subdomain set.
python simplerecon.py -d target.com --verify-live --output json --outfile out.json
# JSON output includes "tls_sans": ["cdn.target.com", "api.target.com", ...] per live host
### DNSSEC NSEC Zone Walking (Amass)
NSEC records form a sorted linked list of every name in the DNS zone. The `nsec_walk` source traverses the chain to enumerate the entire zone without a zone transfer. Works only when the domain uses **NSEC** (not NSEC3 - the module detects and reports this automatically).
python simplerecon.py -d target.com --sources nsec_walk -v
# Example domain with NSEC: nlnetlabs.nl
### SRV Record Enumeration (Amass)
Queries ~70 common SRV prefixes (`_http._tcp`, `_ldap._tcp`, `_kerberos._tcp`, `_autodiscover._tcp`, `_sip._tcp`, etc.). SRV records frequently reveal internal hostnames not found through passive sources.
python simplerecon.py -d target.com --sources srv_enum -v
The prefix list is in `config/srv_prefixes.json` - edit it to add domain-specific services.
### Recursive Enumeration (Subfinder)
After enumerating `target.com`, discovered subdomains like `api.target.com` are themselves used as enumeration targets to find deeper entries (`v2.api.target.com`, `internal.api.target.com`, etc.).
python simplerecon.py -d target.com --recursive --recursive-depth 2
### GitHub Code Search
Searches GitHub for source code files containing references to the target domain (hardcoded subdomains in configs, `.env` files, CI scripts). Requires a `github_token` in `config/api_keys.json`.
python simplerecon.py -d target.com --sources github -v
## Subdomain Takeover Detection
When `--verify-live` is enabled, each live host is checked for takeover signals via **three independent methods**:
| Method | How | Field |
|---|---|---|
| Body fingerprint | Response body matched against ~30 service signatures | `takeover` |
| CNAME chain | Full CNAME chain walked; suffix matched against 21 services | `takeover: "cname:"` |
| WAF / CDN | Response headers fingerprinted against 11 providers | `waf` |
python simplerecon.py -d target.com --verify-live -o json --outfile out.json
[LIVE] orphan.target.com → 404 - NoSuchBucket [TAKEOVER? aws-s3]
[LIVE] docs.target.com → 404 - There isn't a GitHub Pages site here. [TAKEOVER? cname:github-pages]
[LIVE] api.target.com → 200 - API Gateway [cloudflare]
**Takeover-detectable services (body + CNAME):**
`aws-s3`, `github-pages`, `heroku`, `netlify`, `fastly`, `shopify`, `ghost-io`, `surge-sh`, `zendesk`, `readme-io`, `unbounce`, `webflow`, `squarespace`, `hubspot`, `freshdesk`, `sendgrid`, `uservoice`, `wpengine`, `pantheon`, `teamwork`, `acquia`, `bigcartel`
**WAF / CDN fingerprinting:**
`cloudflare`, `akamai`, `fastly`, `cloudfront`, `incapsula`, `sucuri`, `azure-cdn`, `google`, `imperva`, `barracuda`, `f5-big-ip`
All fingerprints are defined in [verify/live_check.py](verify/live_check.py) (`_TAKEOVER_CNAME`, `_TAKEOVER_BODY`, `_WAF_HEADERS`) - edit there to add new services.
### jq recipes for takeover triage
python simplerecon.py -d target.com --verify-live -o ndjson \
| jq 'select(.takeover != null)'
# Only CNAME-based hits
python simplerecon.py -d target.com --verify-live -o ndjson \
| jq 'select(.takeover | strings | startswith("cname:"))'
# Show WAF-protected hosts
python simplerecon.py -d target.com --verify-live -o ndjson \
| jq 'select(.waf != null) | {subdomain, waf, status}'
# JSON outfile - extract takeover candidates
jq -r '.live_hosts | to_entries[] | select(.value.takeover != null) | .key' out.json \
| dnsx -silent -cname -resp
## Output Formats
### Terminal (default)
------------------------------------------------------------
[*] Enumerating: target.com
------------------------------------------------------------
[*] Running passive sources...
[*] [crtsh] +42 subdomains
[*] [github] +8 subdomains
[*] [chaos] +12 subdomains
[*] [nsec_walk] +31 subdomains
[*] [srv_enum] +3 subdomains
[+] Total unique subdomains found: 72
api.target.com
dev.target.com
mail.target.com
...
### JSON
python simplerecon.py -d target.com --verify-live -o json --outfile results/target.json
{
"domain": "target.com",
"timestamp": "2026-05-27T14:32:01.123456",
"total": 72,
"subdomains": [
"api.target.com",
"dev.target.com",
"mail.target.com"
],
"live_hosts": {
"api.target.com": {
"status": 200,
"title": "API Gateway",
"server": "nginx/1.24.0",
"content_length": 1842,
"url": "https://api.target.com",
"tls_sans": ["api.target.com", "*.api.target.com", "cdn.target.com"],
"cname": null,
"waf": "cloudflare",
"takeover": null
},
"orphan.target.com": {
"status": 404,
"title": "",
"server": "AmazonS3",
"content_length": 320,
"url": "https://orphan.target.com",
"tls_sans": [],
"cname": "orphan.target.com.s3-website-us-east-1.amazonaws.com",
"waf": null,
"takeover": "cname:aws-s3"
}
},
"sources": {
"crtsh": 42,
"github": 8,
"chaos": 12,
"nsec_walk": 31,
"srv_enum": 3,
"tls_sans": 5
}
}
### CSV
python simplerecon.py -d target.com --verify-live -o csv --outfile results/target.csv
domain,subdomain,status,title,server,tls_sans,takeover,cname,waf
target.com,api.target.com,200,API Gateway,nginx/1.24.0,api.target.com|*.api.target.com,,,cloudflare
target.com,mail.target.com,200,Webmail,Apache/2.4,,,
target.com,orphan.target.com,404,,AmazonS3,,cname:aws-s3,orphan.target.com.s3-website-us-east-1.amazonaws.com,
### NDJSON
One compact JSON line per subdomain - designed for streaming and `jq` piping.
python simplerecon.py -d target.com --verify-live -o ndjson
python simplerecon.py -d target.com --verify-live -o ndjson --outfile results/target.ndjson
{"domain": "target.com", "subdomain": "api.target.com", "status": 200, "title": "API Gateway", "server": "nginx/1.24.0", "waf": "cloudflare"}
{"domain": "target.com", "subdomain": "orphan.target.com", "status": 404, "server": "AmazonS3", "cname": "orphan.target.com.s3-website-us-east-1.amazonaws.com", "takeover": "cname:aws-s3"}
{"domain": "target.com", "subdomain": "dev.target.com"}
**jq examples:**
# Live hosts only
python simplerecon.py -d target.com --verify-live -o ndjson | jq 'select(.status != null)'
# Takeover candidates
python simplerecon.py -d target.com --verify-live -o ndjson | jq 'select(.takeover != null)'
# WAF-protected hosts
python simplerecon.py -d target.com --verify-live -o ndjson | jq 'select(.waf != null) | {subdomain, waf}'
# Extract only subdomains (pipe-friendly)
python simplerecon.py -d target.com -o ndjson | jq -r '.subdomain'
### TXT
python simplerecon.py -d target.com -o txt --outfile results/target.txt
## Advanced Usage
### Custom User-Agent
python simplerecon.py -d target.com --user-agent 'Mozilla/5.0 (compatible; MyScanner/1.0)'
### Excluding sources
# Run everything except noisy/slow sources
python simplerecon.py -d target.com --exclude github,intelx,publicwww
# Profile with overrides
python simplerecon.py -d target.com --profile osint --exclude merklemap,chaos
### Stdin / pipe targets
# Explicit flag
echo 'target.com' | python simplerecon.py --stdin -o ndjson
# Auto-detected when stdin is not a TTY
cat domains.txt | python simplerecon.py -o txt
# Chain with amass, subfinder, or other tools
subfinder -silent -d target.com | python simplerecon.py --stdin --sources crtsh,virustotal
### httpx - HTTP probing
python simplerecon.py -d target.com --no-banner | httpx -silent -status-code -title -tech-detect
# Filter only 200 OK
python simplerecon.py -d target.com --no-banner | httpx -silent -mc 200
### nmap - port scan
python simplerecon.py -d target.com -o txt --outfile subs.txt
nmap -iL subs.txt -p 80,443,8080,8443 -T4 --open
### nuclei - vulnerability scanning
python simplerecon.py -d target.com --no-banner \
| httpx -silent \
| nuclei -t cves/ -silent
### dnsx - DNS resolution and CNAME chasing
# Find potential subdomain takeovers
python simplerecon.py -d target.com --no-banner \
| dnsx -silent -cname -resp \
| grep -E 'amazonaws|azurewebsites|github.io|herokuapp'
### eyewitness - screenshots
python simplerecon.py -d target.com --verify-live -o txt --outfile subs.txt
eyewitness --web -f subs.txt --no-prompt -d screenshots/
### SimpleReconSubdomain - enrichment and automation
[SimpleReconSubdomain](https://github.com/MrCl0wnLab/SimpleReconSubdomain) (`String-x (aka strx)`) is a modular automation tool using a `{STRING}` placeholder. It pairs naturally with SimpleReconSubdomain via pipes.
# HTTP probe all discovered subdomains
python simplerecon.py -d target.com --no-banner \
| strx -st "echo {STRING}" -module "clc:http_probe" -pm
# Resolve subdomains → extract IPs → Shodan lookup per IP
python simplerecon.py -d target.com --no-banner \
| strx -st "echo {STRING}" -module "clc:dns" -pm \
| strx -st "echo {STRING}" -module "ext:ip" -pm \
| strx -st "echo {STRING}" -module "clc:shodan" -pm
# Enrich with DNS + geolocation in a single chain
python simplerecon.py -d target.com --no-banner \
| strx -st "echo {STRING}" -module "clc:dns|ext:ip|clc:geoip" -pm
# Send live subdomains to Telegram
python simplerecon.py -d target.com --no-banner \
| strx -st "echo {STRING}" -module "con:telegram" -pm
## Creating a New Module
All sources inherit from `BaseSource` in `sources/base.py`. Drop the file in `sources/passive/` or `sources/active/` - no other file needs editing.
The class name must be the **title-cased filename** (e.g. `myservice.py` → class `Myservice`), and `NAME` must equal the filename without `.py`.
### New Passive Source
# sources/passive/myservice.py
import httpx
from sources.base import BaseSource
from core.config import get_key
class Myservice(BaseSource):
NAME = 'myservice'
DESCRIPTION = 'My custom service'
API_TOKEN_IS_REQUIREMENT = True
async def fetch(self, domain: str) -> set[str]:
api_key = get_key('myservice')
if not api_key:
return set()
subdomains: set[str] = set()
async with httpx.AsyncClient(timeout=self.timeout) as client:
resp = await self._get(client, f'https://api.myservice.com/subdomains/{domain}')
if resp.status_code == 200:
for entry in resp.json().get('data', []):
subdomains.add(entry['hostname'])
return self._filter(subdomains, domain)
Add the key to `config/api_keys.json`:
{ "myservice": "your-api-key-here" }
### New Active Source
Use `asyncio.wait_for` + `run_in_executor` for blocking DNS calls to prevent hangs:
# sources/active/myactive.py
import asyncio
from sources.base import BaseSource
class Myactive(BaseSource):
NAME = 'myactive'
DESCRIPTION = 'Active: custom DNS probe'
API_TOKEN_IS_REQUIREMENT = False
async def fetch(self, domain: str) -> set[str]:
loop = asyncio.get_event_loop()
try:
return await asyncio.wait_for(
loop.run_in_executor(None, self._run, domain),
timeout=max(self.timeout, 30),
)
except asyncio.TimeoutError:
self._vlog(1, 'timed out')
return set()
def _run(self, domain: str) -> set[str]:
subdomains: set[str] = set()
try:
import dns.resolver
# ... blocking dnspython calls here ...
except Exception as exc:
self._log_exc(exc)
return self._filter(subdomains, domain)
## 📄 LICENÇA
Este projeto está licenciado sob a Licença Apache - veja o arquivo [LICENSE](LICENSE) para detalhes.
## 👨💻 AUTOR
**MrCl0wn**
- 🌐 **Blog**: [http://blog.mrcl0wn.com](http://blog.mrcl0wn.com)
- 🐙 **GitHub**: [@MrCl0wnLab](https://github.com/MrCl0wnLab)
- 🐦 **Twitter**: [@MrCl0wnLab](https://twitter.com/MrCl0wnLab)
- 📧 **Email**: mrcl0wnlab\@\gmail.com
**⭐ Se este projeto foi útil, considere dar uma estrela!**
**💡 Sugestões e feedbacks são sempre bem-vindos!**
**💀 Hacker Hackeia!**