369 lines
11 KiB
Bash
Executable File
369 lines
11 KiB
Bash
Executable File
#!/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
|