Bypass de disable_functions - função dl

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

dl() permite ao PHP carregar uma extensão compartilhada em tempo de execução. Se você conseguir fazê-lo carregar um módulo controlado pelo atacante, você pode registrar uma nova função PHP que internamente chama execve, system, ou qualquer outro primitivo nativo e, portanto, contornar disable_functions.

Este é um primitivo real, mas em alvos modernos é muito menos comum do que escritos antigos sugerem.

Por que esse bypass é incomum hoje

Os principais bloqueios são:

  • dl() deve existir e não deve estar desabilitada
  • enable_dl ainda deve permitir carregamento dinâmico
  • A SAPI alvo deve suportar dl()
  • O payload deve ser uma extensão PHP válida compilada para o mesmo ABI alvo
  • A extensão deve ser acessível a partir do extension_dir configurado

O manual oficial do PHP é a verificação de realidade mais importante aqui: dl() está disponível apenas para as SAPIs CLI e embed, e para a SAPI CGI quando executada a partir da linha de comando. Isso significa que a técnica é geralmente não está disponível em requisições web normais PHP-FPM/mod_php, então verifique a SAPI antes de gastar tempo construindo um payload.

Observe também que enable_dl é uma configuração INI_SYSTEM e, desde PHP 8.3.0, o PHP documenta-a como deprecated, então normalmente você não pode alterá-la em tempo de execução a partir de código PHP controlado pelo atacante.

Se dl() não for viável, volte para a lista mais ampla de module/version dependent bypasses.

Triagem rápida a partir de um foothold

Antes de construir qualquer coisa, colete os parâmetros exatos que o módulo deve corresponder:

<?php
phpinfo();
echo "PHP_VERSION=" . PHP_VERSION . PHP_EOL;
echo "PHP_SAPI=" . php_sapi_name() . PHP_EOL;
echo "ZTS=" . (PHP_ZTS ? "yes" : "no") . PHP_EOL;
echo "INT_BITS=" . (PHP_INT_SIZE * 8) . PHP_EOL;
echo "enable_dl=" . ini_get("enable_dl") . PHP_EOL;
echo "extension_dir=" . ini_get("extension_dir") . PHP_EOL;
echo "disabled=" . ini_get("disable_functions") . PHP_EOL;
?>

O que importa:

  • PHP_SAPI: se isto for fpm-fcgi ou apache2handler, dl() geralmente é um beco sem saída para exploração web
  • extension_dir: o payload deve ser carregado a partir daqui
  • PHP Version, arquitetura, debug/non-debug, e ZTS/non-ZTS: seu módulo deve corresponder a eles
  • disable_functions: confirme se dl está ausente porque foi desabilitado ou porque a SAPI não o suporta

Restrições práticas de exploração

1. Normalmente é necessário acesso de escrita em extension_dir

Este é o maior gargalo.

dl() recebe o nome do arquivo da extensão, e o PHP o carrega a partir de extension_dir. Na prática, isso significa que um upload arbitrário normal para /var/www/html/uploads não é suficiente. Você ainda precisa de um caminho para colocar um .so/.dll onde o PHP realmente carregue extensões.

Situações realistas em que isso se torna explorável:

  • CTFs ou labs intencionalmente fracos onde extension_dir é gravável
  • Shared-hosting ou erros em containers que expõem um caminho de extensão gravável
  • Um mecanismo separado de escrita arbitrária de arquivos que já alcança extension_dir
  • Cenários de post-exploitation onde você já escalou privilégios o suficiente para colocar arquivos lá

2. O módulo deve corresponder ao build alvo

Corresponder apenas a PHP_VERSION não é suficiente. A extensão também precisa corresponder a:

  • OS e arquitetura da CPU
  • expectativas do libc/toolchain
  • ZEND_MODULE_API_NO
  • build com debug vs sem debug
  • ZTS vs NTS

Se esses itens não corresponderem, dl() falhará ou causará crash no processo.

3. open_basedir não é a principal defesa aqui

Uma vez que você pode colocar o módulo em extension_dir e chamar dl(), o código da extensão é executado dentro do processo PHP. Nesse ponto, a barreira relevante não era open_basedir, mas a capacidade de colocar um objeto compartilhado válido no caminho de carregamento de extensões.

Construindo a extensão maliciosa

A rota clássica ainda é válida:

  1. Recrie o build da vítima o mais fielmente possível
  2. Use phpize, ./configure e make para compilar uma extensão compartilhada
  3. Exporte uma função PHP como bypass_exec($cmd) que encapsula a execução nativa de comandos
  4. Envie o módulo compilado para extension_dir
  5. Carregue-o com dl() e chame a função exportada

O ataque é antigo, mas ainda relevante porque os changelogs do PHP 8.x continuam a incluir correções de crash específicas para dl(). A primitiva ainda existe; a parte difícil é encontrar uma implantação onde ela seja alcançável e onde você possa colocar um módulo compatível.

Fluxo de trabalho mínimo

Na máquina do atacante

mkdir bypass && cd bypass
phpize
./configure
make

O objeto compartilhado resultante geralmente ficará em modules/.

Se você estiver compilando em um ambiente diferente do alvo, trate o arquivo produzido como um rascunho até verificar que o ABI corresponde ao da vítima.

Carregando e usando a extensão

Se o alvo realmente suporta dl() e o módulo estiver dentro de extension_dir, a parte em tempo de execução é simples:

<?php
if (!extension_loaded('bypass')) {
dl('bypass.so'); // use the correct filename for the target platform
}
echo bypass_exec($_GET['cmd']);
?>

No Windows o nome do arquivo normalmente será um .dll, enquanto em alvos tipo Unix geralmente será um .so.

Notas do atacante

  • Não assuma que isso funciona remotamente apenas porque function_exists("dl") retorna true em alguma documentação ou writeup antigo; valide o SAPI em execução
  • Uma tentativa de dl() que falha pode matar o worker PHP se o módulo for incompatível
  • A partir do PHP 8, funções desabilitadas são removidas da tabela de funções, então a enumeração em userland pode diferir de posts antigos
  • Se você não pode escrever em extension_dir, esta técnica geralmente é menos prática do que FPM/FastCGI, LD_PRELOAD, ou bypasses específicos de módulos já cobertos nesta seção

Referências

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks