Voltar para o Blog

PHP2Shell em 2026: Como Proteger Seu Servidor PHP das Falhas CVE-2026-109618 e 109619

Olá HaWkers, no dia 21 de outubro de 2026 o projeto PHP soltou uma atualização de emergência: as versões 8.5.12, 8.4.27, 8.3.36 e 8.2.35 corrigem duas falhas críticas que permitem execução remota de código sem autenticação. As duas receberam nota 9.2 no CVSS e ficaram conhecidas pelo apelido de PHP2Shell, porque o caminho final do ataque é ganhar um shell no servidor.

O detalhe que assusta: as falhas existem desde o PHP 5.4, atacam partes do motor que praticamente toda requisição toca (gerenciamento de memória e tratamento de erros) e, no Apache com mod_php, o ataque acontece antes de qualquer linha do seu código rodar. Não importa se o seu Laravel está impecável.

Você sabe agora, sem abrir o terminal, qual versão do PHP está rodando em produção? Se a resposta for "acho que é a 8.2", este artigo é para você. No fim dele você vai ter um checklist para atualizar, aplicar mitigações enquanto não atualiza e procurar sinais de que alguém já tentou entrar.

O Que É o PHP2Shell e Por Que Ele É Tão Grave

São duas vulnerabilidades diferentes, publicadas juntas:

  • CVE-2026-109618 (RCE via corrupção por falta de memória): quando uma requisição bate no memory_limit no momento errado, o PHP pode deixar dados internos da requisição parcialmente inicializados. Na limpeza, o motor trata esse lixo como dado válido e corrompe a memória. O vetor conhecido é um nome de campo de formulário gigante.
  • CVE-2026-109619 (RCE via estado global "velho"): um erro fatal no ponto errado deixa estado interno apontando para memória de uma requisição anterior que já foi liberada. A próxima requisição atendida pelo mesmo worker usa essa memória: é o clássico use-after-free. O vetor conhecido passa pelo callback do session.upload_progress.

As duas falhas não exigem login nem interação do usuário. A complexidade de ataque é considerada alta, mas isso não traz muito alívio, porque o próprio PHP demonstrou execução remota de código no Apache com mod_php usando as configurações padrão.

Quem corre mais risco

O impacto depende de como o PHP é executado (a chamada SAPI):

Forma de execução Risco O que se sabe
Apache + mod_php Mais alto RCE demonstrado antes do código da aplicação rodar
PHP-FPM Alto RCE confirmado via caminhos do código da aplicação
php-cgi, FrankenPHP, LiteSpeed Em risco Listados como afetados, sem a mesma demonstração pública

Em resumo: se o seu PHP atende requisições HTTP, você está no grupo afetado.

A Linha do Tempo: Auditorias, IA e um Embargo Que Vazou

A história de como essas falhas apareceram diz muito sobre a segurança de open source em 2026. Segundo o blog da PHP Foundation:

  • 2024: a Quarkslab faz a primeira auditoria externa do PHP em anos, organizada pelo OSTIF e financiada pela Sovereign Tech Agency. Corrigindo um problema relatado ali, um desenvolvedor do core encontra os primeiros sinais do bug de falta de memória.
  • Maio de 2026: a fundação cria o Ecosystem Security Team.
  • A partir de 1º de julho de 2026: o time publica 15 CVEs e processa mais de 100 relatórios inválidos, duplicados ou não reproduzíveis.
  • 30 de julho de 2026: a Calif começa a auditar o PHP pelo programa Patch the Planet, da OpenAI.
  • 11 de agosto de 2026: o pesquisador Ryan A, da Calif, reporta um RCE incondicional com a mesma causa raiz.
  • 24 de agosto e 18 de setembro de 2026: a Wiz e a OpenAI reportam outros vetores de ataque.
  • 20 de outubro de 2026: os IDs dos CVEs vazam na internet com horário de release e nota errados (circulou um 10.0), o PHP publica o pré-anúncio antes do previsto e a Calif publica sem querer um vídeo da prova de conceito.
  • 21 de outubro de 2026, 14:00 UTC: release coordenado, antecipado do dia 22.

