
نص برمجي بلغة Python لإثبات المفهوم (PoC) لثغرة CVE-2026-3456 يوضح الاستيلاء على الحساب من خلال حالة سباق (race condition) في OAuth2 PKCE، ويتضمن خادم مصادقة هشًا ونص استغلال لمُحقِّق الكود (code-verifier) يعمل بشكل متزامن.
يسمح وجود حالة سباق (Race Condition) في خادم تفويض OAuth2 للمهاجم بإعادة استخدام رمز تفويض الضحية قبل أن يستردّه العميل الشرعي، عبر تخمين code_verifier الخاص بـ PKCE أو فرضه بالقوة الغاشمة خلال نافذة زمنية صغيرة.
الخطورة: عالية (الاستيلاء على الحساب)
#!/usr/bin/env python3
"""
vulnerable_auth_server.py - Authorization server with race condition window.
"""
import time, random, hashlib, base64, secrets
from http.server import HTTPServer, BaseHTTPRequestHandler
import urllib.parse
# Simulated storage
auth_codes = {} # code -> {client_id, redirect_uri, code_challenge, scope, user}
tokens = {}
def generate_code():
return secrets.token_urlsafe(16)
class AuthHandler(BaseHTTPRequestHandler):
def do_GET(self):
parsed = urllib.parse.urlparse(self.path)
params = urllib.parse.parse_qs(parsed.query)
if parsed.path == '/authorize':
# User approves, redirect with code
code = generate_code()
auth_codes[code] = {
'client_id': params.get('client_id', ['unknown'])[0],
'redirect_uri': params.get('redirect_uri', [''])[0],
'code_challenge': params.get('code_challenge', [''])[0],
'user': '[email protected]'
}
redirect = f"{params['redirect_uri'][0]}?code={code}&state={params.get('state',[''])[0]}"
self.send_response(302)
self.send_header('Location', redirect)
self.end_headers()
elif parsed.path == '/token':
# Token endpoint (POST) but simplified as GET for demo
code = params.get('code', [''])[0]
verifier = params.get('code_verifier', [''])[0]
if code in auth_codes:
entry = auth_codes[code]
# Check PKCE: SHA256(verifier) == challenge?
challenge = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode()).digest()).decode().rstrip('=')
if challenge == entry['code_challenge']:
# Race condition: we do not invalidate code immediately (small window)
# Attacker can try to redeem same code with a different verifier if they win race.
access_token = secrets.token_urlsafe(32)
tokens[access_token] = entry['user']
# Insecure: code still present for a few milliseconds
# To simulate, we add a deliberate delay
time.sleep(0.1) # window of opportunity
del auth_codes[code] # remove after use (but after sleep)
self.send_response(200)
self.end_headers()
self.wfile.write(f'access_token={access_token}'.encode())
else:
self.send_response(400)
self.end_headers()
self.wfile.write(b'invalid code_verifier')
else:
self.send_response(400)
self.end_headers()
self.wfile.write(b'invalid code')
else:
self.send_response(404)
self.end_headers()
server = HTTPServer(('0.0.0.0', 5000), AuthHandler)
print("Auth server on :5000")
server.serve_forever()
تسمح ثغرة في تدفق PKCE الخاص بخادم تفويض OAuth2 للمهاجم باسترداد رمز تفويض قبل العميل الشرعي، متجاوزًا PKCE عبر حالة سباق (Race Condition). يفشل الخادم في إبطال الرمز بشكل ذرّي (atomically)، تاركًا نافذة يمكن فيها تجربة مُتحقِّق (verifier) خبيث.
python vulnerable_auth_server.py
python race_condition_exploit.py