Skip to main content
Início
  • Login
  • Home
  • AppSec & DevSecOps
  • Exposição Cibernética
  • Governança & Cultura
  • Parceiros
  • Blog
  • Contato
  1. Início

PHP2Shell: A Vulnerabilidade no PHP que Abalou a Internet

Fri, 23/10/2026 - 3:34pm by sarah

Análise técnica das CVE-2026-109618 e CVE-2026-109619.

Por Alan Lacerda, Consultor de Segurança da Informação Sênior Haas

No dia 21 de outubro de 2026 o time de segurança do PHP publicou uma correção de emergência para duas falhas críticas que ganharam o apelido de PHP2Shell: a CVE-2026-109618 e a CVE-2026-109619, ambas com nota CVSS v4.0 9.2 [1][2][3]. As duas permitem execução remota de código sem autenticação. 

Um atacante que só consegue mandar uma requisição HTTP para o servidor, sem usuário, sem senha, sem nada, pode rodar código no sistema operacional com os privilégios do processo que serve o PHP. Isso acontece antes de a aplicação executar uma única linha, então nenhum login, token ou regra de permissão escrita no código entra no caminho [2][3].

O conselho prático do que fazer é um velho conhecido: atualize para a versão mais nova (8.5.12, 8.4.27, 8.3.36 ou 8.2.35) [1][5]. O que vale a pena entender, e é o assunto deste texto, é o que causa essas duas falhas. Elas não estão em nenhuma biblioteca exótica, num recurso que quase ninguém usa, nem numa configuração específica que precise ser feita, estão no coração do PHP, na forma como ele monta e desmonta cada requisição.

Como o PHP atende uma requisição

Antes das falhas, um conceito: quando você acessa um site em PHP, não existe um programa novo nascendo e morrendo a cada clique. Por desempenho, o servidor mantém de pé um conjunto de processos chamados workers, e cada worker atende uma requisição atrás da outra, reaproveitando o mesmo processo [4]. É como um caixa de banco que atende um cliente, limpa a mesa e chama o próximo, sem trocar de pessoa a cada atendimento.

A cada requisição, o PHP monta um estado temporário: 

  1. os arrays $_GET e $_POST, 

  2. a sessão, 

  3. as variáveis internas daquele pedido. 

 

Quando a requisição termina, ele desmonta tudo isso para que a próxima comece com “a mesa limpa” [4]. Dá para pensar em duas camadas: 

  1. existe o estado por-requisição, que deveria viver só durante aquele pedido, 

  2. e o estado do worker, que sobrevive de um pedido para o outro. 

 

As duas falhas do PHP2Shell moram exatamente na fronteira entre essas camadas. Uma vulnerabilidade aparece quando a desmontagem encontra algo pela metade, e a outra, quando algo de um pedido sobra e contamina o pedido seguinte
 

CVE-2026-109618: A falta de memória corrompe a limpeza

Primeiro vamos entender dois conceitos importantes:

  1. Hash table é a estrutura de dados que o PHP usa por baixo de todo array, incluindo o $_POST: uma tabela que guarda pares de chave e valor e encontra cada um deles rapidamente. 

  2. memory_limit é o teto de memória que cada requisição pode consumir; quando o pedido tenta passar desse teto, o PHP aborta na hora com um erro fatal de memória esgotada, o chamado OOM (out of memory) [4].

O texto oficial do PHP descreve a falha assim: 

“o tratamento de falta de memória pode interromper o PHP enquanto dados internos da requisição ainda estão apenas parcialmente inicializados, e a limpeza da requisição mais tarde trata esse dado inválido como se fosse válido [2].” 

A análise da Datadog mostra onde isso acontece no código [4]: Ao inserir um item numa hash table, a função interna responsável incrementa os contadores que dizem "quantos itens existem aqui" antes de reservar a memória da chave nova. Se a reserva dessa chave estoura o memory_limit bem nesse instante, o PHP dispara o erro fatal e desiste da inserção, mas os contadores já foram incrementados. Sobra na tabela uma posição que o PHP considera ocupada, embora a chave e o valor dela nunca tenham sido escritos [4]. É como marcar a presença de alguém na lista antes de a pessoa de fato sentar na cadeira: a lista diz que a pessoa está lá, mas a cadeira está vazia.

Para chegar nesse caminho específico de inserção, o atacante usa nomes de campo em formato de array aninhado no corpo do POST, do tipo a[b]; nomes simples seguem outro caminho interno, que não é afetado [4]. Quando a requisição termina e o PHP desmonta o $_POST, ele passa por aquela posição fantasma e interpreta o lixo de memória que estava ali como se fossem valores PHP legítimos. Como esse lixo pode ser influenciado pelo conteúdo que o atacante mandou, ele ganha controle sobre o que a rotina de limpeza faz, e é dessa brecha que sai a execução de código [4]. 

