
SolarWinds Serv-U CVE-2026-28318: falha não autenticada de Content-Encoding: deflate. Análise de causa raiz (liberação inválida de um ponteiro interno -> corrupção de heap) + PoC apenas de DoS. Corrigido na versão 15.5.4 Hotfix 1.
Análise de causa raiz + prova de conceito de DoS. O aviso público classifica isso como uma negação de serviço / consumo descontrolado de recursos não autenticada. A análise binária mostra que o defeito subjacente é de segurança de memória: um
free()inválido de um ponteiro interior no caminho de decodificaçãodeflateHTTP, que corrompe o heap do processo (STATUS_HEAP_CORRUPTION,0xC0000374). Não é uma bomba de descompressão, e o crash é independente do tamanho descomprimido.
Esta é uma pesquisa de segurança defensiva para uma vulnerabilidade já corrigida e divulgada publicamente (correção enviada em 2026-06-04 no Serv-U 15.5.4 Hotfix 1; listado no CISA KEV). O PoC aqui apenas derruba (crash) uma instância do Serv-U que você possui ou está explicitamente autorizado a testar. É apenas DoS — nenhuma execução remota de código está incluída ou demonstrada (veja Severidade). Use-o para validar o status do patch e a detecção em seus próprios sistemas. Não o aponte para sistemas que você não controla. Você é responsável por cumprir a lei aplicável.
Afeta apenas o listener HTTP/HTTPS (o caminho web/gerenciamento). FTP/FTPS/SFTP não estão nesse caminho de código.
Qualquer requisição HTTP contendo Content-Encoding: deflate com um corpo deflate válido derruba o serviço. O manipulador descomprime o corpo, então libera o ponteiro para o corpo comprimido e substitui pelo buffer descomprimido — mas esse ponteiro é um ponteiro interior para o buffer de recepção HTTP (aponta para o corpo, imediatamente após o \r\n\r\n), não uma base de alocação de heap. Chamar free() em um ponteiro não-base e desalinhado corrompe o heap e o processo morre.
Como o bug está em como o ponteiro do corpo é liberado — não em quanto dado é produzido — até mesmo um corpo comprimido de ~25 bytes (que descomprime para alguns KB) o derruba de forma confiável. O uso de memória não cresce; não é uma "bomba zip/deflate".
A rotina de decodificação deflate reside em RhinoNET.dll (biblioteca de rede do Serv-U) e é alcançada a partir do caminho de recepção HTTP (ProcessReceive) assim que o analisador de cabeçalho define a flag "deflate" ao ver Content-Encoding: deflate.
Simplificadamente, a rotina é chamada como decode(this, &bodyPtr, &bodyLen) e faz:
1. inflate bodyPtr[0..bodyLen] -> grows an accumulator buffer `acc` (stock zlib, bounded, correct)
2. free(*bodyPtr) <-- *bodyPtr is an INTERIOR pointer into the receive buffer
3. *bodyPtr = acc // replace compressed body with decompressed buffer
4. *bodyLen = total
O passo 2 é o bug. *bodyPtr não é um bloco alocado independentemente: ele aponta para o corpo da requisição dentro do buffer único de recepção HTTP, i.e., receive_buffer + header_length. Liberar um ponteiro interior (e desalinhado a 16 bytes) faz com que o alocador interprete uma região influenciada pelo atacante como um cabeçalho de chunk de heap → corrupção de metadados de heap → 0xC0000374.
Ambas as hipóteses "óbvias" estão erradas, verificadas em tempo de execução:
zlib1.dll!inflate e respeita avail_out em cada chamada (observado em mais de 100 chunks; zero escritas fora dos limites).prev_total + produced + 1 a cada rodada e escrito exatamente esse tanto — justo, sem estouro.A corrupção é unicamente o free() inválido no passo 2.
Capturado em tempo de execução (Frida) contra Serv-U 15.5.4.108 ao enviar uma requisição Content-Encoding: deflate cujo corpo descomprime para "A" * 8192:
…ce — mod 16 == 14. As bases de alocação de heap são alinhadas a 16 bytes, então esta não é uma base de alocação; é um ponteiro interior.\r\n\r\n:
…tream\r\nContent-Length: 26\r\nConnection: close\r\n\r\n
ed c1 01 0d 00 …).ntdll.dll, exceção 0xC0000374 (STATUS_HEAP_CORRUPTION), com a chamada originando do free no manipulador deflate do RhinoNET.dll. A última operação de heap antes do crash é exatamente este free(bodyPtr).0xC0000374) em nossos testes, e não alcançamos execução de código. Trate isso como DoS de corrupção de heap de pré-autenticação com causa raiz de segurança de memória; não assuma RCE.Requer Python 3 (apenas biblioteca padrão). Aponte para um listener HTTP do Serv-U que você está autorizado a testar. No Windows, usa uma chamada Get-NetTCPConnection para ler o PID do listener e o log de eventos do Aplicativo para confirmar o crash de corrupção de heap.
python poc_verify.py # default 127.0.0.1:80, tiny packet, 1 shot
python poc_verify.py --host <ip> --port 80
python poc_verify.py --big # body decompresses to 8192 bytes
python poc_verify.py --shots 3
python poc_verify.py --no-events # skip event-log check (no privileges needed)
O PoC constrói uma requisição mínima:
POST / HTTP/1.1
Host: <target>
Content-Encoding: deflate
Content-Type: application/octet-stream
Content-Length: <n>
Connection: close
<raw-deflate body — even a few dozen bytes is enough>
Ele reporta PASS se o serviço crashou (PID do listener mudou / evento 0xC0000374 apareceu) e FAIL se sobreviveu (já corrigido, não afetado, ou o corpo não foi processado como deflate).
Content-Encoding de entrada no listener HTTP/HTTPS, por exemplo, em um proxy reverso:
if ($http_content_encoding) { return 400; }
RhinoNET.dll / Serv-U.exe (imagem base 0x180000000) para mapear o caminho recepção → análise de cabeçalho → decodificação deflate e localizar o free errôneo.zlib respeita avail_out, rastreando cada alloc/free/memcpy da chamada de decodificação em disco, e um manipulador de exceção de processo para capturar a instrução com falha e a pilha 0xC0000374 no momento da corrupção. O free do ponteiro interior foi então confirmado ao despejar os bytes ao redor do ponteiro liberado (cauda do cabeçalho HTTP + corpo deflate bruto, desalinhado a 16 bytes).Os offsets referenciados na análise são específicos para a build 15.5.4.108 e diferirão entre builds.
Publicado como pesquisa defensiva após a disponibilidade da correção do fornecedor. O PoC é apenas DoS e destinado a testes autorizados.
| Produto | SolarWinds Serv-U (FTP / MFT / File Server) |
| Vulnerável | 15.5.4 e anteriores nesse branch sem o Hotfix 1 (análise feita na build 15.5.4.108) |
| Corrigido | Serv-U 15.5.4 Hotfix 1 (lançado em 2026-06-04) |
| Vetor | Não autenticado, rede (porta HTTP/HTTPS de gerenciamento/web) |
| Classe pública | CWE-400 Uncontrolled Resource Consumption · DoS · CVSS 7.5 · CISA KEV |
| Classe real | CWE-763 Release of Invalid Pointer / CWE-590 Free of Memory not on the Heap → corrupção de heap |