PHP2Shell: a vulnerabilidade crítica no motor do PHP que pode comprometer metade da web
CVE-2026-109618 e CVE-2026-109619 (PHP2Shell) são duas falhas críticas de corrupção de memória no próprio motor PHP, com CVSS 9.2, que permitem RCE não autenticado por um simples POST — independentemente da aplicação. Mecanismo, exploração em estado real e como verificar se estás vulnerável.
Duas falhas críticas no próprio motor do PHP — não numa aplicação específica — permitem execução remota de código não autenticada com um único pedido HTTP. Afetam WordPress, Drupal, Joomla e qualquer outra coisa escrita em PHP, independentemente de o código da aplicação estar certo.
No dia 21 de outubro de 2026 o projeto PHP publicou correções de emergência para duas vulnerabilidades críticas de corrupção de memória, rapidamente apelidadas PHP2Shell. Não são bugs de um CMS ou de um plugin: são bugs no interpretador PHP em si, no código que processa qualquer pedido HTTP antes de uma única linha da aplicação ser executada.
Isto importa-te mesmo que não escrevas PHP. Se alojas, giras ou simplesmente usas um site WordPress, Drupal, Joomla, Magento ou qualquer aplicação PHP — a vulnerabilidade está por baixo da aplicação, não dentro dela.
O que é o PHP2Shell
CVE-2026-109618 e CVE-2026-109619 são duas falhas distintas, com CVSS v4.0 de 9.2 cada, classificadas como CWE-824 (acesso a ponteiro não inicializado/pendente). Ambas permitem a um atacante não autenticado executar comandos arbitrários no servidor web através de HTTP simples — sem sessão, sem conta, sem precisar de um endpoint vulnerável da aplicação.
A causa raiz comum, segundo a análise da CrowdStrike, está em como o PHP trata condições fatais: quando o interpretador encontra um erro fatal — esgotar o memory_limit, exceder o max_execution_time, perder a ligação ao cliente — a rotina interna zend_bailout() usa um longjmp para abortar o pedido imediatamente, saltando a limpeza normal de memória. As estruturas internas ficam num estado inconsistente, mas o código de encerramento assume que estão íntegras.
A partir daqui as duas CVEs seguem caminhos diferentes:
- CVE-2026-109618 (dentro do mesmo pedido): ao inserir uma chave num array, o PHP incrementa o contador de elementos antes de alocar memória para essa chave. Se a alocação ultrapassar o
memory_limitnesse instante exato, a entrada do array fica com bytes residuais do heap em vez de um ponteiro válido. Na fase de encerramento, o PHP lê essa entrada corrompida e trata esses bytes como se fossem um valor com contagem de referências — desreferenciando um "ponteiro" cujo conteúdo o atacante pode influenciar moldando o tamanho dos campos enviados no corpo do pedido POST. O único rasto típico no log é um erro fatal de memória com a assinaturain Unknown on line 0, que indica que a falha ocorreu antes de qualquer script da aplicação correr. - CVE-2026-109619 (entre pedidos, em workers persistentes): um erro fatal interrompe uma operação de serialização ou de sessão antes da limpeza. Um ponteiro global do PHP fica a apontar para memória já libertada, mas o contador de aninhamento continua a indicar que a operação está "ativa". Em modelos de worker persistente — como o
mod_phpdo Apache — o próprio processo PHP sobrevive ao pedido que falhou. O pedido seguinte, no mesmo worker, reutiliza esse ponteiro pendente. Como o atacante também controla esse segundo pedido, consegue colocar dados próprios na memória entretanto reaproveitada. A funcionalidade usada para desencadear isto —session.upload_progress— está ativa por omissão desde o PHP 5.4.0.
A CrowdStrike afirma ter verificado, de ponta a ponta, que um único pedido POST anónimo é suficiente para que um worker mod_php do Apache arranque um processo de shell, em arquiteturas x86-64 e ARM64.
Há ainda uma nuance de configuração: segundo a mesma análise, a falha só fica praticamente alcançável quando memory_limit é relativamente baixo face a post_max_size — algo próximo de memory_limit < 4 × post_max_size. Os valores por omissão do PHP (8 MB e 128 MB) não cumprem essa condição, mas combinações comuns em alojamento partilhado (por exemplo 64 MB e 128 MB) cumprem-na perfeitamente.
Importa notar que a autoria original da descoberta não está totalmente esclarecida. Parte da imprensa de segurança atribui a investigação de base à Wiz Research; outras fontes (Tanium, SecurityWeek) referem que os detalhes técnicos vazaram publicamente antes da coordenação prevista com o projeto PHP, num site externo, e que a watchTowr afirma ter reproduzido de forma independente a CVE-2026-109618 sem detalhar o método. Trata-se de uma divulgação atribulada, com relatos que nem sempre coincidem entre si.
Quem está afetado
Toda a gente que corre PHP. Literalmente. Como a falha está no motor e é acionada antes de qualquer código da aplicação compilar, qualquer endpoint PHP de um servidor exposto é superfície de ataque — não importa se é WordPress, um script caseiro de 20 linhas ou uma API em Laravel.
| Ramo | Versões afetadas | Corrigida em |
|---|---|---|
| PHP 8.2 | anteriores a 8.2.35 | 8.2.35 |
| PHP 8.3 | anteriores a 8.3.36 | 8.3.36 |
| PHP 8.4 | anteriores a 8.4.27 | 8.4.27 |
| PHP 8.5 | anteriores a 8.5.12 | 8.5.12 |
| PHP ≤ 8.1, 7.x | sem correção oficial | fim de vida — migrar |
As correções saíram a 21 de outubro de 2026. Relatos públicos (sem causa-raiz totalmente confirmada) sugerem que o código afetado existe desde o PHP 5 — mas só os quatro ramos com suporte ativo receberam patch. Se ainda tens PHP 7.4, 8.0 ou 8.1 em produção, não há correção oficial à espera: a única opção séria é migrar para um ramo suportado.
Foi demonstrada RCE não autenticada contra instalações WordPress, Drupal e Joomla — não porque estes CMS tenham um bug próprio, mas porque corriam em PHP vulnerável.
Exploração em estado real
A cronologia é preocupante:
- Detalhes técnicos vazaram antes da data de coordenação prevista para a divulgação, obrigando o projeto PHP a antecipar o lançamento das correções.
- A Amazon reportou ter detetado tentativas de exploração quatro dias antes das correções estarem disponíveis.
- A watchTowr registou exploração ativa na sua rede global de honeypots já a 21 de outubro.
- A Patchstack recebeu relatos de parceiros de alojamento com incidentes de exploração antes do lançamento oficial do patch (até às 07:34 UTC do dia 21).
- A Cloudflare (CTO Dane Knecht) confirmou ataques precoces e publicou regras de WAF contra vetores conhecidos.
- Na Holanda, organizações — incluindo o NCSC — retiraram sites do ar por precaução, depois de uma PoC ter vazado antecipadamente.
- A Sansec previu exploração em massa a começar cerca de 15 minutos depois da publicação dos patches — o tempo que leva a fazer reverse engineering ao diff do código.
- A Modat e a VirusTotal contabilizaram milhões de serviços/IPs a correr PHP, mas a maioria das versões visíveis é de ramos já sem suporte (ex.: PHP 7.4) — estes números não confirmam quantos hosts estão realmente vulneráveis.
Até à data de publicação deste artigo, não há IOCs (indicadores de comprometimento) públicos e confirmados. Existem PoCs publicadas no GitHub (por exemplo poc0_109618.py e poc1_109619.py, atribuídas a J4ck3LSyN), mas a Insikt Group da Recorded Future não as validou de forma independente, e o próprio autor de uma delas já invalidou a teoria em que se baseava. Não publicamos aqui nenhum exploit funcional — pelas razões que explicamos a seguir.
Como funciona o ataque (sem exploit funcional)
É propositado não publicarmos código de exploração pronto a correr. Não porque o mecanismo seja secreto — já está descrito em detalhe por várias empresas de segurança, e resumimos acima — mas porque:
- As PoCs públicas conhecidas até agora são de fiabilidade duvidosa (uma delas assenta numa premissa que o próprio autor já desmentiu);
- Explorar com sucesso exige moldar o conteúdo residual do heap de forma determinística, o que depende de detalhes de alocador, arquitetura e configuração — não é um "copy-paste";
- A exploração em massa já está em curso; publicar mais um exploit funcional só acrescentaria combustível, sem valor defensivo adicional.
Dito isto, para entenderes o que procurar nos teus logs, a sequência conceptual de um ataque à CVE-2026-109619 (o vetor mais documentado) é:
Pedido 1 — "envenenar" o worker
POST /qualquer-endpoint.php HTTP/1.1
Content-Type: multipart/form-data; boundary=...
[campo com PHP_SESSION_UPLOAD_PROGRESS a forçar
uma falha fatal a meio da serialização da sessão —
p. ex. upload interrompido / limite de tempo excedido]
→ o worker mod_php sobrevive à falha, mas fica com
um ponteiro global a apontar para memória já libertada
Pedido 2 — disparar o use-after-free, no MESMO worker
POST /qualquer-endpoint.php HTTP/1.1
[corpo desenhado para realocar exactamente o bloco
de memória libertado no pedido 1, com bytes que o
PHP volta a interpretar como estruturas internas —
incluindo, no cenário demonstrado pela CrowdStrike,
um ponteiro para exec/system]
→ o processo PHP arranca um shell
Não há aqui nenhum payload funcional: faltam de propósito os valores exactos de boundary, os tamanhos de campo, o offset do heap e o shellcode/comando final — é precisamente a parte que exige engenharia inversa cuidadosa ao binário/versão alvo, e que não vamos facilitar.
A CVE-2026-109618 é mais simples na forma (um único pedido, sem precisar de reutilizar worker), mas exige controlar com precisão o tamanho do nome de um campo de array no corpo POST para que a falha de alocação de memória aconteça exactamente no momento certo — novamente, algo que depende da configuração (memory_limit/post_max_size) e do alocador do Zend Memory Manager da versão em causa.
Como verificar se o teu sistema está vulnerável
1. Confirma a versão do PHP
Confirma contra a tabela de versões corrigidas acima. Atenção a cópias de PHP "embutidas" que o php -v da shell não vê: XAMPP, WampServer, Laragon no Windows, PHP compilado à mão por uma aplicação de terceiros, ou uma imagem Docker com tag fixa que ninguém atualizou.
2. Verifica a configuração de risco
Se memory_limit for inferior a cerca de 4× o post_max_size, a combinação está dentro da janela de configuração que a CrowdStrike descreve como mais facilmente explorável para a CVE-2026-109618. Isto não significa que combinações fora dessa janela estejam seguras — é apenas um sinal de risco adicional, não uma prova de segurança.
3. Procura sinais nos logs (deteção, não confirmação)
Não há IOCs públicos confirmados, mas vale a pena rever, desde 20 de outubro de 2026:
- Erros fatais de PHP com a assinatura
PHP Fatal error: ... in Unknown on line 0(indica falha antes de qualquer script correr — consistente com a CVE-2026-109618); - Crashes ou reinícios inesperados de workers
php-fpmoumod_php; - Pedidos
multipart/form-dataanómalos ou malformados, sobretudo com campos dePHP_SESSION_UPLOAD_PROGRESS; - Processos filho inesperados gerados a partir do PHP ou do servidor web (
sh,bash, binários desconhecidos) — um EDR com deteção comportamental apanha isto mesmo sem assinatura específica da vulnerabilidade; - Picos de erros 500 sem alteração de código correspondente.
Como a exploração ocorre abaixo da camada de aplicação, os logs da aplicação (framework, CMS) podem não registar nada de anómalo — a investigação tem de olhar para os logs do servidor web e do gestor de processos PHP.
Mitigação
- Atualiza o PHP. É a única correção completa. Prioriza sistemas expostos à internet. Depois de atualizar, reinicia o PHP-FPM e o servidor web — o binário novo só entra em efeito depois do reinício dos workers.
- Sem patch imediato disponível?
- Restringe o acesso externo ao que for possível (rede, firewall, Cloudflare/WAF — a Cloudflare e a VulnCheck já publicaram regras contra os vetores conhecidos).
- Desativa parcialmente um dos vetores:
session.upload_progress.enabled=0, definido nophp.iniou num pool do FPM (oini_set()e o.user.ininão funcionam para esta diretiva — tem de ser configuração de arranque, com reinício a seguir). Isto mitiga apenas parte da CVE-2026-109619; não tem qualquer efeito sobre a CVE-2026-109618. - Nenhuma destas medidas substitui a atualização — são só para ganhar tempo.
- Ramos em fim de vida (PHP ≤ 8.1): não têm correção oficial. Planeia a migração — não há mitigação de configuração que resolva isto de forma fiável.
- Depois de corrigir: se encontraste algum dos sinais da secção anterior num sistema que esteve exposto e sem patch, trata-o como potencialmente comprometido — ativa resposta a incidentes e roda credenciais, tokens e chaves de API que possam ter sido expostos pela fuga de memória (a vulnerabilidade também permite ler memória de outros pedidos, mesmo sem chegar a RCE).
Conclusão
O PHP2Shell não é "mais um CVE de WordPress". É uma falha no motor que serve uma fração enorme da web — e a janela entre o vazamento dos detalhes e a disponibilidade do patch já bastou para exploração em estado real antes da correção oficial. Se giras alguma coisa em PHP, a prioridade é simples: confirma a versão, atualiza, reinicia os workers, e só depois te preocupes com mitigações de configuração.
Não vamos publicar um exploit pronto a usar — o mecanismo já está descrito com detalhe suficiente para quem precisa de o entender para se defender, e mais do que isso só ajudaria quem já está a tentar atacar.
Fontes
- Recorded Future — PHP2Shell: Vulnerability and Exploitation Overview
- CrowdStrike — CrowdStrike Protects Customers from Threats Delivered via PHP2Shell
- SecurityWeek — PHP2Shell: Mass Exploitation Looms for Leaked Critical PHP Flaws
- Tanium — PHP2Shell: Responding to CVE-2026-109618 and CVE-2026-109619
- Fastly — Fastly's proactive protection for critical PHP RCE (CVE-2026-109618)
- Island.io — PHP2Shell turns nearly half of the web into exploitation infrastructure
- Techzine — PHP shuts the internet: why PHP2Shell affects every company
Partilhar
Comentários 0
Ainda sem comentários — sê o primeiro.