Repare em duas coisas. Primeiro, ferramentas de IA estão no meio do processo: a Alpha-Omega rodou o Claude Mythos, da Anthropic, contra o código do PHP, e o time passou a usar o Daybreak Red, da OpenAI, para validar relatórios. Segundo, o embargo não segurou. Quando o patch saiu, muita gente já sabia exatamente onde olhar.

Passo 1: Descubra Qual PHP Você Está Rodando

Parece óbvio, mas o PHP do terminal nem sempre é o mesmo que atende o site. Um servidor pode ter o CLI na 8.3 e o FPM na 8.2. Confira os dois:

# Versão do PHP de linha de comando
php -v

# Versões do PHP-FPM instaladas (Debian/Ubuntu)
ls /usr/sbin/php-fpm* 2>/dev/null
for bin in /usr/sbin/php-fpm*; do "$bin" -v | head -n 1; done

# Pergunte ao próprio servidor web qual PHP responde
# (crie o arquivo, acesse e APAGUE logo em seguida)
echo '<?php echo PHP_VERSION, " ", PHP_SAPI;' > /var/www/html/versao-tmp.php
curl -s https://seu-dominio.com.br/versao-tmp.php; echo
rm /var/www/html/versao-tmp.php

Com a versão em mãos, compare com a tabela de correções:

Ramo Vulnerável Corrigido
PHP 8.5 abaixo de 8.5.12 8.5.12
PHP 8.4 abaixo de 8.4.27 8.4.27
PHP 8.3 abaixo de 8.3.36 8.3.36
PHP 8.2 abaixo de 8.2.35 8.2.35

E se aparecer 8.1, 8.0 ou 7.4? Esses ramos não recebem mais atualização do projeto. O time de segurança publicou backports mínimos em código-fonte para 7.4, 8.0 e 8.1, voltados a quem compila o PHP por conta própria, e distribuições e fornecedores de suporte estendido receberam os patches antes. Fora isso, o caminho é migrar. Lembre também que o PHP 8.2 chega ao fim de vida em 31 de dezembro de 2026, então quem está nele vai ter que mexer de novo em breve.

Passo 2: Atualize (e Reinicie Todos os Workers)

A correção completa é uma só: atualizar. O resto do artigo é contenção. Um script que confere se a versão em execução já está corrigida ajuda muito em pipeline de deploy ou em um cron de auditoria:

<?php
// checa-php2shell.php - verifica se o PHP em execução já tem as correções de outubro de 2026
$corrigidas = [
    '8.5' => '8.5.12',
    '8.4' => '8.4.27',
    '8.3' => '8.3.36',
    '8.2' => '8.2.35',
];

$ramo = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;

if (!isset($corrigidas[$ramo])) {
    // 8.1 ou mais antigo: sem release oficial, só backport ou migração
    fwrite(STDERR, "PHP {$ramo} está fora de suporte. Migre ou use um backport do seu fornecedor.\n");
    exit(2);
}

if (version_compare(PHP_VERSION, $corrigidas[$ramo], '<')) {
    fwrite(STDERR, "VULNERÁVEL: PHP " . PHP_VERSION . " (precisa de {$corrigidas[$ramo]} ou superior)\n");
    exit(1);
}

echo "OK: PHP " . PHP_VERSION . " já inclui as correções do PHP2Shell\n";

Rode com php checa-php2shell.php em cada imagem ou servidor. O código de saída diferente de zero faz o pipeline falhar, que é exatamente o que você quer.

Atualizado o pacote, reinicie todos os workers. Um FPM que continua com processos antigos de pé segue rodando o binário vulnerável:

# Debian/Ubuntu com PHP-FPM 8.3 (ajuste o número do ramo)
sudo apt update && sudo apt install --only-upgrade php8.3-fpm php8.3-cli
sudo systemctl restart php8.3-fpm

# Apache com mod_php: o PHP vive dentro do processo do Apache
sudo systemctl restart apache2

