Programação Por Equipe DevBras

Capa do artigo: PHP2Shell na lista da CISA: confira o seu PHP

PHP2Shell na lista da CISA: confira o seu PHP

A CISA pôs o PHP2Shell na lista de falhas exploradas. Veja as versões corrigidas do PHP e por que o php -v engana no Ubuntu, no FPM e no container.

Em 26 de outubro de 2026, a CISA, agência de cibersegurança dos Estados Unidos, colocou as duas falhas do PHP conhecidas como PHP2Shell (CVE-2026-109618 e CVE-2026-109619) no catálogo KEV, a lista de vulnerabilidades que ela confirma estarem sendo exploradas de verdade. Os órgãos federais americanos têm até 29 de outubro para corrigir e a CISA marcou as duas com exigência de triagem forense, ou seja: não basta atualizar, é preciso procurar sinais de invasão.

A correção existe desde 21 de outubro. O problema de muita equipe, uma semana depois, não é falta de patch, e sim saber com certeza qual PHP está atendendo as requisições. Este texto junta o que as fontes oficiais confirmam e mostra, com saídas reais de terminal, onde a verificação costuma enganar.

O que o KEV muda na prática

Até 26/10, a exploração era relatada por empresas de segurança. A Amazon Threat Intelligence, por exemplo, registrou em seus honeypots uma tentativa de exploração em 17/10, quatro dias antes da divulgação pública, e várias outras na madrugada de 21/10, antes de o embargo cair às 14h UTC (11h no horário de Brasília). Com a entrada no KEV, a exploração passa a ser fato oficial para o governo americano, e isso costuma puxar auditorias, seguradoras e clientes corporativos a cobrarem evidência de correção.

O alerta da CISA, atualizado no mesmo dia, é direto: atualizar para PHP 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, priorizar o que está exposto na internet e, para quem não pode atualizar ou ainda usa PHP 8.1 ou anterior, tirar o sistema do ar até corrigir. O alerta lembra ainda que o PHP muitas vezes vem embutido em outros produtos, onde a versão nem aparece. A própria página do NVD já lista, na configuração afetada, equipamentos de terceiros como o PAN-OS/Panorama da Palo Alto Networks e o RUGGEDCOM APE1808 da Siemens. Nesses casos, quem manda é o aviso do fabricante, não o php.net.

As duas falhas em linguagem de servidor

CVE-2026-109618 (RCE por corrupção em falta de memória). Quando o PHP estoura o memory_limit, ele aborta a requisição com um salto (longjmp()). Em alguns pontos, a memória da requisição ainda estava pela metade, e a rotina de limpeza depois lê esses dados como se fossem válidos. O aviso GHSA-w8hw-w9fx-j79w descreve requisições multipart montadas para estourar a memória ainda dentro do post_max_size. No Apache com mod_php, isso acontece antes de qualquer linha da sua aplicação rodar. Execução remota completa foi validada contra mod_php com limites padrão.

CVE-2026-109619 (RCE por estado global velho). Um worker do PHP atende várias requisições seguidas. Se uma requisição é interrompida por erro fatal, parte do estado global continua apontando para memória já liberada, e a próxima requisição no mesmo worker pode usar esse lixo antes da inicialização normal (um use-after-free). Segundo o aviso GHSA-6wmf-4rv5-p3rp, o caminho pelo session upload progress, ligado por padrão, foi validado tanto em mod_php quanto em PHP-FPM.

As duas têm nota 9.2 no CVSS 4.0 dada pelo próprio projeto PHP. O NVD, em CVSS 3.1, deu 9.8 para a 109618 e 8.1 para a 109619. O aviso do php.net considera em risco toda instalação que serve web: PHP-FPM, mod_php, php-cgi, FrankenPHP e LiteSpeed, com risco maior no mod_php.

Versões afetadas e corrigidas

Pelos avisos GHSA e pelo NVD, está vulnerável tudo abaixo destas versões, em cada ramo suportado:

  • PHP 8.5: corrigido no 8.5.12
  • PHP 8.4: corrigido no 8.4.27
  • PHP 8.3: corrigido no 8.3.36
  • PHP 8.2: corrigido no 8.2.35
  • PHP 8.1, 8.0 e 7.4: sem versão oficial. O time de segurança do PHP publicou backports mínimos de código-fonte para quem compila, e alguns fornecedores de LTS e distros trazem a correção nos próprios pacotes
  • PHP 8.6.0: a RC4 já tem a correção (versão de teste, não use em produção)

Nas distribuições, o número do pacote é o que vale, porque elas aplicam a correção sem mudar a versão do PHP. Conferido nos rastreadores oficiais em 26/10:

  • Debian 13 (trixie): php8.4 8.4.27-1~deb13u1 (DSA-6574-1)
  • Debian 12 (bookworm): php8.2 8.2.35-1~deb12u1 (DLA-4848-1)
  • Ubuntu 26.04 LTS: php8.5 8.5.4-0ubuntu1.5
  • Ubuntu 24.04 LTS: php8.3 8.3.6-0ubuntu0.24.04.13
  • Ubuntu 22.04 LTS: php8.1 8.1.2-1ubuntu2.28 (lista completa na página do CVE na Ubuntu)
  • Imagens oficiais do Docker Hub: as tags php:8.5, php:8.4, php:8.3 e php:8.2 já trazem 8.5.12, 8.4.27, 8.3.36 e 8.2.35. A tag php:8.1-apache não recebe atualização desde o fim de dezembro de 2025

