Execução remota de código sem autenticação no núcleo do PHP, CVE-2026-109618 e CVE-2026-109619
Duas falhas no núcleo do interpretador PHP permitem que uma requisição HTTP sem autenticação execute comandos no servidor, antes de qualquer linha da aplicação rodar. A primeira nasce da forma como o PHP aborta uma requisição quando a memória acaba: o salto de emergência deixa estruturas pela metade, e a limpeza do fim da requisição as usa como se fossem válidas. A segunda nasce do estado global que os processos persistentes carregam de uma requisição para a outra: um erro fatal pula a limpeza, e a requisição seguinte usa memória já liberada. Os detalhes vazaram antes da correção, a exploração começou antes do anúncio oficial e a CISA incluiu as duas falhas no catálogo de vulnerabilidades exploradas. Atualizar é a única correção completa.
O PHP usa um salto de emergência (longjmp()) para abandonar a requisição quando a memória acaba ou ocorre um erro fatal. Em dois pontos do núcleo, esse salto deixa memória num estado inválido: estruturas da própria requisição pela metade (CVE-2026-109618) e ponteiros globais do processo apontando para memória já liberada (CVE-2026-109619) [1] [2]. Um atacante sem credenciais provoca o esgotamento de memória com uma requisição multipart construída para isso e transforma o estado inválido em execução de código, antes de a aplicação rodar [4] [7]. Afeta toda instalação que serve requisições web, em qualquer versão anterior a 8.2.35, 8.3.36, 8.4.27 e 8.5.12 [1] [3]. Não há mitigação completa além de atualizar [1] [2].
PHP2Shell é o nome dado a duas vulnerabilidades críticas no núcleo do interpretador PHP, a CVE-2026-109618 e a CVE-2026-109619, corrigidas pelo projeto PHP em 21 de outubro de 2026 [1] [2] [3]. As duas permitem execução remota de código sem autenticação e receberam a mesma pontuação CVSS v4 de 9.2, com vetor de rede, sem privilégios e sem interação do usuário [1] [2]. Como o defeito está no interpretador, e não em um framework ou aplicação, ele alcança praticamente todo servidor que usa PHP para atender requisições web: Apache com mod_php, PHP-FPM, php-cgi, FrankenPHP e LiteSpeed [3] [4].
O ataque acontece antes de qualquer código da aplicação. A requisição maliciosa é um POST com corpo multipart montado para esgotar a memória do PHP enquanto ele ainda interpreta a própria requisição; por isso o erro registrado aparece em Unknown on line 0, sem arquivo de script [4]. Em campo, o mecanismo de progresso de upload da sessão (session.upload_progress) foi o caminho usado para vazar endereços e consumir o estado corrompido [4] [7].
A exploração começou antes do anúncio público: segundo a Datadog, a AWS relatou tentativas em 17 de outubro, três dias antes da divulgação [4]. Um honeypot registrou execução remota de código contra Apache com mod_php rodando PHP 8.4.26 [6], e a pesquisa da Dream documentou uma campanha que encadeou o PHP2Shell com uma falha do kernel Linux para obter root em 25 servidores [7]. Essa campanha é analisada em detalhe no relatório Da webshell ao root do CiberLab.
A ação é uma só: atualize para PHP 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, comece pelos servidores expostos à internet e reinicie todos os processos do PHP [1] [3]. Quem roda PHP 8.1 ou anterior, fora de suporte, deve tirar o sistema do ar até migrar, como orienta a CISA [3]. Este relatório traz, na seção 6, a verificação da plataforma CiberLab: a aplicação não usa PHP, mas o painel que a publica, sim.
Não houve submissão a sandbox, execução de exploit nem análise de amostra. O CiberLab não reproduziu as falhas em laboratório próprio. A causa raiz vem dos avisos oficiais do projeto PHP [1] [2]; os sinais de detecção, da Datadog Security Labs [4] e da Unit 42 [5]; a exploração em campo, da Dream [7] e da imprensa especializada [6]. A verificação da seção 6, ao contrário, foi feita diretamente sobre o código e a infraestrutura de publicação da plataforma CiberLab.
| Campo | CVE-2026-109618 | CVE-2026-109619 |
|---|---|---|
| Título oficial | RCE via OOM corruption [1] | RCE via stale global state [2] |
| Aviso | GHSA-w8hw-w9fx-j79w [1] | GHSA-6wmf-4rv5-p3rp [2] |
| Componente | Inicialização de memória da requisição e limpeza no encerramento [1] [4] | Estado global de erro, sessão e extensões dos processos persistentes [2] |
| Classe de fraqueza | CWE-416, CWE-755, CWE-824, CWE-1325, CWE-1419 [1] | CWE-416, CWE-755, CWE-824, CWE-1325, CWE-1419 [2] |
| Vetor CVSS v4 | AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N [1] | AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N [2] |
| Pontuação | 9.2, crítica [1] | 9.2, crítica [2] |
| Caso confirmado | RCE por requisição POST processada antes do código da aplicação [4] | RCE em mod_php com o recurso fatal_error_backtraces do PHP 8.5 [2] |
| Publicação | 21 de outubro de 2026 [1] | 21 de outubro de 2026 [2] |
| Inclusão no KEV | 26 de outubro de 2026 [3] | 26 de outubro de 2026 [3] |
| Créditos | Relato: lcfr-hax, sagitzadik-wiz, tomash-areion e amyb-oai. Correção: arnaud-lb, iluuu1994, bukka e ndossche [1] [2] | |
| Ramo | Versões vulneráveis | Primeira versão corrigida |
|---|---|---|
| PHP 8.5 | Anteriores a 8.5.12 [1] [2] | 8.5.12 [1] [2] |
| PHP 8.4 | Anteriores a 8.4.27 [1] [2] | 8.4.27 [1] [2] |
| PHP 8.3 | Anteriores a 8.3.36 [1] [2] | 8.3.36 [1] [2] |
| PHP 8.2 | Anteriores a 8.2.35 [1] [2] | 8.2.35 [1] [2] |
| PHP 7.4, 8.0 e 8.1 | Afetados, fora de suporte [3] [4] | Sem versão oficial; o projeto publicou correções de código-fonte, que distribuições podem aplicar sem mudar o número da versão [4] |
Distribuições Linux aplicam correções em versões antigas sem trocar o número exibido por php -v [4]. Não conclua que um servidor está vulnerável, ou corrigido, só pela versão: confira o pacote no aviso de segurança da sua distribuição. O inverso também vale: um contêiner com PHP compilado à parte não recebe a correção do sistema operacional e precisa de imagem nova [4].
Para entender as duas falhas, é preciso conhecer duas decisões de projeto do PHP: como ele reaproveita processos entre requisições e como ele aborta uma requisição que deu errado.
Nas formas usuais de servir PHP (mod_php dentro do Apache, PHP-FPM, FrankenPHP, LiteSpeed), o mesmo processo trabalhador atende muitas requisições seguidas [2] [3]. A memória que pertence a uma requisição vive num espaço próprio, liberado em bloco no fim dela; o estado global do processo, como informações de erro, de sessão e de extensões, permanece entre uma requisição e a seguinte [2]. Esse arranjo é eficiente, mas exige uma disciplina: tudo o que o estado global aponta dentro da memória de uma requisição precisa ser zerado antes de essa memória ser liberada [2].
longjmp()Quando o PHP fica sem memória, estoura o tempo de execução ou encontra outro erro fatal, ele não desfaz a pilha de chamadas passo a passo. Usa longjmp(), uma instrução da linguagem C que salta direto de volta a um ponto de recuperação, abandonando o que estava no meio do caminho [1] [5]. O salto é rápido, mas não executa nenhuma limpeza das funções que abandonou. Se uma delas estava no meio da montagem de uma estrutura, a estrutura fica pela metade [1].
O recurso session.upload_progress grava na sessão do usuário o andamento de um upload em curso, para que a aplicação mostre uma barra de progresso [2]. Ele roda durante a leitura do corpo da requisição, antes de qualquer script, e manipula a sessão do usuário a partir de campos do próprio formulário, como PHPSESSID e PHP_SESSION_UPLOAD_PROGRESS [4]. É um dos dois consumidores precoces de estado global citados no aviso da CVE-2026-109619 [2] e o ponto de entrada usado na campanha documentada pela Dream [7].
Em alguns contextos, a memória da requisição se torna alcançável antes de estar totalmente inicializada [1]. Se uma alocação falha nesse intervalo, o longjmp() abandona a inicialização, e a rotina de encerramento da requisição depois lê essa memória ou toma decisões com base nela [1]. O aviso destaca que a alocação que falha não precisa ter relação com a estrutura inválida: basta acontecer no momento errado [1].
A Datadog descreve um caso concreto na tabela de dispersão do PHP (Zend/zend_hash.c): a função _zend_hash_str_add_or_update_i() incrementa os contadores da tabela antes de alocar a chave; se essa alocação falha, a limpeza visita um elemento cuja chave e cujo valor nunca foram escritos [4]. Um atacante que controla o conteúdo dessa memória controla o que a limpeza faz com ela.
Os processos persistentes guardam estado global de erro, sessão, objetos e extensões que aponta para memória de uma única requisição, e esse estado nem sempre é zerado antes de a memória da requisição ser liberada [2]. Erros fatais, incluindo falta de memória e tempo de execução esgotado, podem pular o zeramento; diagnósticos emitidos tarde, durante o encerramento, podem repovoar o estado de erro depois de ele ter sido limpo [2]. A requisição seguinte usa então um ponteiro para memória já liberada, antes que a inicialização normal rode: um uso após liberação (use-after-free) [2].
O aviso nomeia os dois consumidores precoces desse estado: os diagnósticos de configuração (INI) aplicados antes da inicialização da requisição e o tratamento de progresso de upload da sessão [2]. O caso de execução confirmado usa o recurso fatal_error_backtraces do PHP 8.5 e afeta o mod_php [2]; no PHP-FPM, segundo a Datadog, a execução depende de a aplicação realizar uma operação adequada depois da inicialização [4].
O aviso da CVE-2026-109619 pede auditoria dos registros com E_ALL ligado, mas avisa que registros limpos não provam que o servidor está seguro [2]. A Datadog acrescenta que a exploração pode devolver HTTP 200 e manter o trabalhador vivo [4]. Não use a ausência de erros ou de quedas como evidência de que um servidor sem atualização não foi atacado.
Em 23 de outubro, dois dias depois da correção, o projeto PHP publicou um aviso informativo sobre uma terceira falha de execução remota, a CVE-2026-115560, ainda sem correção [9]. Ela exige uma combinação incomum de configuração e código: a aplicação define session.serialize_handler como php_binary ou php_serialize, troca para php em tempo de execução com ini_set() antes de session_start(), e mantém o progresso de upload ligado [9]. A mitigação é a mesma da CVE-2026-109619, session.upload_progress.enabled=0, e as versões de 21 de outubro não a corrigem [9]. Não havia exploração relatada na data deste relatório [9].
As fontes divergem em detalhes de horário, mas concordam na sequência. A tabela reúne os marcos com a fonte de cada um:
| Data | Evento |
|---|---|
| 8 a 22 de outubro | O operador da campanha documentada pela Dream prepara a operação, desenvolve o exploit e perfila versões em laboratório [7] |
| 17 de outubro | A AWS relata tentativas de exploração em campo, antes da divulgação pública [4] |
| 20 de outubro | Divulgação pelo projeto PHP; a Unit 42 ativa proteção virtual às 22h21 (horário do Pacífico) [4] [5] |
| 21 de outubro | Lançamento de 8.5.12, 8.4.27, 8.3.36 e 8.2.35; alerta da CISA; varredura ampla e não direcionada já observada [1] [3] [4] |
| 23 de outubro | Aviso informativo da CVE-2026-115560 [9]; a CISA acrescenta uma regra Sigma ao alerta [3]; o primeiro firewall da campanha da Dream é comprometido [7] |
| 24 e 25 de outubro | Honeypot registra RCE contra mod_php com PHP 8.4.26 [6]; a Dream encontra os artefatos da campanha em 25 de outubro [7] |
| 26 de outubro | As duas CVEs entram no catálogo KEV da CISA [3] |
| 28 de outubro | A falha de kernel usada na cadeia, CVE-2026-46300, entra no KEV [6] |
| 29 de outubro | A Unit 42 confirma a exploração contra interfaces de gerenciamento do PAN-OS expostas à internet [5] |
A Dream recuperou o exploit de um operador e descreveu o estágio PHP2Shell em quatro passos, contra o servidor de gerenciamento de firewalls [7]:
multipart construídas para esgotar a memória e moldar o comportamento do alocador do PHP [7].Set-Cookie, um ponteiro da biblioteca libphp.so, o que permite calcular os demais endereços [7].system() [7].nobody no caso documentado [7].O operador seguiu com a falha de kernel Fragnesia (CVE-2026-46300) para virar root e instalou uma webshell PHP de 103 bytes; a cadeia completa levava menos de 15 minutos por alvo [7]. A pós-exploração, com túneis, roubo de credenciais e ataque ao Active Directory, está no relatório Da webshell ao root.
Os alvos da campanha não eram sites PHP comuns: eram firewalls cuja interface de gerenciamento roda PHP 7.4.33 ou 8.0.30 internamente [7]. A CISA alerta que o PHP costuma vir embutido em outros produtos, onde a organização nem o enxerga [3]. Inclua no inventário painéis de administração, appliances e ferramentas de terceiros, não só os servidores de aplicação.
A plataforma CiberLab foi verificada em duas camadas: a aplicação em si e a infraestrutura que a publica. A conclusão é que a aplicação não é afetada, mas o painel de publicação usa PHP e precisa estar na versão corrigida.
| Componente | Estado verificado | Resultado |
|---|---|---|
| Aplicação CiberLab | Escrita em Next.js; nenhum arquivo .php no repositório; imagem baseada em node:22-bookworm-slim, sem interpretador PHP | Não afetada |
| Painel Coolify (publicação) | O Coolify é uma aplicação PHP; as versões v4.4.7 e v4.3.24 atualizam o PHP embutido para 8.4.27 [8] | Afetado até atualizar |
| Servidor Git (Gitea) | Escrito em Go, sem PHP | Não afetado |
Confirme que o Coolify está em v4.4.7 ou superior, pelo painel em Settings, Update [8]. A nota de lançamento recomenda que todos migrem para a v4.4.7, porque as outras linhas não recebem todas as correções de segurança [8]. Não deixe o painel exposto à internet sem restrição de origem: ele controla a implantação de toda a plataforma, e é exatamente o tipo de interface de gerenciamento que a campanha da seção 5.1 procurava.
A detecção vai do mais barato (o registro de erros que já existe) ao mais caro (a telemetria de processos no host). Os sinais abaixo vêm da Datadog [4] e da Unit 42 [5].
Dois padrões merecem alerta imediato [4]:
PHP Fatal error: Allowed memory size of 16777216 bytes exhausted
(tried to allocate 3500032 bytes) in Unknown on line 0
AH00052: child pid 12345 exit signal Segmentation fault (11)
O local Unknown on line 0 significa que a memória acabou antes de qualquer script rodar, ou seja, durante a leitura da requisição [4]. Uma rajada curta desses erros num mesmo trabalhador pode ser a preparação do ataque; cadeias mais novas produzem só dois a quatro erros antes de silenciar [4].
POST multipart com campos PHPSESSID e PHP_SESSION_UPLOAD_PROGRESS onde a aplicação não os usa [4].files[R00001][a][a][a] [4].application/x-www-form-urlencoded com um único campo de 3 a 60 MB, contendo bytes nulos e caracteres de controle [4].<?php ou |O: [4].Set-Cookie: PHPSESSID= anormalmente longo ou codificado, sinal do vazamento de endereço [4] [7].A CISA publicou uma regra Sigma própria no seu repositório [3]. A regra abaixo, derivada dos sinais de [4], cobre o registro de erro do PHP, que existe mesmo sem telemetria de rede:
title: Esgotamento de memoria antes do script, possivel PHP2Shell
id: 3f6c2a10-8d47-4b1e-9a52-c07e14d9b8a1
status: experimental
description: Erro fatal de memoria em "Unknown on line 0", sinal de ataque
as CVE-2026-109618 e CVE-2026-109619 durante a leitura da requisicao
author: CiberLab (Ciência Embarcada)
references:
- https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w
- https://securitylabs.datadoghq.com/articles/php2shell-critical-vulnerabilities-in-php/
logsource:
product: php
category: application
detection:
selection:
message|contains|all:
- 'Allowed memory size of'
- 'in Unknown on line 0'
condition: selection
falsepositives:
- Uploads legitimos muito grandes com memory_limit baixo
level: high
tags:
- attack.initial_access
- attack.t1190
- cve.2026-109618
- cve.2026-109619
A evidência mais direta de exploração é um shell ou utilitário de download iniciado por um processo do Apache ou do PHP, por exemplo a árvore apache2 (www-data), sh -c, bash com conexão de saída [4]. A Unit 42 publicou consultas que pontuam sinais desse tipo a partir de processos do servidor web e de contas de serviço (www-data, apache, nginx): reconhecimento, download, gravação em diretório executável, shell reverso e acesso a credenciais [5]. Arquivos PHP novos em diretórios públicos, sobretudo pequenos, são o rastro da webshell [7].
Atualize para PHP 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, ou para o pacote corrigido da sua distribuição, e reinicie todos os trabalhadores [1] [2] [3]. Comece pelos sistemas expostos à internet [3]. Em contêineres, reconstrua a imagem com a base atualizada: a correção do sistema operacional não alcança um PHP compilado dentro da imagem [4]. Sistemas em PHP 8.1 ou anterior devem sair do ar até a migração [3].
Os avisos oficiais deixam claro que nenhuma destas medidas fecha a falha; elas apenas estreitam o caminho conhecido [1] [2]:
session.upload_progress.enabled=0, recomendado inclusive depois da atualização se o recurso não for usado [2]. Também cobre a CVE-2026-115560 [9].fatal_error_backtraces=0, o que remove o produtor de RCE confirmado [2].post_max_size conservador, reduza max_input_nesting_level, limite variáveis, partes e uploads, e bloqueie multipart no proxy onde a aplicação não o usa [1].RLIMIT_AS nem RLIMIT_DATA: esses limites provocam justamente as falhas de alocação de que o ataque precisa [1] [4].pm.max_requests=1 no PHP-FPM, se o desempenho permitir, encurta a vida do estado global obsoleto [2].As diretivas acima só valem se carregadas antes da leitura da requisição, no arquivo de configuração principal, e seguidas de reinício de todos os trabalhadores [4]. Um ini_set() dentro da aplicação chega tarde demais, porque o ataque acontece antes de o script rodar.
Trate como comprometido todo servidor sem atualização com os sinais da seção 7. Preserve os registros, procure PHP novo em diretórios públicos e verifique /etc/pam.d/su, serviços systemd e scripts de inicialização, pontos de escalada e persistência da campanha da Dream [7]. Gire os segredos da conta do servidor web e reconstrua a máquina. Com kernel vulnerável à CVE-2026-46300, assuma que o atacante chegou a root [6] [7].
IDs e nomes conferidos na base oficial do MITRE ATT&CK for Enterprise [10]:
| Técnica | Nome | Relação com o caso |
|---|---|---|
| T1595.002 | Active Scanning: Vulnerability Scanning | Varredura ampla e não direcionada observada desde 21 de outubro [4] |
| T1190 | Exploit Public-Facing Application | Exploração do PHP exposto, sem autenticação [1] [2] [3] |
| T1059.004 | Command and Scripting Interpreter: Unix Shell | Comando executado via system() com a conta do servidor web [4] [7] |
| T1505.003 | Server Software Component: Web Shell | Webshell PHP de 103 bytes gravada em diretório público [7] |
| T1068 | Exploitation for Privilege Escalation | Encadeamento com a CVE-2026-46300 para chegar a root [6] [7] |
Nenhuma fonte publicou IPs, domínios ou hashes do PHP2Shell [5] [7]. Os indicadores são de comportamento e de artefato, do sinal mais forte ao mais fraco:
| Tipo | Indicador | Severidade | Contexto e ação |
|---|---|---|---|
| Vulnerabilidade | CVE-2026-109618, CVE-2026-109619 | Crítica | RCE sem autenticação no núcleo do PHP, no KEV desde 26/10. Atualize e reinicie os trabalhadores [1] [2] [3]. |
| Processo | shell filho de apache2, httpd ou php-fpm | Crítica | Evidência mais direta de exploração; isole o host [4] [5]. |
| Arquivo | /unauth/php/change_password.php | Crítica | Webshell de 103 bytes da campanha da Dream em firewalls PAN-OS; procure equivalentes em diretórios públicos [7]. |
| Registro de erro | Allowed memory size ... in Unknown on line 0 | Alta | Memória esgotada antes do script; rajadas curtas indicam preparação [4]. |
| Registro de erro | AH00052 ... Segmentation fault (11) | Alta | Queda de trabalhador do Apache; correlacione com o padrão anterior [4]. |
| Requisição | PHP_SESSION_UPLOAD_PROGRESS + PHPSESSID em multipart | Alta | Campos de progresso de upload onde a aplicação não os usa [4] [7]. |
| Requisição | files[R00001][a][a][a] | Alta | Aninhamento profundo e cerca de 900 partes em menos de 1 MB [4]. |
| Requisição | filename com <?php ou |O: | Alta | Código PHP ou objeto serializado no nome do arquivo enviado [4]. |
| Resposta | Set-Cookie: PHPSESSID= longo ou codificado | Média | Possível vazamento de endereço da libphp.so [4] [7]. |
PHP2Shell, execução remota de código no núcleo do PHP. Relatório técnico de análise de vulnerabilidade, versão 1.0, emitido em 2 de novembro de 2026.
CiberLab, uma iniciativa do Ciência Embarcada.
Classificado TLP:CLEAR: distribuição livre, sem restrição de compartilhamento.