#!/usr/bin/env bash # The Analyzer v2 — Discovery Engine # Finds actual URLs, forms, parameters, and endpoints on the target # This feeds the exploit vectors with real attack surface SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../lib/utils.sh" discover_target() { local target="$1" local domain=$(get_domain "$target") local base=$(get_base "$target") local outfile="$REPORTS_DIR/.${domain}_discovery.txt" print_info "Discovering attack surface on $target..." separator local DISCOVERED_URLS="" local DISCOVERED_FORMS="" local DISCOVERED_PARAMS="" local DISCOVERED_ENDPOINTS="" # 1. Crawl the homepage for links and forms print_sub "Crawling homepage for links..." local page=$(curl -s --connect-timeout 10 --max-time 20 -L "$target" 2>/dev/null) if [ -z "$page" ]; then print_error "Cannot fetch target page" return 1 fi # Extract all internal links local links=$(echo "$page" | perl -nle 'while (/href="([^"]+)"/g) { print $1 }' | sort -u) local internal_links="" while IFS= read -r link; do [ -z "$link" ] && continue # Make absolute if [[ "$link" == /* ]]; then link="${base}${link}" elif [[ "$link" == http* ]]; then # External link — skip unless same domain local link_domain=$(echo "$link" | sed 's|https\?://||' | cut -d/ -f1) [[ "$link_domain" != "$domain" ]] && continue else link="${base}/${link}" fi internal_links+="$link\n" DISCOVERED_URLS+="$link\n" done <<< "$links" local url_count=$(echo -e "$DISCOVERED_URLS" | grep -c .) print_ok "Found $url_count internal URLs" # 2. Extract forms print_sub "Extracting forms..." local forms=$(echo "$page" | perl -0 -nle 'while (/]*>.*?<\/form>/gs) { print $& }') local form_count=0 while IFS= read -r form; do [ -z "$form" ] && continue form_count=$((form_count + 1)) local form_action=$(echo "$form" | perl -nle 'print $1 if /action="([^"]*)"/') local form_method=$(echo "$form" | perl -nle 'print $1 if /method="([^"]*)"/' | tr '[:upper:]' '[:lower:]') local form_inputs=$(echo "$form" | perl -nle 'print $1 while /name="([^"]*)"/g') # Make action URL absolute if [[ "$form_action" == / ]]; then form_action="$base/" elif [[ "$form_action" == /* ]]; then form_action="${base}${form_action}" elif [[ "$form_action" == http* ]] && ! echo "$form_action" | grep -qi "$domain"; then continue # skip external forms elif [ -z "$form_action" ]; then form_action="$target" # submits to current page fi DISCOVERED_FORMS+="$form_count|$form_method|$form_action|$form_inputs\n" DISCOVERED_URLS+="$form_action\n" DISCOVERED_PARAMS+="$form_inputs\n" print_info "Form #$form_count: [$form_method] $form_action -> params: $form_inputs" done <<< "$forms" print_ok "Found $form_count form(s)" # 3. Extract URL parameters from existing links print_sub "Finding URL parameters..." local url_params=$(echo -e "$DISCOVERED_URLS" | perl -nle 'while (/[?&]([^=]+)=/g) { print $1 }' | sort -u) while IFS= read -r p; do [ -z "$p" ] && continue DISCOVERED_PARAMS+="$p\n" done <<< "$url_params" local param_count=$(echo -e "$DISCOVERED_PARAMS" | grep -c .) print_ok "Found $param_count parameter(s): $(echo -e "$DISCOVERED_PARAMS" | tr '\n' ' ')" # 4. Check common API paths print_sub "Probing API endpoints..." local api_paths=( "/api" "/api/v1" "/api/v2" "/v1" "/v2" "/graphql" "/graph" "/gql" "/rest" "/swagger" "/openapi" "/docs" "/api/docs" "/api/swagger" "/api/openapi" ) for path in "${api_paths[@]}"; do local code=$(http_check "${base}${path}") if [[ "$code" =~ ^[23] ]]; then DISCOVERED_ENDPOINTS+="${base}${path} (HTTP $code)\n" print_info "API: ${base}${path} (HTTP $code)" fi done # 5. Check for JS files that might leak endpoints print_sub "Scanning JS for endpoint leaks..." local js_urls=$(echo "$page" | perl -nle 'print $1 while /src="([^"]*\.js[^"]*)"/g' | head -10) while IFS= read -r js; do [ -z "$js" ] && continue [[ "$js" == /* ]] && js="${base}${js}" [[ "$js" != http* ]] && continue local js_content=$(curl -s --connect-timeout 5 --max-time 10 "$js" 2>/dev/null) local leaked_endpoints=$(echo "$js_content" | perl -nle 'print $1 while m|["\x27](/api/[^"\x27]+)["\x27]|g' | sort -u | head -10) if [ -n "$leaked_endpoints" ]; then print_info "JS leak: $js" while IFS= read -r ep; do [ -z "$ep" ] && continue DISCOVERED_ENDPOINTS+="${base}${ep} (JS leak)\n" print_find " Leaked endpoint: ${ep}" done <<< "$leaked_endpoints" fi done <<< "$js_urls" # 6. Save everything to a discovery file cat > "$outfile" << EOF TARGET=$target DOMAIN=$domain BASE=$base URLS: $(echo -e "$DISCOVERED_URLS" | sort -u | grep -v '^$') FORMS: $(echo -e "$DISCOVERED_FORMS" | sort -u | grep -v '^$') PARAMS: $(echo -e "$DISCOVERED_PARAMS" | sort -u | grep -v '^$') ENDPOINTS: $(echo -e "$DISCOVERED_ENDPOINTS" | sort -u | grep -v '^$') EOF print_ok "Discovery complete. Saved to $(basename $outfile)" separator # Summary local total_urls=$(echo -e "$DISCOVERED_URLS" | grep -c .) local total_forms=$(echo -e "$DISCOVERED_FORMS" | grep -c .) local total_params=$(echo -e "$DISCOVERED_PARAMS" | grep -c .) local total_eps=$(echo -e "$DISCOVERED_ENDPOINTS" | grep -c .) echo "" echo -e " ${BOLD}Discovery Summary:${NC}" echo -e " ${CYAN}URLs:${NC} $total_urls" echo -e " ${CYAN}Forms:${NC} $total_forms" echo -e " ${CYAN}Params:${NC} $total_params" echo -e " ${CYAN}Endpoints:${NC} $total_eps" return 0 } # Get discovered data for a target get_discovered_urls() { local domain="$1" local file="$REPORTS_DIR/.${domain}_discovery.txt" if [ -f "$file" ]; then sed -n '/^URLS:/,/^FORMS:/p' "$file" | grep -v "^URLS:\|^FORMS:\|^\$" fi } get_discovered_forms() { local domain="$1" local file="$REPORTS_DIR/.${domain}_discovery.txt" if [ -f "$file" ]; then sed -n '/^FORMS:/,/^PARAMS:/p' "$file" | grep -v "^FORMS:\|^PARAMS:\|^\$" fi } get_discovered_params() { local domain="$1" local file="$REPORTS_DIR/.${domain}_discovery.txt" if [ -f "$file" ]; then sed -n '/^PARAMS:/,/^ENDPOINTS:/p' "$file" | grep -v "^PARAMS:\|^ENDPOINTS:\|^\$" fi } get_discovered_endpoints() { local domain="$1" local file="$REPORTS_DIR/.${domain}_discovery.txt" if [ -f "$file" ]; then sed -n '/^ENDPOINTS:/,$p' "$file" | grep -v "^ENDPOINTS:\|^\$" fi }