A tabela abaixo resume as mesmas versões numa imagem só, para consulta rápida.

Onde o número engana

Rodar php -v no terminal e comparar com a lista acima parece suficiente, mas há três armadilhas. Todos os comandos a seguir foram executados pela equipe em 26/10/2026, e as saídas são as reais.

1. O Ubuntu corrigido continua dizendo 8.3.6

Num container ubuntu:24.04 com o php8.3 da própria distro, a versão do PHP parece velhíssima:

$ php -v | head -1
PHP 8.3.6 (cli) (built: Oct 19 2026 15:16:58) (NTS)

$ dpkg-query -W -f='${Package} ${Version}\n' php8.3-cli php8.3-common
php8.3-cli 8.3.6-0ubuntu0.24.04.13
php8.3-common 8.3.6-0ubuntu0.24.04.13

$ zcat /usr/share/doc/php8.3-cli/changelog.Debian.gz | grep -m2 CVE-2026-10961
    - debian/patches/CVE-2026-109618_109619.patch: Avoid state corruption via
    - CVE-2026-109618

O pacote é o .13, exatamente o corrigido, e o changelog mostra o patch das duas CVEs. Quem olhar só o php -v vai abrir um alarme falso. No sentido contrário, um PHP compilado à mão que mostre 8.3.6 está de fato vulnerável. Em RHEL e derivados, o equivalente é rpm -q php-cli e rpm -q --changelog php-cli | grep CVE-2026-109618, comparando com o errata do fornecedor.

2. O PHP do terminal não é o PHP do site

CLI, FPM e mod_php são binários diferentes, com php.ini diferentes. No servidor Debian 13 usado no teste, o CLI vem com memory_limit => -1, enquanto o FPM usa outro arquivo:

$ php-fpm8.4 -v | head -1
PHP 8.4.27 (fpm-fcgi) (built: Oct 21 2026 07:53:46) (NTS)

$ php-fpm8.4 -i | grep -E '^(Loaded Configuration File|memory_limit|session.upload_progress.enabled)'
Loaded Configuration File => /etc/php/8.4/fpm/php.ini
memory_limit => 128M => 128M
session.upload_progress.enabled => On => On

Confira a versão e a configuração no binário que atende a web (php-fpm8.x -v, ou apache2ctl -M | grep php para saber se o mod_php está carregado) e, depois de atualizar, reinicie o serviço. Um FPM que ficou rodando desde antes do update continua com o código antigo na memória.

3. Cada container carrega o próprio PHP

Atualizar o host não muda nada dentro das imagens. As tags oficiais flutuantes já foram reconstruídas, mas a 8.1 parou no tempo:

$ docker run --rm php:8.1-apache php -v | head -1
PHP 8.1.34 (cli) (built: Dec 29 2025 23:35:29) (NTS)

$ docker run --rm php:8.4-apache php -v | head -1
PHP 8.4.27 (cli) (built: Oct 21 2026 15:53:29) (NTS)

$ docker run --rm php:8.5-fpm-alpine php -v | head -1
PHP 8.5.12 (cli) (built: Oct 21 2026 22:50:07) (NTS)

Para o que já está em produção, liste as imagens com docker ps --format '{{.Names}} {{.Image}}' e rode docker exec <container> php -v em cada um. Imagem com tag fixa antiga ou com PHP 8.1 precisa de rebuild com docker build --pull e novo deploy. Em frota com vários hosts, um painel que mostre todos os containers numa tela, como o Dockyard, painel Docker da DevBras, encurta esse inventário.

Um script para rodar no mesmo PHP da aplicação

O script abaixo compara a versão com a correção do ramo e mostra as diretivas que entram nas mitigações. Ele não substitui a checagem do pacote, mas roda no contexto que você escolher: no CLI, dentro do container ou, temporariamente, como página no FPM (apague logo depois, porque expõe configuração).

<?php
// Compara a versão do PHP com as correções do PHP2Shell (CVE-2026-109618/109619)
$corrigida = ['8.2' => '8.2.35', '8.3' => '8.3.36', '8.4' => '8.4.27', '8.5' => '8.5.12'];
$ramo = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
echo 'PHP ' . PHP_VERSION . ' (SAPI ' . PHP_SAPI . ")\n";
if (!isset($corrigida[$ramo])) {
    echo "Ramo $ramo sem correção oficial do php.net: só backport do fornecedor ou atualizar o ramo.\n";
} elseif (version_compare(PHP_VERSION, $corrigida[$ramo], '>=')) {
    echo "OK pelo número: igual ou acima de {$corrigida[$ramo]}.\n";
} else {
    echo "ABAIXO de {$corrigida[$ramo]}: confira se o pacote da distro tem backport.\n";
}
foreach (['session.upload_progress.enabled', 'memory_limit', 'post_max_size', 'fatal_error_backtraces'] as $k) {
    $v = ini_get($k);
    echo str_pad($k, 32) . ($v === false ? '(não existe neste ramo)' : var_export($v, true)) . "\n";
}

