hacktricks/pentesting-web/file-inclusion/lfi2rce-via-eternal-waiting.md

94 lines
6.7 KiB
Markdown
Raw Normal View History

2023-06-06 18:56:34 +00:00
## Informação Básica
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
Por padrão, quando um arquivo é enviado para o PHP (mesmo que não seja esperado), 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 em que os arquivos gerados não contêm dígitos.
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
Em uma inclusão de arquivo local, **se você conseguir incluir esse arquivo enviado, obterá RCE**.
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
Observe que, por padrão, **o PHP permite apenas o upload de 20 arquivos em uma única solicitação** (definido em `/etc/php/<versão>/apache2/php.ini`):
2022-12-18 23:00:42 +00:00
```
; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20
```
2023-06-06 18:56:34 +00:00
Também, o **número de possíveis nomes de arquivos são 62\*62\*62\*62\*62\*62 = 56800235584**
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
### Outras técnicas
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
Outras técnicas dependem de atacar protocolos PHP (você não será capaz se apenas controlar 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 arquivos temporários enviados não sejam excluídos**.\
Esta técnica é **muito semelhante à última, mas sem precisar encontrar uma vulnerabilidade zero day**.
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
### Técnica de espera eterna
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
Nesta técnica, **só precisamos controlar um caminho relativo**. Se conseguirmos enviar arquivos e fazer com que o **LFI nunca termine**, teremos "tempo suficiente" para **forçar a força bruta dos arquivos enviados** e **encontrar** qualquer um dos arquivos enviados.
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
**Prós desta técnica**:
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
* Você só precisa controlar um caminho relativo dentro de um include
* Não requer nginx ou 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
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
Os **principais problemas** desta técnica são:
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
* Precisa de um arquivo(s) específico(s) para estar presente (pode haver mais)
* A **quantidade insana** de possíveis nomes de arquivos: **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 usado.
* Este limite com os anteriores pode fazer com que este ataque dure muito tempo
* **Tempo limite para uma solicitação PHP**. Idealmente, isso deveria ser eterno ou deveria matar o processo PHP sem excluir os arquivos temporários enviados, caso contrário, isso também será um problema
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
Então, como você pode **fazer um include PHP nunca terminar**? Apenas incluindo o arquivo **`/sys/kernel/security/apparmor/revision`** (**infelizmente não disponível em contêineres Docker**).
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
Tente chamá-lo apenas com:
2022-12-19 15:21:53 +00:00
```bash
php -a # open php cli
include("/sys/kernel/security/apparmor/revision");
```
2022-12-18 23:00:42 +00:00
## Apache2
2023-06-06 18:56:34 +00:00
Por padrão, o Apache suporta **150 conexões simultâneas**, seguindo [https://ubiq.co/tech-blog/increase-max-connections-apache/](https://ubiq.co/tech-blog/increase-max-connections-apache/) é possível aumentar esse número para até 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](https://www.digitalocean.com/community/tutorials/how-to-configure-apache-http-with-mpm-event-and-php-fpm-on-ubuntu-18-04).
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
Por padrão, (como posso ver em meus testes), um **processo PHP pode durar eternamente**.
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
Vamos fazer alguns cálculos:
2022-12-18 23:00:42 +00:00
2023-06-06 18:56:34 +00:00
* Podemos usar **149 conexões** para gerar **149 \* 20 = 2980 arquivos temporários** com nossa webshell.
* Em seguida, use 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)
2022-12-18 23:00:42 +00:00
{% hint style="warning" %}
2023-06-06 18:56:34 +00:00
Observe que no exemplo anterior estamos **completamente DoSando outros clientes**!
2022-12-18 23:00:42 +00:00
{% endhint %}
2023-06-06 18:56:34 +00:00
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).
2022-12-18 23:00:42 +00:00
2022-12-19 15:21:53 +00:00
## PHP-FMP
2023-06-06 18:56:34 +00:00
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.
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
O PHP-FMP permite **configurar** o **parâmetro** **`request_terminate_timeout`** em **`/etc/php/<php-version>/fpm/pool.d/www.conf`**.\
Este parâmetro indica o tempo máximo em segundos **quando** **a solicitação ao PHP deve ser encerrada** (infinito por padrão, mas **30s se o parâmetro não estiver comentado**). Quando uma solicitação está sendo processada pelo PHP pelo número de segundos indicado, ela é **encerrada**. Isso significa que, se a solicitação estivesse 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, poderá **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 consumindo todas as conexões.
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
Portanto, para **evitar DoS**, vamos supor que um **atacante usará apenas 100 conexões** ao mesmo tempo e o tempo máximo de processamento do php pelo **php-fmp** (`request_terminate_timeout`**)** é de **30s**. Portanto, o número de **arquivos temporários** que podem ser gerados **por segundo** é `100*20/30 = 66,67`.
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
Então, para gerar **10000 arquivos**, um atacante precisaria de: **`10000/66.67 = 150s`** (para gerar **100000 arquivos** o tempo seria de **25min**).
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
Em seguida, o atacante poderia usar essas **100 conexões** para realizar uma **busca por força bruta**. Supondo uma velocidade de 300 req/s, o tempo necessário para explorar isso é o seguinte:
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
* 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)
2022-12-19 15:21:53 +00:00
2023-06-06 18:56:34 +00:00
Sim, é possível gerar 100000 arquivos temporários em uma instância de tamanho médio do EC2:
2022-12-19 16:08:19 +00:00
<figure><img src="../../.gitbook/assets/image (3) (1) (1) (3).png" alt=""><figcaption></figcaption></figure>
2022-12-19 16:08:19 +00:00
{% hint style="warning" %}
2023-06-06 18:56:34 +00:00
Observe que para acionar o tempo limite, seria **suficiente incluir a página LFI vulnerável**, para que ela entre em um loop de inclusão eterna.
{% endhint %}
2022-12-18 23:00:42 +00:00
## Nginx
2023-06-06 18:56:34 +00:00
Parece que por padrão o Nginx suporta **512 conexões paralelas** ao mesmo tempo (e esse número pode ser melhorado).