Perceba no detalhe que torna tudo mais grave: nada disso depende da aplicação desenvolvida usando o PHP. A corrupção acontece na montagem e na desmontagem do pedido, abaixo do WordPress, do Laravel ou de qualquer coisa rodando em cima [2][4] (ou seja, o problema está no próprio PHP).

 

CVE-2026-109619: A requisição anterior afeta a próxima

Vamos conhecer primeiro mais um termo novo: use-after-free, ou uso após liberação:

  • É quando o programa continua acessando, por um ponteiro antigo, uma região de memória que ele já devolveu para ser reaproveitada. Como aquela região pode já ter sido entregue a outra finalidade, ler ou escrever ali gera comportamento imprevisível, e nas mãos certas vira uma primitiva de ataque [4].

O texto oficial resume: um estado interno que pertence à requisição pode sobreviver depois que a memória que o sustentava já foi liberada, e uma requisição seguinte, atendida pelo mesmo worker, pode usar esse estado velho antes de a inicialização normal o reiniciar [3]. Em outras palavras: um ponteiro que vive no nível do worker aponta para memória do pedido anterior; o pedido acaba, a memória é liberada, mas o ponteiro não é zerado. O próximo pedido que cair naquele worker segue o ponteiro antigo [4].

A Datadog confirmou dois caminhos para isso [4]:

  1. O primeiro aparece só no PHP 8.5: o estado de um backtrace de erro fatal (o rastro que o PHP monta quando um erro grave estoura) persiste depois do encerramento e é lido por um diagnóstico de configuração na requisição seguinte, antes da inicialização.

  2. O segundo é mais universal e passa pelo session.upload_progress, um recurso que acompanha o progresso de uploads, vem ligado por padrão e roda mesmo que a aplicação nunca chame session_start() [4]. Estado deixado para trás depois de um erro fatal durante um upload acaba sendo lido por um upload posterior antes de ser reiniciado. 

O primeiro caminho foi confirmado em mod_php; o segundo, em mod_php e em PHP-FPM, com a ressalva de que no FPM a aplicação ainda precisa executar alguma operação adequada depois de iniciar [4].

Tem um pré-requisito que o pentester precisa guardar: as requisições do atacante precisam cair no mesmo worker para que o estado órfão de uma seja lido pela outra. Em servidores com um pool grande de workers, a chance de dois pedidos consecutivos pegarem o mesmo processo diminui, o que reduz a taxa de sucesso do ataque sem corrigir a falha [4]. 

IMPORTANTE: Existe uma diferença entre "difícil de acertar" e "seguro", e as duas coisas não são a mesma.

 

O que o patch mudou

As correções atacam as duas falhas na mesma fronteira, por ângulos diferentes [1][4]. Para a CVE-2026-109618, o PHP passou a tratar a falta de memória de outro jeito. Um limite mais baixo, "soft", adia o erro para um ponto seguro, deixando a operação em curso terminar de se inicializar antes de o erro ser levantado. E um limite mais alto, "hard", faz o PHP encerrar o worker na hora, chamando _exit(137), em vez de rodar a limpeza normal, que era justamente onde a corrupção acontecia [4]. A lógica é simples: ou a operação termina inteira, ou o processo morre limpo, nunca para no meio do caminho.

Para a CVE-2026-109619, o patch garante que o estado de posse da requisição seja reiniciado antes de o worker ser reutilizado, limpa o estado de erro e de exceção no encerramento, e inicializa a sessão e a serialização cedo o bastante para que nenhuma requisição o alcance num estado antigo [4].

Um ponto que a própria Datadog faz questão de registrar, e que importa para quem vai conviver com isso é: a ordem problemática no código da hash table, incrementar o contador antes de a alocação dar certo, continua existindo no 8.5.12. O patch mudou o tratamento de erro ao redor dela, não a ordem em si [4]. O padrão de base, mexer em metadados antes de ter certeza de que a alocação funcionou, segue vivo em outros pontos do motor e tende a reaparecer, especialmente nos ramos mais antigos que receberam apenas backports mínimos [4]. A ferida específica foi fechada; a classe do problema, não.

Quem está exposto

Figura 1 - Busca por PHP 8.5.11 no Shodan

O PHP se conecta ao servidor web de várias formas, e o jargão para isso é SAPI (Server API). As mais comuns são o mod_php (o PHP embutido no Apache), o PHP-FPM (um pool de processos separado, usado com o nginx e também com o Apache) e, menos frequentes, o php-cgi, o FrankenPHP e o LiteSpeed. O aviso do PHP coloca todas as implantações web no escopo, com o risco mais alto no mod_php, onde os dois CVEs foram confirmados [1][4]. Quem usa o PHP só na linha de comando, para scripts, sem servir web, não está na linha de frente desse ataque [1].

