
Variante sintética de estouro de buffer de pilha CWE-120 de CVE-2020-8597 (pppd EAP) como um alvo de análise estática CodeQL
Um programa C deliberadamente vulnerável, com cerca de 130 linhas, usado como alvo de análise estática com CodeQL. Ele reproduz a classe de bug da CVE-2020-8597 — o estouro de buffer de pilha rhostname do EAP do pppd (CWE-120) — em um programa que não compartilha nenhum dos nomes de funções, profundidade de chamada ou estrutura de despacho do pppd.
O objetivo é um teste de generalidade: uma consulta CodeQL escrita para detectar o bug do pppd também deve disparar neste programa, sem edições. Se isso ocorrer, a consulta expressa a classe de bug, e não o formato do código original.
Este programa é intencionalmente inseguro e existe apenas para análise. Não o implante. O bug que ele espelha é público (CVE-2020-8597, divulgada em 2020).
Um comprimento derivado de um atacante é copiado para um buffer de tamanho fixo, sem nenhuma verificação que relacione esse comprimento ao tamanho do buffer.
Uma verificação de limites está presente — ela apenas verifica a coisa errada: o comprimento declarado é validado contra o quadro recebido (evitando uma leitura além do limite), mas nunca contra sizeof(dest) (que é o que evita a gravação além do limite). Essa é a mesma causa raiz da verificação morta vallen >= len + sizeof(rhostname) do pppd.
Ambos mantêm a única propriedade que torna isso fluxo de dados, e não grep: uma chamada indireta por meio de uma tabela de ponteiros de função entre a origem e o sink.
handle_hello() — vulnerável. memcpy(name, payload + 2, vlen) com vlen
limitado pelo quadro, não por sizeof(name).handle_echo() — seguro. Mesma forma de origem e sink, mas vlen também é
limitado por sizeof(buf). Este é o controle negativo: a consulta deve disparar
em handle_hello e permanecer silenciosa aqui.Um datagrama UDP = um quadro:
[ type : 1 ] [ length : 2, big-endian ] [ value : length bytes ]
type 0x01 → hello, 0x02 → echo. Um quadro hello com comprimento declarado entre 65
e ~2045 estoura name[64].
make # gcc -Wall -Wextra -O0 -g -o tlv_server tlv_server.c
Linux/POSIX (soquetes BSD). Compila sem avisos.
O CodeQL rastreia uma compilação real, então compile a partir do estado limpo:
make clean
codeql database create db --language=cpp --command="make"
# ou, sem a etapa clean:
codeql database create db --language=cpp --command="make -B"
Em seguida, execute a consulta da Parte 3 em db; ela deve relatar o memcpy em
handle_hello e não o de handle_echo.
| pppd / CVE-2020-8597 | este projeto |
|---|
| Origem | read() no fd do PPP | recvfrom() em um socket UDP |
| Despacho | struct protent *protocols[] global, correspondência linear por nº de protocolo | const struct frame_op ops[] local ao arquivo, correspondência linear por tag de 1 byte |
| Profundidade até o sink | get_input → (*input) → eap_input → eap_request | dispatch_frame → (*handle) → handle_hello |
| Destino | char rhostname[256] | char name[64] |
| Verificação errada | vallen limitado por len do pacote | vlen limitado por plen do quadro |