Saída real no PHP 8.1 da imagem oficial e no Ubuntu 24.04 corrigido:

$ docker run --rm -v "$PWD":/t php:8.1-apache php /t/checa-php2shell.php
PHP 8.1.34 (SAPI cli)
Ramo 8.1 sem correção oficial do php.net: só backport do fornecedor ou atualizar o ramo.
session.upload_progress.enabled '1'
memory_limit                    '128M'
post_max_size                   '8M'
fatal_error_backtraces          (não existe neste ramo)

# Ubuntu 24.04, pacote 8.3.6-0ubuntu0.24.04.13
PHP 8.3.6 (SAPI cli)
ABAIXO de 8.3.36: confira se o pacote da distro tem backport.

Note a segunda saída: é a armadilha da seção anterior em ação. Por isso o script manda conferir o pacote em vez de declarar vulnerável.

Se não dá para atualizar hoje

O php.net, a CISA e a AWS repetem: só atualizar resolve. As medidas oficiais abaixo apenas fecham caminhos de ataque conhecidos e precisam ser aplicadas na configuração de inicialização (php.ini, pool do FPM com php_admin_value ou configuração do Apache), nunca com ini_set() ou .user.ini, sempre reiniciando todos os workers:

  • session.upload_progress.enabled=0: bloqueia o caminho de sessão confirmado da 109619. Em 23/10 o php.net publicou um aviso complementar recomendando manter essa opção desligada até a próxima versão regular, por causa de uma terceira falha (CVE-2026-115560) que só aparece numa combinação incomum de session.serialize_handler.
  • fatal_error_backtraces=0, só no PHP 8.5: remove o caminho de erro fatal confirmado. No teste acima, a imagem 8.5 veio com o valor 1.
  • memory_limit=-1 definido de forma que a aplicação não consiga sobrescrever: tira o estouro controlável da 109618, mas troca o risco por consumo de memória, então combine com limite de memória no container ou cgroup. O aviso proíbe usar RLIMIT_AS ou RLIMIT_DATA, que levam justamente ao caminho vulnerável.
  • post_max_size baixo (8M sem upload, 32M com upload) e limites no proxy para tamanho do corpo, número de partes e cabeçalhos do multipart, valendo também para requisições sem Content-Length. Se a aplicação não recebe formulários multipart, bloqueie esse tipo de requisição antes do PHP.

Os ajustes de php.ini e pool estão detalhados no nosso guia de configuração do PHP para produção. Como a 109619 depende de erros fatais e avisos emitidos antes da inicialização, vale também revisar o que aparece no log: esconder com @ ou display_errors não protege, e o texto sobre display_errors em produção mostra como manter o erro no log sem exibi-lo.

Procurar invasão a partir de 17/10

A marca de triagem forense no KEV e o relato da AWS apontam na mesma direção: a investigação começa na data da primeira exploração conhecida, 17 de outubro, e não no dia em que você aplicou o patch. Os sinais citados pelas fontes oficiais:

  • Processos do worker PHP (usuário www-data, apache ou nginx) abrindo shell ou baixando ferramentas, que é o sinal destacado pela CISA. Um ps -eo user,pid,ppid,cmd --forest mostra filhos estranhos de php-fpm ou apache2.
  • Arquivos .php novos ou alterados desde 17/10 em pastas graváveis pelo servidor web, por exemplo com find /var/www -name '*.php' -newermt 2026-10-17.
  • Requisições POST multipart com o campo PHP_SESSION_UPLOAD_PROGRESS, sugeridas pela AWS. Esse campo fica no corpo da requisição, então só aparece se você tiver WAF ou log de corpo. O log de acesso comum não mostra.
  • Acessos vindos dos IPs publicados pela AWS. Ela avisa que são redes de anonimização compartilhadas: servem para investigar, não para bloquear às cegas.

A CISA também publicou uma regra SIGMA no seu repositório no GitHub, citada na atualização de 23/10 do alerta, para quem centraliza logs num SIEM.

E o Windows?

Quem usa os binários oficiais do PHP para Windows deve atualizar para as mesmas versões e prestar atenção ao sufixo -1: em 26/10 o php.net publicou os builds 8.5.12-1, 8.4.27-1, 8.3.36-1 e 8.2.35-1, com a biblioteca Brotli 1.2.1. Eles corrigem a falha no Brotli (CVE-2026-111497), alcançável pela extensão cURL quando a descompressão automática está ligada. O código do PHP é o mesmo, então o php -v não mostra a diferença: confira o nome do pacote baixado.

Em resumo, para fechar o PHP2Shell de verdade, você precisa de três evidências: o pacote ou a imagem na versão corrigida, o serviço web reiniciado depois disso e a busca por sinais de invasão desde 17/10. Só o php -v no terminal não prova nenhuma das três.

Avalie este artigo