7.8 KiB
LFI2RCE via Espera Eterna
Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
Outras maneiras de apoiar o HackTricks:
- Se você deseja ver sua empresa anunciada no HackTricks ou baixar o HackTricks em PDF Verifique os PLANOS DE ASSINATURA!
- Adquira o swag oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-nos no Twitter 🐦 @carlospolopm.
- Compartilhe seus truques de hacking enviando PRs para os HackTricks e HackTricks Cloud repositórios do github.
Informação Básica
Por padrão, quando um arquivo é enviado para o PHP (mesmo que não esteja esperando), ele irá gerar um arquivo temporário em /tmp
com um nome como php[a-zA-Z0-9]{6}
, embora eu tenha visto algumas imagens do docker onde os arquivos gerados não contêm dígitos.
Em uma inclusão de arquivo local, se você conseguir incluir esse arquivo enviado, obterá RCE.
Observe que por padrão o PHP permite apenas o envio de 20 arquivos em uma única solicitação (definido em /etc/php/<versão>/apache2/php.ini
):
; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20
Também, o número de nomes de arquivo potenciais são 62*62*62*62*62*62 = 56800235584
Outras técnicas
Outras técnicas dependem de atacar os protocolos PHP (você não será capaz se controlar apenas a última parte do caminho), revelar o caminho do arquivo, abusar de arquivos esperados, ou fazer o PHP sofrer uma falha de segmentação para que os arquivos temporários enviados não sejam excluídos.
Essa técnica é muito semelhante à última, mas sem a necessidade de encontrar uma vulnerabilidade zero day.
Técnica de espera eterna
Nesta técnica só precisamos controlar um caminho relativo. Se conseguirmos enviar arquivos e fazer o LFI nunca terminar, teremos "tempo suficiente" para forçar bruta os arquivos enviados e encontrar qualquer um dos arquivos enviados.
Prós desta técnica:
- Você só precisa controlar um caminho relativo dentro de um include
- Não requer nginx ou um nível inesperado de acesso aos arquivos de log
- Não requer uma vulnerabilidade zero day para causar uma falha de segmentação
- Não requer uma revelação de caminho
Os principais problemas desta técnica são:
- Necessidade de um arquivo(s) específico(s) estar presente (pode haver mais)
- A quantidade insana de nomes de arquivo potenciais: 56800235584
- Se o servidor não estiver usando dígitos, o total potencial é: 19770609664
- Por padrão, apenas 20 arquivos podem ser enviados em uma única solicitação.
- O número máximo de trabalhadores paralelos do servidor utilizado.
- Esse limite junto com os anteriores pode fazer com que esse ataque dure muito tempo
- Tempo limite para uma solicitação PHP. Idealmente, isso deveria ser eterno ou deveria encerrar o processo PHP sem excluir os arquivos temporários enviados, caso contrário, isso também será um problema
Então, como você pode fazer um include PHP nunca terminar? Apenas incluindo o arquivo /sys/kernel/security/apparmor/revision
(não disponível em contêineres Docker infelizmente...).
Tente apenas chamando:
php -a # open php cli
include("/sys/kernel/security/apparmor/revision");
Apache2
Por padrão, o Apache suporta 150 conexões simultâneas, seguindo https://ubiq.co/tech-blog/increase-max-connections-apache/ é possível aumentar esse número para 8000. Siga este tutorial para usar o PHP com esse módulo: https://www.digitalocean.com/community/tutorials/how-to-configure-apache-http-with-mpm-event-and-php-fpm-on-ubuntu-18-04.
Por padrão, (como pude ver nos meus testes), um processo PHP pode durar eternamente.
Vamos fazer alguns cálculos:
- Podemos usar 149 conexões para gerar 149 * 20 = 2980 arquivos temporários com nossa webshell.
- Em seguida, usar a última conexão para forçar possíveis arquivos.
- A uma velocidade de 10 solicitações/s os tempos são:
- 56800235584 / 2980 / 10 / 3600 ~= 530 horas (50% de chance em 265h)
- (sem dígitos) 19770609664 / 2980 / 10 / 3600 ~= 185h (50% de chance em 93h)
{% hint style="warning" %} Note que no exemplo anterior estamos completamente DoSando outros clientes! {% endhint %}
Se o servidor Apache for melhorado e pudermos abusar de 4000 conexões (metade do caminho para o número máximo). Poderíamos criar 3999*20 = 79980
arquivos e o número seria reduzido para cerca de 19.7h ou 6.9h (10h, 3.5h 50% de chance).
PHP-FMP
Se em vez de usar o módulo php regular para o apache executar scripts PHP a página da web estiver usando PHP-FMP (isso melhora a eficiência da página da web, então é comum encontrá-lo), há algo mais que pode ser feito para melhorar a técnica.
O PHP-FMP permite configurar o parâmetro request_terminate_timeout
em /etc/php/<versão-php>/fpm/pool.d/www.conf
.
Este parâmetro indica a quantidade máxima de segundos quando a solicitação ao PHP deve ser encerrada (infinito por padrão, mas 30s se o parâmetro for descomentado). Quando uma solicitação está sendo processada pelo PHP pelo número indicado de segundos, ela é encerrada. Isso significa que se a solicitação estava enviando arquivos temporários, porque o processamento php foi interrompido, esses arquivos não serão excluídos. Portanto, se você puder fazer uma solicitação durar esse tempo, você pode gerar milhares de arquivos temporários que não serão excluídos, o que acelerará o processo de encontrá-los e reduzirá a probabilidade de um DoS na plataforma ao consumir todas as conexões.
Então, para evitar DoS vamos supor que um atacante estará usando apenas 100 conexões ao mesmo tempo e o tempo máximo de processamento do php pelo php-fmp (request_terminate_timeout
) é 30s. Portanto, o número de arquivos temporários que podem ser gerados por segundo é 100*20/30 = 66.67
.
Então, para gerar 10000 arquivos um atacante precisaria de: 10000/66.67 = 150s
(para gerar 100000 arquivos o tempo seria de 25min).
Então, o atacante poderia usar essas 100 conexões para realizar uma busca de força bruta. Supondo uma velocidade de 300 req/s, o tempo necessário para explorar isso é o seguinte:
- 56800235584 / 10000 / 300 / 3600 ~= 5.25 horas (50% de chance em 2.63h)
- (com 100000 arquivos) 56800235584 / 100000 / 300 / 3600 ~= 0.525 horas (50% de chance em 0.263h)
Sim, é possível gerar 100000 arquivos temporários em uma instância de tamanho médio do EC2:
{% hint style="warning" %} Note que para acionar o tempo limite seria suficiente incluir a página LFI vulnerável, para que entre em um loop de inclusão eterno. {% endhint %}
Nginx
Parece que por padrão o Nginx suporta 512 conexões paralelas ao mesmo tempo (e esse número pode ser melhorado).