Na hora de olhar um alvo, cuidado com uma armadilha comum: a versão que aparece quando você roda php -v no terminal é a do binário de linha de comando, que pode ser diferente da versão que o servidor web realmente usa [4][8]. O que interessa é o PHP que atende as requisições. Isso costuma aparecer no cabeçalho HTTP X-Powered-By (quando o servidor não o esconde), numa página phpinfo() esquecida, ou conferindo o módulo carregado no Apache e a versão do pool do PHP-FPM direto no servidor, quando há acesso. No relatório, o que importa registrar é a versão exata, a SAPI em uso e o impacto: execução remota de código sem autenticação, com os privilégios do usuário do servidor web [1][5].

As versões que corrigem são 8.5.12, 8.4.27, 8.3.36 e 8.2.35 [1]. Os ramos mais antigos ficam num limbo que vale a pena mencionar: o projeto publicou backports mínimos de código-fonte para 7.4, 8.0 e 8.1, mas 8.1 e anteriores não recebem mais atualização oficial, e a 8.2 chega ao fim de vida em 31 de dezembro de 2026 [1][11]. Distribuições Linux e fornecedores de suporte estendido estão lançando seus próprios pacotes, às vezes sem mudar o número da versão, então conferir o aviso do fornecedor faz parte do trabalho [5][10][11]. 

Mas ainda existe outro problema: equipamentos de rede e appliances que embarcam o próprio PHP, raramente atualizados, que já começaram a aparecer na lista de produtos afetados de alguns fabricantes [5][7] (ex.: modems, câmeras, e diversos devices IoT). São justamente esses que ficam vulneráveis por anos.

https://php2shell.censys.com/

Depois da tempestade inicial, o que sobrou

As duas falhas do PHP2Shell contam a mesma história por ângulos diferentes. Num modelo em que o processo é reaproveitado de requisição em requisição, a fronteira entre a memória que pertence ao pedido de agora e o estado que sobrevive no worker é delicada por natureza. O lado mais incômodo não é o par de bugs que foi corrigido, e sim o reconhecimento, da própria Datadog, de que o padrão que os gerou continua no código [4]. Some a isso os milhões de instalações antigas e embarcadas que nunca verão o patch, e fica claro que o PHP2Shell vai durar bem mais do que o ciclo de notícia que o criou.

Referências

[1] PHP. “Upcoming/Published Critical Security Release” (avisos de 20 e 21/10/2026). https://www.php.net/archive/2026.php

[2] GitHub Security Advisory GHSA-w8hw-w9fx-j79w (CVE-2026-109618). https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w

[3] GitHub Security Advisory GHSA-6wmf-4rv5-p3rp (CVE-2026-109619). https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp

[4] Datadog Security Labs. “PHP2Shell: critical vulnerabilities in PHP — detection, analysis, and remediation.” https://securitylabs.datadoghq.com/articles/php2shell-critical-vulnerabilities-in-php/

[5] Help Net Security. “PHP2Shell: Critical PHP vulnerabilities patched, update now!” https://www.helpnetsecurity.com/2026/10/21/php2shell-php-vulnerabilities-patched-cve-2026-109618-cve-2026-109619/

[6] BleepingComputer. “PHP ships emergency patches for critical PHP2Shell flaws.” https://www.bleepingcomputer.com/news/security/php-ships-emergency-patches-for-critical-php2shell-flaws/

[7] The Hacker News. “PHP Issues Emergency Patches for Two Critical PHP2Shell RCE Flaws.” https://thehackernews.com/2026/10/php-issues-emergency-patches-for-two.html

[8] Tenable. “php2shell (CVE-2026-109618, CVE-2026-109619): FAQ.” https://www.tenable.com/blog/php2shell-cve-2026-109618-cve-2026-109619-frequently-asked-questions-about-critical-php-remote

[9] Sansec. “PHP2Shell research.” https://sansec.io/research/php2shell

[10] AlmaLinux. “php2shell (CVE-2026-109618, CVE-2026-109619): patched packages released.” https://almalinux.org/blog/2026-10-21-php2shell-cve-2026-109618-cve-2026-109619/

[11] TuxCare. “TuxCare Patches php2shell for the PHP Versions Upstream Left Behind.” https://tuxcare.com/blog/php2shell-cve/

[12] Cloudflare. “WAF Release — 2026-10-21 — Emergency — Cloudflare Managed Ruleset.” https://developers.cloudflare.com/changelog/post/2026-10-21-emergency-waf-release-cfmr/

 

footer footercustom

Contato

Av. Angélica, 2582
2° Andar
CEP 01228-200
Bela Vista
São Paulo / SP

contato@ibliss.com.br


+55 (11) 3255 -3926

Links

  • A IBLISS

  • Blog

  • Oportunidades

  • Contato

  • Aviso de Privacidade

  • Política de Cookies

Siga-nos

  • Instagram
  • Linkedin
  • Facebook
  • Youtube

Newsletter

© 2026 IBLISS Digital Security — Todos os direitos reservados.