etc~ scripts and random things |
| git clone https://github.com/djnnvx/etc.git |
| log | files | refs | archive |
run-fuzzers.sh (5699B)
1 #!/bin/bash 2 # Run all TTYD fuzzers in tmux 3 # Two visible panes (one main per target), cmplog + secondaries run headless 4 # Safe to detach from SSH - everything persists in background 5 6 set -e 7 8 SESSION="ttyd-fuzz" 9 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 10 11 # Check dependencies 12 if ! command -v tmux &> /dev/null; then 13 echo "[!] tmux not found. Install with: sudo apt-get install tmux" 14 exit 1 15 fi 16 17 if ! command -v afl-fuzz &> /dev/null; then 18 echo "[!] afl-fuzz not found. Install AFL++ first." 19 exit 1 20 fi 21 22 # Check that harnesses are built 23 for harness in fuzz_websocket_auth fuzz_http_parsing; do 24 if [ ! -x "$SCRIPT_DIR/$harness" ]; then 25 echo "[!] $harness not found. Run ./build_fuzzers.sh first." 26 exit 1 27 fi 28 done 29 30 # Generate corpus if missing 31 for dir in websocket_auth http_parsing; do 32 if [ ! -d "$SCRIPT_DIR/corpus/$dir" ] || [ -z "$(ls -A "$SCRIPT_DIR/corpus/$dir" 2>/dev/null)" ]; then 33 echo "[*] Corpus missing. Run ./build_fuzzers.sh first to generate it." 34 exit 1 35 fi 36 done 37 38 # Find dictionaries 39 DICT_DIR="" 40 for candidate in /usr/share/afl++/dictionaries /usr/local/share/afl++/dictionaries "$SCRIPT_DIR/dictionaries"; do 41 if [ -d "$candidate" ]; then 42 DICT_DIR="$candidate" 43 break 44 fi 45 done 46 47 if [ -z "$DICT_DIR" ]; then 48 echo "[!] Warning: No AFL++ dictionaries directory found." 49 fi 50 51 # Calculate core allocation 52 TOTAL_CORES=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4) 53 CORES_PER_TARGET=$((TOTAL_CORES / 2)) 54 [ "$CORES_PER_TARGET" -lt 1 ] && CORES_PER_TARGET=1 55 56 echo "[*] System: $TOTAL_CORES cores, $CORES_PER_TARGET per target" 57 58 # Create output directories 59 mkdir -p "$SCRIPT_DIR/output/websocket_auth" "$SCRIPT_DIR/output/http_parsing" 60 61 # Kill existing session if running 62 tmux kill-session -t "$SESSION" 2>/dev/null || true 63 64 echo "[*] Starting fuzzing in tmux session: $SESSION" 65 echo 66 67 # Build afl-fuzz command 68 build_afl_cmd() { 69 local harness=$1 corpus=$2 output=$3 dict=$4 node_flag=$5 70 shift 5 71 local extra="$*" 72 local cmd="afl-fuzz -i $corpus -o $output $node_flag" 73 [ -n "$DICT_DIR" ] && [ -f "$DICT_DIR/$dict" ] && cmd="$cmd -x $DICT_DIR/$dict" 74 [ -n "$extra" ] && cmd="$cmd $extra" 75 cmd="$cmd -- ./$harness" 76 echo "$cmd" 77 } 78 79 # Custom mutator for http_parsing 80 HTTP_ENV="" 81 if [ -f "$SCRIPT_DIR/http_mutator.so" ]; then 82 HTTP_ENV="AFL_CUSTOM_MUTATOR_LIBRARY=$SCRIPT_DIR/http_mutator.so" 83 echo "[+] Using custom HTTP mutator for http_parsing" 84 fi 85 86 # ── Launch headless background nodes ────────────────────────────────────────── 87 # These run without a UI pane — they sync via the shared output dir 88 BG_PIDS=() 89 90 launch_bg() { 91 local env_prefix="$1" 92 local cmd="$2" 93 local logfile="$3" 94 (cd "$SCRIPT_DIR" && AFL_NO_UI=1 $env_prefix $cmd > "$logfile" 2>&1) & 95 BG_PIDS+=($!) 96 } 97 98 bg_count=0 99 100 for target_info in "fuzz_websocket_auth|websocket_auth|json.dict|" "fuzz_http_parsing|http_parsing|http.dict|$HTTP_ENV"; do 101 IFS='|' read -r harness corpus_dir dict env_prefix <<< "$target_info" 102 output="output/$corpus_dir" 103 corpus="corpus/$corpus_dir" 104 logdir="$SCRIPT_DIR/output/$corpus_dir" 105 106 # CmpLog secondary (if binary exists and we have cores) 107 if [ -x "$SCRIPT_DIR/${harness}_cmplog" ] && [ "$CORES_PER_TARGET" -ge 2 ]; then 108 cmd=$(build_afl_cmd "$harness" "$corpus" "$output" "$dict" "-S cmplog" "-c ./${harness}_cmplog") 109 launch_bg "$env_prefix" "$cmd" "$logdir/cmplog.log" 110 bg_count=$((bg_count + 1)) 111 fi 112 113 # Extra secondaries 114 used=2 # main + cmplog 115 remaining=$((CORES_PER_TARGET - used)) 116 for i in $(seq 1 $remaining); do 117 cmd=$(build_afl_cmd "$harness" "$corpus" "$output" "$dict" "-S sec_$i") 118 launch_bg "$env_prefix" "$cmd" "$logdir/sec_$i.log" 119 bg_count=$((bg_count + 1)) 120 done 121 done 122 123 echo "[*] Launched $bg_count headless secondary nodes" 124 125 # ── Create tmux: 2 panes (main nodes with UI) ──────────────────────────────── 126 ws_main=$(build_afl_cmd "fuzz_websocket_auth" "corpus/websocket_auth" "output/websocket_auth" "json.dict" "-M main") 127 http_main=$(build_afl_cmd "fuzz_http_parsing" "corpus/http_parsing" "output/http_parsing" "http.dict" "-M main") 128 129 tmux new-session -d -s "$SESSION" -n "fuzzers" \ 130 "cd '$SCRIPT_DIR' && $ws_main; echo '[!] Fuzzer exited'; read" 131 tmux split-window -h -t "$SESSION:fuzzers" \ 132 "cd '$SCRIPT_DIR' && $HTTP_ENV $http_main; echo '[!] Fuzzer exited'; read" 133 134 # ── Status window ───────────────────────────────────────────────────────────── 135 tmux new-window -t "$SESSION" -n "status" \ 136 "cd '$SCRIPT_DIR' && watch -n 10 'echo \"=== WebSocket Auth ===\"; echo; afl-whatsup -s output/websocket_auth 2>&1; echo; echo \"=== HTTP Parsing ===\"; echo; afl-whatsup -s output/http_parsing 2>&1'" 137 138 # Select fuzzers window 139 tmux select-window -t "$SESSION:fuzzers" 140 141 # Save background PIDs so clean.sh can kill them 142 printf '%s\n' "${BG_PIDS[@]}" > "$SCRIPT_DIR/.bg_fuzz_pids" 143 144 echo 145 echo "[+] All fuzzers started in tmux session: $SESSION" 146 echo " 2 main nodes (visible) + $bg_count headless secondaries" 147 echo 148 echo "Commands:" 149 echo " tmux attach -t $SESSION # Attach to session" 150 echo " Ctrl-b d # Detach (fuzzers keep running)" 151 echo " tmux kill-session -t $SESSION # Stop all fuzzers" 152 echo 153 echo "[*] You can safely disconnect from SSH. Fuzzers will keep running." 154 echo "[*] Crashes will be saved in output/*/main/crashes/"