# Containers: reconstrua a imagem a partir da base nova, não só reinicie
docker build --pull -t minha-app:php-corrigido .

Em container, o --pull importa: sem ele, o Docker pode reaproveitar a imagem base antiga do cache e você publica o mesmo PHP vulnerável com uma tag nova.

Passo 3: Mitigações Enquanto Você Não Atualiza

Às vezes não dá para atualizar hoje: hospedagem compartilhada, aplicação legada presa a uma versão, janela de manutenção marcada. O php.net lista mitigações, mas deixa claro que elas não tornam a instalação segura, só reduzem a superfície.

Para a CVE-2026-109619, desligue o progresso de upload por sessão no php.ini ou no pool do FPM:

; php.ini ou pool do FPM - mitigação temporária do PHP2Shell
; Fecha o vetor conhecido da CVE-2026-109619 (quebra barras de progresso de upload)
session.upload_progress.enabled = 0

; Apenas no PHP 8.5: desliga os backtraces em erro fatal
; fatal_error_backtraces = 0

; Mitigação da CVE-2026-109618: limite o tamanho dos POSTs
; 8M se a aplicação não recebe upload, 32M se recebe
post_max_size = 8M
upload_max_filesize = 6M

Detalhes que derrubam quem faz com pressa:

  • Não confie em ini_set() nem no .user.ini do FPM para isso. A configuração precisa estar no php.ini, no pool ou na configuração do servidor.
  • Reinicie todos os workers depois de mudar.
  • O php.net também cita memory_limit=-1 (preferencialmente via php_admin_value) como mitigação da CVE-2026-109618 e pede para não usar RLIMIT_AS nem RLIMIT_DATA. Avalie com cuidado: sem limite de memória, um script com vazamento pode derrubar a máquina inteira.

Tem mais um motivo para desligar o session.upload_progress mesmo depois de atualizar. Em 23 de outubro de 2026, o PHP publicou um aviso informativo sobre um terceiro problema, a CVE-2026-115560, que não é corrigido pelos releases do dia 21. Ele só atinge aplicações que configuram session.serialize_handler como php_binary ou php_serialize e trocam para php em tempo de execução com ini_set() antes do session_start(). É um cenário raro, e a correção vem no próximo release regular. A recomendação oficial é manter session.upload_progress.enabled=0 até lá.

Passo 4: Bloqueie o Que Você Não Usa na Borda

Se a sua aplicação não recebe formulário multipart/form-data em determinadas rotas, não existe motivo para aceitar esse tipo de corpo nelas. Bloquear na borda (Nginx, WAF ou CDN) corta o vetor antes de a requisição chegar no PHP. Um exemplo em Nginx para uma API que só fala JSON:

# Nginx - recusa multipart em rotas que só deveriam receber JSON
location /api/ {
    # Limita o tamanho do corpo para atrapalhar nomes de campo gigantes
    client_max_body_size 1m;

    if ($content_type ~* "multipart/form-data") {
        return 415;
    }

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

Já existem regras de WAF públicas para ModSecurity e Suricata. A recomendação da Abstract Security é ativar em modo de log primeiro, conferir os falsos positivos e só depois passar para bloqueio. Regra de WAF mal calibrada derruba checkout de e-commerce em sexta-feira à noite.

Outro ponto: qualquer achado antigo de local file inclusion do tipo include($_GET['pagina']) que estava no backlog como "médio" deve voltar para a fila como crítico. Boa parte das provas de conceito que circularam depende justamente de um LFI para virar RCE.

Passo 5: Procure Sinais de Que Alguém Já Tentou

Os detalhes vazaram no dia 20 de outubro, e equipes de segurança relataram tentativas de ataque já no dia 21. A janela de investigação deve começar no dia 20, não no dia em que você atualizou. Alguns sinais que a Abstract Security aponta como característicos:

  • Erros fatais do PHP terminando em in Unknown on line 0 nos logs do servidor web.
  • POSTs de 1 MB ou mais para endpoints PHP, principalmente rajadas de 10 ou mais vindas do mesmo IP em 10 minutos.
  • No Apache, centenas de POSTs grandes do mesmo IP gerando entradas AH00052, seguidas de uma resposta lenta, o que sugere força bruta contra o ASLR.
  • Processos sh -c filhos do Apache, do Nginx ou dos workers PHP, rodando id, curl ou nc.

Um primeiro passe rápido nos logs:

# 1. Assinatura do exploit nos logs de erro (desde 20/10/2026)
sudo grep -h "in Unknown on line 0" /var/log/apache2/error.log* /var/log/php*-fpm.log 2>/dev/null | tail -n 50

# 2. Crashes de processo filho do Apache, agrupados por dia
sudo zgrep -h "AH00052" /var/log/apache2/error.log* | awk '{print $2, $3, $5}' | sort | uniq -c

# 3. IPs com mais POSTs no access log (formato combined)
sudo awk '$6 == "\"POST" {print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -n 20

# 4. Arquivos novos em diretórios temporários e na raiz web desde 20/10
sudo find /tmp /dev/shm /var/www -newermt "2026-10-20" -type f -name "*.php" 2>/dev/null

Achou algo? Confira também chaves novas em authorized_keys, cron jobs que ninguém criou e conexões de saída inesperadas. Se houver sinal concreto de comprometimento, tratar como incidente (isolar, preservar evidência, rotacionar credenciais) é mais seguro do que só atualizar e seguir a vida.

O Que Esse Caso Ensina Sobre Segurança em 2026

Quem acompanhou o React2Shell, a vulnerabilidade crítica nos React Server Components, reconhece o padrão: uma falha no próprio runtime ou framework, que nenhuma revisão de código da sua aplicação teria pego, e uma corrida entre o patch e o primeiro exploit funcional.

Três lições práticas:

  1. Inventário de versões é segurança. O primeiro passo de todo incidente desse tipo é responder "onde roda o quê". Se isso leva um dia, você já perdeu o dia mais importante.
  2. Embargo não é garantia. Desta vez o vazamento antecipou o release em quase um dia. Tenha um processo de atualização que rode em horas, não em semanas.
  3. IA mudou o volume dos dois lados. O mesmo tipo de ferramenta que ajudou a achar essas falhas também gera relatórios falsos (o time do PHP descartou mais de 100) e acelera quem procura brechas.

Vale uma ressalva honesta: o pesquisador Elias Taylor argumentou que muitas provas de conceito que circularam no dia do anúncio eram falsas ou só funcionavam em laboratório com um componente vulnerável adicionado. Isso não muda a conclusão dele mesmo: atualize de qualquer forma.

Perspectivas: O Que Vem Por Aí no PHP

O PHP 8.6.0 já está no RC4, e a PHP Foundation reforçou o time com Volker Dusch como engenheiro de segurança de IA residente e Daniel Scherzer focado em hardening, além de builds com sanitizers em todas as plataformas suportadas. A fundação também pediu que empresas, hospedagens, distribuições e governos que dependem do PHP financiem o trabalho na medida dessa dependência. O trabalho em tempo integral que corrigiu o bug de memória foi pago por patrocínio.

Para quem cuida de servidor, a agenda dos próximos dias é curta: atualizar para 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, reiniciar os workers, manter session.upload_progress.enabled=0 até o próximo release regular e revisar os logs desde 20 de outubro. E, se você ainda está no 8.2, já marque a migração no calendário: o fim de vida é em 31 de dezembro de 2026.

Bora pra cima! 🦅

📚 Quer Acompanhar o Que Vem Por Aí?

Este artigo cobriu o PHP2Shell e como proteger servidores PHP das falhas CVE-2026-109618 e CVE-2026-109619, mas o ecossistema muda toda semana e nem tudo vira artigo aqui.

No X eu compartilho o que estou testando, os bastidores dos projetos e as novidades que aparecem antes de virarem post.

Me Segue Lá

👉 Seguir @jeffbruchado no X

💡 Conteúdo diário sobre desenvolvimento, carreira e as ferramentas que eu realmente uso

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário