FlawOpen

flawopen.com/Teardowns/cve-2023-6246-glibc-syslog-heap-buffer-overflow

● CVE-2023-6246 · CVSS 7.8 · Alta
Pesquisa · FlawOpen

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.

💡 Explicação em Linguagem Simples (ELI5)

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() e vsyslog() para formatar a mensagem e o SYSLOG_HEADER antes 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

Passo 1

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.

Passo 2

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.

Passo 3

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.

Passo 4

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

IMPLEMENTAÇÃO VULNERÁVEL
/* 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. */
PATCH SEGURO E ROBUSTO
/* 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

Fontes