#!/usr/bin/env bash set -euo pipefail # Script Name: passive-recon # Description: Truly passive reconnaissance (no direct target contact) # Usage: passive-recon VERSION="1.0.0" # Colors readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' readonly BLUE='\033[0;34m' readonly CYAN='\033[0;36m' readonly MAGENTA='\033[0;35m' readonly BOLD='\033[1m' readonly NC='\033[0m' # Status indicators readonly GREENPLUS="${GREEN}[+]${NC}" readonly GREENSTAR="${YELLOW}[*]${NC}" readonly REDMINUS="${RED}[-]${NC}" readonly REDEXCLAIM="${RED}[!]${NC}" show_help() { echo -e "${BOLD}passive-recon${NC} - Truly Passive Reconnaissance v${VERSION}" echo echo -e "${BOLD}USAGE:${NC}" echo " passive-recon " echo echo -e "${BOLD}DESCRIPTION:${NC}" echo " Performs 100% PASSIVE reconnaissance with ZERO target contact" echo " All data gathered from third-party sources (DNS, certs, archives)" echo echo -e "${BOLD}WHAT IS PASSIVE?${NC}" echo " ✓ DNS lookups (public records)" echo " ✓ Certificate transparency logs" echo " ✓ Wayback Machine archives" echo " ✓ WHOIS lookups" echo " ✓ Shodan/censys (if API keys configured)" echo " ✓ GitHub dorking" echo " ✓ Subfinder/amass (passive mode)" echo echo " ✗ Port scanning (sends packets)" echo " ✗ Directory brute-forcing (sends HTTP requests)" echo " ✗ Web crawling (touches target)" echo echo -e "${BOLD}EXAMPLES:${NC}" echo " passive-recon example.com" echo " passive-recon target.htb" echo echo -e "${BOLD}OUTPUT:${NC}" echo " All results saved to: ./passive-recon--/" echo echo -e "${BOLD}WHY PASSIVE?${NC}" echo " • Undetectable (no IDS/IPS alerts)" echo " • Safe for bug bounty recon phase" echo " • Legal (public information only)" echo " • Fast (no rate limiting)" } # Check required tools check_tools() { local missing=() local optional_missing=() # Core tools command -v tmux &>/dev/null || missing+=("tmux") command -v dig &>/dev/null || missing+=("dig") command -v whois &>/dev/null || missing+=("whois") command -v curl &>/dev/null || missing+=("curl") command -v jq &>/dev/null || missing+=("jq") # Optional tools (all passive) command -v subfinder &>/dev/null || optional_missing+=("subfinder") command -v amass &>/dev/null || optional_missing+=("amass") command -v waybackurls &>/dev/null || optional_missing+=("waybackurls") command -v gau &>/dev/null || optional_missing+=("gau") if [[ ${#missing[@]} -gt 0 ]]; then echo -e "${RED}Error:${NC} Missing required tools: ${missing[*]}" exit 1 fi if [[ ${#optional_missing[@]} -gt 0 ]]; then echo -e "${YELLOW}⚠${NC} Optional tools missing (some scans will be skipped): ${optional_missing[*]}" echo -e "${CYAN}Install with:${NC}" for tool in "${optional_missing[@]}"; do case "$tool" in subfinder) echo " go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest" ;; amass) echo " go install -v github.com/owasp-amass/amass/v4/...@master" ;; waybackurls) echo " go install github.com/tomnomnom/waybackurls@latest" ;; gau) echo " go install github.com/lc/gau/v2/cmd/gau@latest" ;; esac done echo fi } # Create output directory setup_output_dir() { local domain="$1" local timestamp=$(date +%Y%m%d-%H%M%S) local clean_domain=$(echo "$domain" | tr '/:' '_' | tr -d 'http') OUTPUT_DIR="passive-recon-${clean_domain}-${timestamp}" mkdir -p "$OUTPUT_DIR" echo -e "${GREEN}✓${NC} Output directory: ${BOLD}$OUTPUT_DIR${NC}" } # Check if target is localhost check_localhost() { local domain="$1" if [[ "$domain" =~ ^(localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|::1)$ ]]; then return 0 # Is localhost fi return 1 # Not localhost } # Main passive-recon function run_passive_recon() { local domain="$1" # Strip http:// if provided domain=$(echo "$domain" | sed 's~https\?://~~g' | sed 's~/.*~~g') # Check if target is localhost if check_localhost "$domain"; then echo -e "${RED}${BOLD}" echo "╔════════════════════════════════════════════════════════════╗" echo "║ ⚠️ LOCALHOST DETECTED ⚠️ ║" echo "║ ║" echo "║ Passive recon doesn't work on localhost! ║" echo "║ No DNS records, certificates, or wayback data exists. ║" echo "║ ║" echo "║ Use instead: ║" echo "║ web-recon http://localhost:PORT ║" echo "║ web-attack http://localhost:PORT ║" echo "╚════════════════════════════════════════════════════════════╝" echo -e "${NC}" exit 1 fi echo -e "${CYAN}${BOLD}" echo "╔════════════════════════════════════════════════════════════╗" echo "║ Passive Reconnaissance (Zero Target Contact) ║" echo "║ Domain: $domain" echo "╚════════════════════════════════════════════════════════════╝" echo -e "${NC}" # Create output directory setup_output_dir "$domain" # Check if in tmux if [[ -z "${TMUX:-}" ]]; then echo -e "${YELLOW}⚠${NC} Not in tmux session - running sequentially" run_scans_sequential "$domain" return fi # Create tmux window with 4 panes tmux new-window -n "--> Passive: ${domain:0:15}... <--" # Split into 4 panes (2x2 grid) # CRITICAL: Tmux renumbers panes during splits # After all splits complete, panes are numbered: 1, 2, 3, 4 (NOT 0, 1, 2, 3) # [1: DNS/WHOIS] [2: Cert Transparency] # [3: Wayback] [4: Subdomain Enum ] # Create 2x2 grid layout tmux split-window -h tmux select-pane -t 0 tmux split-window -v tmux select-pane -t 2 tmux split-window -v # Force tiled layout for perfect 2x2 grid (equal-sized panes) tmux select-layout tiled # Final pane layout after tmux renumbering: 1 (TL), 2 (TR), 3 (BL), 4 (BR) # Pane 1 (top-left): DNS enumeration and WHOIS tmux select-pane -t 1 tmux send-keys "cd '$PWD/$OUTPUT_DIR' && echo -e '${GREENSTAR} DNS & WHOIS lookup...${NC}' && dig '$domain' ANY +noall +answer | tee dns.txt && echo && whois '$domain' | tee whois.txt && echo -e '${GREEN}✓ DNS/WHOIS complete${NC}'" C-m # Pane 2 (top-right): Certificate Transparency logs tmux select-pane -t 2 tmux send-keys "cd '$PWD/$OUTPUT_DIR' && echo -e '${GREENSTAR} Certificate Transparency logs...${NC}' && curl -s 'https://crt.sh/?q=%.$domain&output=json' | jq -r '.[].name_value' 2>/dev/null | sed 's/\*\.//g' | sort -u | tee subdomains-crt.txt && echo -e '${GREEN}✓ Cert transparency complete${NC}'" C-m # Pane 3 (bottom-left): Wayback Machine / historical URLs tmux select-pane -t 3 if command -v waybackurls &>/dev/null || command -v gau &>/dev/null; then tmux send-keys "cd '$PWD/$OUTPUT_DIR' && echo -e '${GREENSTAR} Wayback Machine historical URLs...${NC}' && (waybackurls '$domain' 2>/dev/null || gau '$domain' 2>/dev/null || echo 'No wayback tool available') | tee wayback-urls.txt && cat wayback-urls.txt | unfurl -u paths 2>/dev/null | sort -u | tee wayback-paths.txt || true && echo -e '${GREEN}✓ Wayback complete${NC}'" C-m else tmux send-keys "cd '$PWD/$OUTPUT_DIR' && echo -e '${YELLOW}⚠ waybackurls/gau not installed${NC}' && echo '# Install: go install github.com/tomnomnom/waybackurls@latest' && touch wayback-urls.txt" C-m fi # Pane 4 (bottom-right): Subdomain enumeration (passive only) tmux select-pane -t 4 if command -v subfinder &>/dev/null || command -v amass &>/dev/null; then tmux send-keys "cd '$PWD/$OUTPUT_DIR' && echo -e '${GREENSTAR} Passive subdomain enumeration...${NC}' && (subfinder -d '$domain' -silent 2>/dev/null || amass enum -passive -d '$domain' 2>/dev/null || echo 'No subdomain tool available') | tee subdomains-enum.txt && cat subdomains-*.txt 2>/dev/null | sort -u | tee all-subdomains.txt && echo -e '${GREEN}✓ Subdomain enum complete${NC}'" C-m else tmux send-keys "cd '$PWD/$OUTPUT_DIR' && echo -e '${YELLOW}⚠ subfinder/amass not installed${NC}' && echo '# Install: go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest' && touch subdomains-enum.txt all-subdomains.txt" C-m fi # Focus back on DNS pane tmux select-pane -t 1 echo echo -e "${GREEN}✓${NC} Tmux passive-recon window created" echo -e "${CYAN}[*]${NC} Switch to window: ${BOLD}--> Passive: ${domain:0:15}... <--${NC}" echo -e "${CYAN}[*]${NC} Results will be in: ${BOLD}$OUTPUT_DIR${NC}" echo echo -e "${MAGENTA}Note:${NC} 100% passive - no packets sent to target" } # Sequential execution (when not in tmux) run_scans_sequential() { local domain="$1" cd "$OUTPUT_DIR" echo -e "\n${GREENSTAR} Running DNS & WHOIS...${NC}" dig "$domain" ANY +noall +answer | tee dns.txt whois "$domain" | tee whois.txt echo -e "\n${GREENSTAR} Certificate Transparency...${NC}" curl -s "https://crt.sh/?q=%.$domain&output=json" | jq -r '.[].name_value' 2>/dev/null | sed 's/\*\.//g' | sort -u | tee subdomains-crt.txt echo -e "\n${GREENSTAR} Wayback Machine...${NC}" if command -v waybackurls &>/dev/null; then waybackurls "$domain" | tee wayback-urls.txt elif command -v gau &>/dev/null; then gau "$domain" | tee wayback-urls.txt fi echo -e "\n${GREENSTAR} Subdomain enumeration (passive)...${NC}" if command -v subfinder &>/dev/null; then subfinder -d "$domain" -silent | tee subdomains-enum.txt elif command -v amass &>/dev/null; then amass enum -passive -d "$domain" | tee subdomains-enum.txt fi cat subdomains-*.txt 2>/dev/null | sort -u | tee all-subdomains.txt cd .. echo -e "\n${GREEN}✓${NC} Passive recon complete! Results in: ${BOLD}$OUTPUT_DIR${NC}" } # Parse arguments if [[ $# -eq 0 ]] || [[ "$1" =~ ^(-h|--help|help)$ ]]; then show_help exit 0 fi domain="$1" # Validate domain if [[ -z "$domain" ]]; then echo -e "${RED}Error:${NC} Domain required" echo "Usage: passive-recon " exit 1 fi # Check tools check_tools # Run passive reconnaissance run_passive_recon "$domain"