Skip to content

Instantly share code, notes, and snippets.

@cholmboe
Created November 26, 2025 14:35
Show Gist options
  • Select an option

  • Save cholmboe/3f1a25c0be3456fd4a94f2550d815688 to your computer and use it in GitHub Desktop.

Select an option

Save cholmboe/3f1a25c0be3456fd4a94f2550d815688 to your computer and use it in GitHub Desktop.

Subdomain Analysis Tool

A bash script that discovers, resolves, and analyzes subdomains of a target domain. It performs subdomain enumeration from Certificate Transparency logs, DNS resolution, HTTP probing, and generates a comprehensive CSV report.

Overview

The tool performs a complete subdomain analysis in four steps:

  1. Discovery: Fetches subdomains from crt.sh Certificate Transparency logs
  2. DNS Resolution: Resolves A, AAAA, and CNAME records for all discovered subdomains
  3. HTTP Probing: Probes HTTP/HTTPS endpoints to gather status codes, redirects, page titles, and technology stack
  4. Reporting: Generates a CSV report with all findings, including live subdomains, dead domains, and those that resolve but have no HTTP service

Requirements

  • jq - JSON processor
  • dnsx - DNS resolution tool
  • httpx - HTTP probe tool

Installation

# macOS
brew install jq
brew install projectdiscovery/tap/dnsx
brew install projectdiscovery/tap/httpx

# Linux
sudo apt-get install jq  # or: sudo yum install jq
go install -v github.com/projectdiscovery/dnsx/cmd/dnsx@latest
go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest

Usage

./analyse_subdomains.sh <domain>

Example:

./analyse_subdomains.sh epidemicsound.com

Output

The script creates a timestamped directory (e.g., analysis-20251126-1437/) containing:

  • report.csv - Main analysis report (see format below)
  • subdomains.txt - List of all discovered subdomains
  • dns.json - DNS resolution results
  • http.json - HTTP probe results
  • resolved.txt - Subdomain-to-IP mapping

Report Format

The CSV report includes all discovered subdomains with the following columns:

Column Description
subdomain Subdomain name
ip Resolved IP address (IPv4/IPv6) or "-"
cname CNAME record or "-"
status HTTP status code or "-"
redirect Redirect location or "-"
title Page title or "-"
tech Detected technologies (semicolon-separated) or "-"

The report includes:

  • Live subdomains with full HTTP data
  • Resolved subdomains that have DNS but no HTTP service
  • Dead subdomains that don't resolve to any IP
#!/usr/bin/env bash
set -euo pipefail
DOMAIN="${1:-}"
OUTDIR="analysis-$(date +%Y%m%d-%H%M)"
mkdir -p "$OUTDIR"
if [[ -z "$DOMAIN" ]]; then
echo "Usage: $0 <domain>"
exit 1
fi
# Check for required tools
MISSING_TOOLS=()
if ! command -v jq &> /dev/null; then
MISSING_TOOLS+=("jq")
fi
if ! command -v dnsx &> /dev/null; then
MISSING_TOOLS+=("dnsx")
fi
if ! command -v httpx &> /dev/null; then
MISSING_TOOLS+=("httpx")
fi
if [[ ${#MISSING_TOOLS[@]} -gt 0 ]]; then
echo "[!] Error: Missing required tools: ${MISSING_TOOLS[*]}"
echo "[!] Please install the missing tools and try again."
exit 1
fi
echo "[*] Target domain: $DOMAIN"
echo "[*] Output directory: $OUTDIR"
CRT_RAW="$OUTDIR/crt_raw.json"
SUBDOMAINS="$OUTDIR/subdomains.txt"
RESOLVED="$OUTDIR/resolved.txt"
DNS_JSON="$OUTDIR/dns.json"
HTTP_JSON="$OUTDIR/http.json"
REPORT="$OUTDIR/report.csv"
echo "[*] Fetching subdomains from crt.sh..."
curl -s "https://crt.sh/?q=%25.$DOMAIN&output=json" > "$CRT_RAW"
jq -r '.[].name_value' "$CRT_RAW" \
| sed 's/\*\.//g' \
| tr '\n' '\n' \
| sort -u > "$SUBDOMAINS"
COUNT=$(wc -l < "$SUBDOMAINS")
echo "[*] Found $COUNT unique subdomains"
echo "[*] Resolving DNS..."
dnsx -l "$SUBDOMAINS" -a -aaaa -cname -json -o "$DNS_JSON"
jq -r '.host + " " + (.a[0] // .aaaa[0] // "NO_IP")' "$DNS_JSON" > "$RESOLVED"
LIVE_COUNT=$(grep -vc "NO_IP" "$RESOLVED")
echo "[*] $LIVE_COUNT subdomains resolve to IPs"
echo "[*] Probing HTTP(S)..."
cut -d' ' -f1 "$RESOLVED" | httpx -json -location -status-code -title -tech-detect -o "$HTTP_JSON"
echo "[*] Building final report..."
echo "subdomain,ip,cname,status,redirect,title,tech" > "$REPORT"
# Add live subdomains from HTTP results
jq -r '
[
.input,
(.a[0] // .aaaa[0] // "-"),
((.cname[0] // "-")),
(.status_code // "-"),
(.location // "-"),
(.title // "-"),
((.tech | join(";")) // "-")
] | @csv
' "$HTTP_JSON" >> "$REPORT"
# Add all subdomains from resolved.txt that aren't already in the report
# This includes subdomains that resolve but have no HTTP response, and dead domains
while IFS=' ' read -r subdomain ip; do
# Check if subdomain is not already in the report
if ! grep -q "^\"$subdomain\"," "$REPORT"; then
# Get CNAME from DNS JSON
cname=$(jq -r "select(.host == \"$subdomain\") | .cname[0] // \"-\"" "$DNS_JSON" 2>/dev/null || echo "-")
if [[ "$ip" == "NO_IP" ]]; then
# Dead domain - no DNS resolution
echo "\"$subdomain\",\"-\",\"$cname\",\"-\",\"-\",\"-\",\"-\"" >> "$REPORT"
else
# Resolves but no HTTP response (timeout, no HTTP service, etc.)
echo "\"$subdomain\",\"$ip\",\"$cname\",\"-\",\"-\",\"-\",\"-\"" >> "$REPORT"
fi
fi
done < "$RESOLVED"
echo "[+] Analysis complete"
echo
echo "Artifacts:"
echo " - Subdomains: $SUBDOMAINS"
echo " - DNS records: $DNS_JSON"
echo " - HTTP results: $HTTP_JSON"
echo " - Final report: $REPORT"
echo
echo "[*] Redirect summary:"
awk -F',' '$5 !~ /^"-"$/ && NR>1 {print $1 " -> " $5}' "$REPORT" || true
echo
echo "[*] Dead subdomains (no DNS):"
grep "NO_IP" "$RESOLVED" || true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment