Bypass de ASLR Sem Info Leak: Matriz de Hardening de Distribuições e Exploração de fork
Bypass de ASLR Sem Info Leak: Matriz de Hardening de Distribuições e Exploração de fork
Verificado em 23 de outubro de 2026.
<time datetime="2026-10-23">Verificado em 23 de outubro de 2026</time>
Address Space Layout Randomization (ASLR) é uma das mitigações genéricas mais eficazes contra corrupção de memória. Ainda assim, análises do CVE-2026-109619 mostram que variantes do PHP2Shell dispensam vazamento interativo de informação. A razão não é um ASLR quebrado, mas a combinação de uso previsível do espaço de endereços, herança via fork() e a possibilidade de repetir tentativas falhas a baixo custo. Este artigo descreve os mecanismos e o que as distribuições realmente fazem a respeito.
1. Física do hijack sem leak
1.1 Offsets de página permanecem constantes
Em Linux 64-bit, endereços de usuário são limitados a cerca de 47 bits. O ASLR randomiza os bits superiores, mas os 12 bits inferiores (offset de página) permanecem inalterados. Um atacante que visa um objeto de estrutura conhecida pode prever parte do endereço e acertar o resto por repetição.
1.2 PIE ausente ou parcial
Alguns pacotes compilam php-fpm sem PIE completo, ou apenas o programa principal é PIE enquanto extensões são carregadas em endereços fixos. Então funções internas são endereçáveis sem necessidade de leak.
Verificação:
checksec --file=/usr/sbin/php-fpm8.3
readelf -h /usr/sbin/php-fpm8.3 | grep Type
readelf -lW /usr/sbin/php-fpm8.3 | grep GNU_RELRO
Type: EXEC significa sem PIE; Type: DYN significa PIE. O resultado varia por distribuição, compilador e flags de build. Não assuma; meça na imagem realmente usada.
1.3 Herança de fork()
O master FPM inicia seus workers via fork(). Filhos herdam o espaço de endereço do pai; assim, todos os workers compartilham as mesmas bases de bibliotecas. Um acerto de endereço bem-sucedido em um worker vale para todo o pool.
ps -eo pid,ppid,user,cmd | grep -E 'php-fpm' | head -20
Essa arquitetura é performática, mas reduz a entropia efetiva do ASLR a um único momento de inicialização do master. Quem mantém o master rodando por muito tempo amplia a janela de ataque.
2. Matriz por distribuição
Tabela comparativa de PIE, RELRO, canary, libc e nível de mitigação para Ubuntu 22.04/24.04, Debian 12, RHEL 9/Rocky 9, Alpine 3.20 e imagens de container.
O decisivo não é a versão do PHP sozinha, mas se o pacote da distribuição contém a correção da CVE. Um pacote pode carregar versão upstream mais antiga e ainda assim estar patcheado.
Verificação de backport:
apt changelog php8.1-fpm | grep -i 'CVE-2026-10961'
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.1-fpm/changelog.Debian.gz
rpm -q --changelog php-fpm | grep -i 'CVE-2026-10961'
docker run --rm php:8.3-fpm php -v
3. Exploração do modelo master-worker
Um atacante pode usar a herança de fork em três passos:
-
Aprender o layout: uma requisição inofensiva produz mensagem de erro ou padrão de timing que permite inferir bases.
-
Repetir falhas: um crash termina apenas o worker. O master inicia um novo imediatamente, herdando a mesma base de layout.
-
Acumular probabilidade: com centenas de requisições por segundo, a chance de acerto cresce rapidamente.
journalctl -u php8.3-fpm --since "30 min ago" | grep -E 'WARNING|seems busy|SIGSEGV|SIGABRT|terminated'
4. Contramedidas
4.1 Throttling de crashes no FPM
emergency_restart_threshold = 5
emergency_restart_interval = 1m
process_control_timeout = 10s
pm.max_requests = 300
Se o número de términos de worker exceder o limiar, o FPM para o reinício automático e exige intervenção. É um compromisso consciente entre disponibilidade e segurança.
4.2 Status do ASLR e hardening do serviço
cat /proc/sys/kernel/randomize_va_space
sudo systemctl edit php8.3-fpm
Configurar LimitCORE=0, NoNewPrivileges=yes, ProtectSystem=strict, PrivateTmp=yes. LimitCORE=0 evita que core dumps exponham informações de endereço e conteúdo de memória. Para forense pode ser contraproducente; em ambientes de alta segurança a decisão deve ser consciente e documentada.
4.3 Verificar hardening binário
Script bash com checksec/readelf para ELF type, RELRO, BIND_NOW e canary. Execute na CI e falhe se faltarem características de hardening. Assim evita-se que uma nova imagem base seja silenciosamente mais fraca que a anterior.
5. Canais laterais de timing e layouts de container
Além de leaks clássicos, existem canais mais sutis. Um atacante pode medir o tempo de resposta de uma requisição para saber se um endereço chutado era válido. Um acerto frequentemente leva a um caminho mais longo, pois a VM chama mais handlers antes de crashar. A diferença fica na faixa de microssegundos a milissegundos e é difícil de medir de forma confiável via rede — mas em ambientes de baixa latência e com muitas repetições, é utilizável. Para defensores: tempos de resposta uniformes e throttling de crashes consistentes dificultam a avaliação.
Containers agravam o problema de outra forma. A imagem base determina libc, loader e build do PHP. Muitas equipes usam a mesma imagem por meses sem atualizar a versão do PHP contida. Um docker pull atualiza apenas a tag, não a instância em execução, e uma tag latest não é versão. Verifique no container em execução:
docker exec <container> php -v
docker exec <container> php -r 'echo PHP_BINARY, PHP_EOL;'
docker exec <container> ldd "$(docker exec <container> which php)" | head
Kubernetes adiciona escala horizontal: muitos pods efêmeros com imagem idêntica não compartilham o mesmo espaço de endereço, mas compartilham os mesmos offsets. Um atacante que conhece a versão da imagem cria sua tabela uma vez e a usa contra todas as réplicas. Por isso, pinning de digest de imagem não é apenas questão de reprodutibilidade, mas também de custo de ataque.
Um último aspecto é o papel de JIT e OPcache. Ambos alteram a dinâmica do layout de memória, mas não removem os problemas fundamentais. Quem ativa opcache.jit deve planejar a complexidade adicional na depuração; quem desativa ganha alguma previsibilidade, mas perde performance. A decisão pertence a um conceito de hardening documentado, não a uma mudança emergencial espontânea.
6. Limites da análise
ASLR é uma mitigação probabilística, não uma garantia. Ela aumenta o custo de um ataque, mas não o impede. Em um ataque que permite centenas de tentativas por segundo e cujas falhas custam apenas um worker, a probabilidade de acerto em poucos minutos é alta. Por isso a medida decisiva continua sendo o patch para 8.5.12, 8.4.27, 8.3.36 ou 8.2.35 — e até lá a desativação do callback RFC1867.
7. Conclusão
- Offsets de página e herança de fork reduzem a entropia efetiva.
- PIE ausente ou imagens base de container desatualizadas agravam o problema.
- emergency_restart_threshold, pm.max_requests e LimitCORE=0 dificultam brute-force.
- Hardening binário deve ser parte da CI e do build de imagem, não apenas uma verificação única.
Quem trata ASLR como defesa única superestima-a. Quem a combina com gerenciamento de patches, hardening da engine e detecção em runtime ganha tempo e reduz significativamente a probabilidade de sucesso.
8. Exercício de hardening e validação contínua
Para tornar o hardening efetivo, execute periodicamente um exercício que simula as condições de ataque: worker de longa duração, heap fragmentado e requisições repetidas. Meça o tempo até o primeiro crash e a taxa de sucesso de tentativas de endereço. Se o tempo for curto, reduza pm.max_requests e aumente emergency_restart_threshold. Se a taxa de sucesso for alta, investigue PIE, RELRO e base image. Documente resultados e compare ao longo do tempo. Um hardening que não é medido degrada silenciosamente com atualizações de pacotes e mudanças de imagem base. Inclua a verificação de hardening binário em todo pipeline de CI/CD e bloqueie deploys que não atendam aos critérios mínimos. Também mantenha um inventário de imagens base com suas versões de libc e PHP, e revalide após cada atualização. A combinação de medição, automação e inventário é o que transforma ASLR de esperança estatística em controle gerenciável.