flawopen.com/Teardowns/cve-2023-6246-glibc-syslog-heap-buffer-overflow
CVE-2023-6246: overflow no heap do syslog da glibc
CVE-2023-6246 é um overflow no heap do syslog da glibc, acionado por um cabeçalho longo. Atualize o pacote glibc corrigido da distribuição.
Imagine um funcionário medindo uma encomenda e sua etiqueta com uma régua curta. A etiqueta não cabe, então o cálculo não registra o espaço necessário. Ele pede uma caixa minúscula e tenta imprimir nela a etiqueta inteira e o conteúdo. Na glibc, um cabeçalho syslog longo podia deixar o tamanho necessário sem valor, levando o logger a alocar pouca memória no heap.
Conceitos Centrais e Termos
glibc- A GNU C Library fornece funções centrais do runtime C usadas pela maioria dos programas Linux.
__vsyslog_internal()- Implementação interna da glibc usada por
syslog()evsyslog()para formatar a mensagem e oSYSLOG_HEADERantes do envio ao logger do sistema. SYSLOG_HEADER- Prefixo de prioridade e identificação formatado antes da mensagem syslog. Pode incluir o nome do programa ou um identificador definido por
openlog(). Heap-based buffer overflow (CWE-122)- Uma gravação ultrapassa o limite de um buffer alocado no heap. Aqui, o cálculo falhava quando o cabeçalho com nome longo não cabia no buffer fixo inicial.
Mapeamentos de frameworks
- Referência CWE para a fraqueza descrita neste guia: CWE-122
Análise de Causa Raiz
O aviso da glibc informa que __vsyslog_internal() não atualizava o tamanho necessário ao formatar um SYSLOG_HEADER com nome de programa longo. No código vulnerável, o comprimento do cabeçalho l podia ser igual ou maior que o buffer de pilha de 1.024 bytes; assim, o ramo que formatava o corpo da mensagem e definia bufsize não era executado. A alocação posterior no heap usava tamanho não definido/zero e, em seguida, escrevia o cabeçalho e a mensagem em um espaço pequeno demais. A Qualys relata que o nome longo pode vir do basename de um argv[0] controlado pelo chamador ou de um identificador openlog() maior que 1.024 bytes; um programa setuid vulnerável que registra por esse caminho pode tornar o defeito relevante para segurança. A Qualys demonstrou elevação local de privilégios via su no Fedora 38. A questão depende de acesso local, configuração e caminho de chamada; não é um exploit remoto genérico de syslog.
Fluxo de Ataque Passo a Paso
Pré-condição local
Um processo local precisa chamar syslog() ou vsyslog() por meio de um programa que use a glibc afetada. O impacto de segurança exige um chamador privilegiado e um caminho que não substitua o prefixo do nome do programa por um identificador seguro e limitado.
Cabeçalho longo
O cabeçalho excede o buffer inicial|O SYSLOG_HEADER inclui um nome longo (__progname, derivado do basename de argv[0]) ou um identificador openlog() longo. A Qualys informa que o valor acionador precisa exceder 1.024 bytes.
Cálculo incompleto
O ramo que calcula o tamanho é ignorado|Quando o cabeçalho não cabe no buffer de pilha de 1.024 bytes, o código vulnerável ignora o ramo que calcula bufsize. A alocação no heap fica sem espaço suficiente para o cabeçalho e a mensagem formatada.
Impacto na memória
A gravação excede a alocação|O logger grava o cabeçalho e a mensagem em um buffer pequeno demais, corrompendo a memória do heap. A Qualys demonstrou elevação local via su no Fedora 38; não presuma a mesma exposição em todo aplicativo ou distribuição.
Código-Fonte: Vulnerável vs. Seguro
O ramo antigo deixava bufsize em zero quando o cabeçalho não cabia no buffer de pilha; a alocação no heap podia então reservar espaço insuficiente. A correção marca o buffer de pilha como inutilizável nesse caso, formata nele para medir o corpo, registra l + vl e segue o caminho de alocação existente com o tamanho necessário. São trechos focados do upstream, não funções completas independentes.
Trecho de origem: misc/syslog.c
/* Trecho específico de misc/syslog.c antes do commit 6bd0e4efcc78. */
char bufs[1024];
char *buf = NULL;
size_t bufsize = 0;
...
if (0 <= l && l < sizeof bufs)
{
va_list apc;
va_copy (apc, ap);
int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
mode_flags);
if (0 <= vl && vl < sizeof bufs - l)
buf = bufs;
bufsize = l + vl;
va_end (apc);
}
/* Um cabeçalho longo ignora o ramo acima que define o tamanho. */
/* Trecho específico de misc/syslog.c após o commit 6bd0e4efcc78. */
char bufs[1024];
char *buf = bufs;
size_t bufsize;
...
if (0 <= l && l < sizeof bufs)
{
pos = bufs + l;
len = sizeof (bufs) - l;
}
else
{
buf = NULL;
pos = bufs;
len = sizeof (bufs);
}
vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
if (!(0 <= vl && vl < len))
buf = NULL;
bufsize = l + vl;
Lista de Verificação de Segurança para Engenharia
- ✓Atualize a glibc pelo pacote corrigido publicado para sua distribuição e versão; não deduza o estado do pacote apenas pela versão upstream.
- ✓Confira o pacote no aviso da distribuição: as correções upstream são glibc 2.39, 2.38-42, 2.37-57 e 2.36-126.
- ✓Inventarie programas privilegiados que chamam
syslog()ouvsyslog()e verifique se nomes controlados pelo chamador ou identificadoresopenlog()chegam ao cabeçalho. - ✓Ao implementar logging formatado, contabilize o tamanho completo do cabeçalho e do corpo mesmo quando o buffer fixo inicial for insuficiente; adicione um teste com nome de programa longo e confira a aritmética da alocação.