This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Recon

Map every live host’s services, web surface, and content into a per-host picture you can attack.

Discovery told you what exists. Recon tells you what’s running on it. For each live host you build a profile: open ports, service versions, web apps, screenshots, and discovered content. This is the raw material the hunting phase mines for vulnerabilities.

Organize per host

Recon output is per-host. The convention (Arsenic’s hosts/ layout) keeps each host’s data isolated, so you can hand a teammate one host folder and they have everything:

hosts/
└── 203.0.113.10/
    └── recon/
        ├── nmap-quick-tcp.{nmap,gnmap,xml}   # full TCP port sweep
        ├── nmap-tcp.{nmap,gnmap,xml}         # version/script scan of open ports
        ├── nmap-udp.{nmap,gnmap,xml}
        ├── httpx.txt                          # live web services
        ├── ffuf.*.json                        # content discovery
        └── hostnames.txt                      # vhosts pointing at this IP

The recon pipeline

For each live host, in order:

  1. Port scanning — find every open TCP (and key UDP) port.
  2. Service enumeration — version + default-script scan the open ports to identify what’s listening.
  3. HTTP probing & screenshots — find web services across all hosts/ports and eyeball them fast.
  4. Content discovery — fuzz web roots for hidden paths, files, and endpoints.

Scan once per IP, remember every name

A single IP frequently hosts many domains (name-based virtual hosting). Port scan the IP so you don’t scan the same box ten times — but carry the list of hostnames forward, because the web server may serve completely different apps depending on the Host: header. The HTTP probing step is where vhosts matter most.

A note on pacing

Recon is the loudest phase so far — full port scans and fuzzing are unmistakable. Respect the rate limits from your rules of engagement: tune nmap -T, ffuf -rate, and run during permitted windows. When in doubt, go slower. A knocked-over production service is a bad look and a worse phone call.

Start with Port Scanning.

1 - Port Scanning

Find every open port on each live host — fast, then thorough — without scanning the same box twice.

The goal is the complete set of open ports on each host. The pattern that balances speed and completeness is two passes: a fast full-range sweep to find which ports are open, then a detailed scan of only those ports (covered in Service Enumeration).

Pass 1: fast full-range TCP sweep

Scan all 65,535 TCP ports quickly to find what’s open. I reach for one of two tools here.

nmap (the classic)

host=203.0.113.10
mkdir -p "hosts/$host/recon"

sudo nmap -p- --open -Pn -n \
  --min-rate 1500 --max-retries 1 \
  -T4 \
  "$host" \
  -oA "hosts/$host/recon/nmap-quick-tcp"

# Pull the open ports into a comma list for pass 2
ports=$(awk -F/ '/open/{print $1}' "hosts/$host/recon/nmap-quick-tcp.gnmap" \
        | tr '\n' ',' | sed 's/,$//')
  • -p- — all 65,535 ports.
  • --open — only report open ports.
  • -Pn — skip host discovery (you already know it’s up).
  • -n — no DNS resolution (faster, quieter).
  • --min-rate / --max-retries — speed knobs; raise min-rate on robust networks, lower it on fragile ones.

naabu (faster for many hosts)

naabu uses a SYN scan and is noticeably quicker across large host lists. Pipe its results straight into nmap for versioning:

naabu -host "$host" -p - -silent -o "hosts/$host/recon/naabu-tcp.txt"
ports=$(cut -d: -f2 "hosts/$host/recon/naabu-tcp.txt" | paste -sd,)

masscan is an option for very large IP ranges (it can scan the internet in minutes), but it trades accuracy for speed and needs careful rate limiting. For typical engagement-sized scope, nmap --min-rate or naabu is plenty.

Incremental / batched scanning for large scope

When you have many hosts, scanning every port on every host serially takes forever. Arsenic batches this: scan the most popular ports across all hosts first (you get fast, high-value coverage), then work through the remaining port ranges in batches. The idea is to surface the interesting services early instead of waiting for a full sweep of one host before starting the next.

A simple version — popular ports across everything first:

TOP_PORTS=$(sort -r -k3 /usr/share/nmap/nmap-services | awk '/\/tcp/{print $2}' \
            | cut -d/ -f1 | head -n 1000 | paste -sd,)

sudo nmap -sS -p"$TOP_PORTS" --open -Pn -n -T4 \
  --min-hostgroup 255 --max-retries 1 \
  -iL recon/ips/alive.txt \
  -oA recon/nmap-popular-tcp

Then schedule the full -p- sweep per host as time allows.

UDP — don’t skip it entirely

UDP scanning is slow, but skipping it misses SNMP, DNS, SChannel, IKE, TFTP, NetBIOS and other juicy services. Scan the top UDP ports rather than all of them:

sudo nmap -sU --top-ports 100 --open -Pn -n -T4 \
  "$host" -oA "hosts/$host/recon/nmap-udp"

With the open-port list in hand, move to Service Enumeration to find out what’s actually listening.

2 - Service Enumeration

Identify the exact software and version behind every open port — the input every later step depends on.

Knowing port 8080 is open tells you little. Knowing it’s Apache Tomcat 9.0.30 tells you what default paths to check, what CVEs apply, and what credentials to try. Service enumeration turns open ports into identified, versioned services.

Version + default-script scan

Run nmap against only the ports you found open in port scanning, with version detection and the default safe scripts. This is the deep, accurate scan, so let it take its time:

host=203.0.113.10
ports=$(awk -F/ '/open/{print $1}' "hosts/$host/recon/nmap-quick-tcp.gnmap" \
        | tr '\n' ',' | sed 's/,$//')

sudo nmap -p"$ports" -sV -sC -A -Pn -n \
  --host-timeout 30m \
  "$host" \
  -oA "hosts/$host/recon/nmap-tcp"

What the flags do:

  • -sV — probe for service/version.
  • -sC — run the default NSE script set (banner grab, titles, common checks).
  • -A — aggressive: adds OS detection, traceroute, and more scripts. Drop it if you need to be quieter; -sV -sC alone is the high-signal core.
  • --host-timeout — don’t let one stubborn host stall the whole run.

The two output formats you’ll use constantly:

  • .nmap — human-readable; read it.
  • .xml — machine-readable; feed it to searchsploit, reporting tools, and importers.

What to extract

Walk every host’s .nmap output and pull out:

  • Service + version for each port → drives vulnerability hunting.
  • HTTP/HTTPS services (including odd ports like 8000, 8443, 3000) → feed to HTTP probing.
  • TLS cert names → may surface new vhosts/domains (loop back to discovery).
  • Anonymous/guessable access flagged by NSE scripts (FTP anon login, open SMB shares, exposed RPC).

Targeted NSE for interesting services

When -sC flags something, follow up with service-specific scripts. A few I reach for a lot:

# SMB — shares, users, known vulns
nmap -p139,445 --script "smb-enum-shares,smb-enum-users,smb-vuln-*" "$host"

# HTTP — titles, methods, common files
nmap -p80,443 --script "http-title,http-methods,http-headers,http-enum" "$host"

# SSL/TLS — protocols, ciphers, weaknesses
nmap -p443 --script "ssl-enum-ciphers,ssl-cert" "$host"

Quick service inventory across all hosts

To get a one-line-per-service overview for triage:

grep -hP '^\d+/(tcp|udp)\s+open' hosts/*/recon/nmap-*.nmap \
  | awk '{print $1, $3, $4, $5, $6, $7}' \
  | sort | uniq -c | sort -rn

This tells you at a glance “we have 40 web servers, 12 SSH, 6 RDP, 3 Tomcat” — which decides where to spend the hunting phase.

Next: get eyes on the web surface with HTTP Probing & Screenshots.

3 - HTTP Probing & Screenshots

Find every live web service across all hosts and ports, then screenshot them to triage the web surface at a glance.

Web is where most findings live. After port scanning you have a pile of open ports that might be HTTP; this step confirms which ones actually serve web content — on which scheme and port, with what title and technology — then screenshots them so you can eyeball hundreds of apps in minutes.

Probe with httpx

I use httpx (ProjectDiscovery) for this. Feed it every host and every web-ish port; it works out http vs https, follows redirects, and reports a bunch of metadata.

# Build the candidate list: every hostname + IP you care about
# (httpx will try each on the ports you specify)
httpx -l recon/web-candidates.txt \
  -p 80,443,8000,8001,8080,8443,3000,8843,9000 \
  -title -status-code -tech-detect -web-server -content-length \
  -follow-redirects \
  -json -o recon/httpx.json -silent

# Plain list of live URLs for the next steps
jq -r '.url' recon/httpx.json | sort -u | tee recon/live-urls.txt

The flags that matter:

  • -tech-detect — Wappalyzer-style fingerprinting (CMS, framework, server). Really useful for the hunting phase.
  • -title -status-code -web-server — fast triage columns.
  • -follow-redirects — catches apps that bounce http→https or to a login.

Virtual hosts matter here. The same IP can serve different apps per Host: header, so probe by hostname, not just IP, and name-based vhosts get discovered. If you have many names on one IP, httpx handles the list — just make sure the hostnames (not only IPs) are in your candidate file.

Screenshot the web surface

Eyeballing screenshots is the fastest way to spot login panels, default install pages, admin consoles, and abandoned apps across a large estate.

Arsenic originally used aquatone for this. Aquatone is archived now, so I use one of these instead.

Option A — gowitness (what I use)

gowitness scan file -f recon/live-urls.txt \
  --screenshot-path report/static/screenshots \
  --write-db   # SQLite report you can browse
gowitness report server   # browse at http://localhost:7171

Option B — httpx built-in screenshots

If you’d rather not add a tool, httpx can screenshot during the probe:

httpx -l recon/web-candidates.txt -p 80,443,8080,8443 \
  -screenshot -srd report/static/screenshots -silent

Option C — aquatone (still works)

If you’re maintaining an existing aquatone-based flow:

cat recon/live-urls.txt \
  | aquatone -ports 80,443,3000,8000,8001,8080,8443 \
             -out report/static/aquatone

Open the report and bucket what you see:

  • Login panels → credential testing, default creds, auth bypass.
  • Default/install pages → unconfigured apps, often exploitable.
  • Admin consoles (Tomcat Manager, Jenkins, phpMyAdmin, Grafana) → high-value targets; check default creds immediately.
  • Errors / stack traces → version disclosure, debug endpoints.
  • Parked / blank → deprioritize.

Promising apps go to Content Discovery for deeper fuzzing, and the whole live-URL list feeds vulnerability hunting.

4 - Content Discovery

Fuzz web roots for hidden directories, files, and endpoints the app doesn’t link to.

Apps expose far more than their navigation shows: /admin, /.git/, /backup.zip, /api/v1, /.env, old /test.php files. Content discovery brute-forces paths against a wordlist to find them. Run it against every live web service from HTTP probing.

Pick a fuzzer

Arsenic supports gobuster, dirb, and ffuf, defaulting to ffuf. The two I actually use:

  • ffuf — fast, flexible, good filtering; my default.
  • feroxbuster — recursive by default, nice for deep trees.

Wordlists

SecLists is where I pull wordlists from. A solid general-purpose stack (this mirrors Arsenic’s default web-content set):

Discovery/Web-Content/common.txt
Discovery/Web-Content/raft-medium-words.txt
Discovery/Web-Content/raft-large-directories.txt
Discovery/Web-Content/quickhits.txt
Discovery/Web-Content/RobotsDisallowed-Top1000.txt

Build a combined, de-duplicated list once:

cat /opt/SecLists/Discovery/Web-Content/{common,raft-medium-words,quickhits}.txt \
  | sort -u > recon/wordlist-web-content.txt

Tailor it to the tech you fingerprinted: a Tomcat box gets tomcat.txt, a Jenkins box gets Jenkins-Hudson.txt, and so on.

Run ffuf

url="https://app.example.com"
host=app.example.com
mkdir -p "hosts/$host/recon"

ffuf -u "$url/FUZZ" \
     -w recon/wordlist-web-content.txt \
     -ac \
     -mc all -fc 404 \
     -recursion -recursion-depth 2 \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0" \
     -of json -o "hosts/$host/recon/ffuf.json"

What the flags do (these match the Arsenic as-ffuf defaults):

  • -acauto-calibration: ffuf learns the “not found” response shape and filters it automatically. You need this, or you drown in false positives.
  • -mc all -fc 404 — match everything, filter out 404s. Lets you see 401/403 (exists but protected) and 500 (something broke = interesting).
  • -recursion -recursion-depth 2 — dig into discovered directories.
  • -e .php,.bak,.zip,.txt — add extension fuzzing when you know the stack.

Tune signal, not noise

Auto-calibration handles most of the junk, but apps that return 200 for everything need manual filtering. Inspect the size/word/line distribution and filter the dominant bucket:

# How many results per status code?
jq '.results[].status' hosts/app.example.com/recon/ffuf.json | sort | uniq -c

# Filter by response size if a wildcard 200 is flooding results
ffuf -u "$url/FUZZ" -w wordlist.txt -fs 1234   # filter that exact size

Arsenic’s as-prune-ffuf does exactly this after the fact — trimming the dominant status/size bucket out of a bloated results file so what’s left is signal.

What to chase

From the results, prioritize:

  • Auth panels & admin paths (/admin, /manager, /wp-admin).
  • Source/secrets leakage (/.git/, /.env, /config.php.bak, /backup/).
  • APIs (/api, /swagger, /graphql) — often under-protected.
  • Anything 403 — it exists and someone tried to hide it.

Discovered endpoints and the technologies you fingerprinted both feed the Vulnerability Hunting phase.