PHP Tricks
Çerezlerin yaygın konumu:
Bu aynı zamanda phpMyAdmin çerezleri için de geçerlidir.
Çerezler:
Konumlar:
PHP Karşılaştırmalarını Atlatma
Gevşek karşılaştırmalar/Tür Dönüşümü ( == )
Eğer PHP'de ==
kullanılıyorsa, beklenmeyen durumlar olabilir ve karşılaştırma beklenildiği gibi davranmayabilir. Bu, "==" sadece aynı türe dönüştürülen değerleri karşılaştırır, eğer karşılaştırılan verinin türünün de aynı olduğunu karşılaştırmak istiyorsanız ===
kullanmanız gerekir.
PHP karşılaştırma tabloları: https://www.php.net/manual/en/types.comparisons.php
"string" == 0 -> True
Bir sayı ile başlamayan bir dize, bir sayıya eşittir"0xAAAA" == "43690" -> True
Onaltılık veya ondalık formatındaki sayılardan oluşan dizeler, diğer sayılar/dizilerle karşılaştırılabilir ve sayılar aynıysa sonuç True olur (bir dizideki sayılar sayı olarak yorumlanır)"0e3264578" == 0 --> True
"0e" ile başlayan ve herhangi bir şeyi takip eden bir dize, 0'a eşit olacaktır"0X3264578" == 0X --> True
"0" ile başlayan ve herhangi bir harfi takip eden (X herhangi bir harf olabilir) ve herhangi bir şeyi takip eden bir dize, 0'a eşit olacaktır"0e12334" == "0" --> True
Bu çok ilginç çünkü bazı durumlarda "0" ile başlayan ve karşılaştırılan veri türüne eşit olan bazı içeriklerin dizgesini kontrol edebilirsiniz. Bu nedenle, "0e" ile başlayan ve herhangi bir harf içermeyen bir karmayı oluşturacak bir değer sağlayabilirseniz, karşılaştırmayı atlayabilirsiniz. Bu formatta zaten karmalanmış dizgeleri burada bulabilirsiniz: https://github.com/spaze/hashes"X" == 0 --> True
Bir dizgedeki herhangi bir harf, int 0'a eşittir
Daha fazla bilgi için https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09
in_array()
Tür Dönüşümü, varsayılan olarak in_array()
işlevini de etkiler (katı bir karşılaştırma yapmak için üçüncü argümanı true olarak ayarlamanız gerekir):
strcmp()/strcasecmp()
Eğer bu fonksiyon herhangi bir kimlik doğrulama kontrolü için kullanılıyorsa (örneğin şifre kontrolü) ve kullanıcı karşılaştırmanın bir tarafını kontrol ediyorsa, şifre değeri olarak bir dizi yerine boş bir dizi gönderebilir (https://ornek.com/giris.php/?kullaniciadi=admin&sifre[]=
) ve bu kontrolü atlayabilir:
Katı Tür Dönüşümü
strcasecmp()
ile aynı hata meydana gelir.
Katı tür dönüşümü
Eğer ===
kullanılıyorsa bile, karşılaştırmanın tür dönüşümüne karşı savunmasız olabileceği hatalar olabilir. Örneğin, karşılaştırma veriyi karşılaştırmadan önce farklı bir nesne türüne dönüştürüyorsa:
preg_match(/^.*/)
preg_match()
kullanıcı girişini doğrulamak için kullanılabilir (herhangi bir kelime/regex'in kara listesinde olup olmadığını kontrol eder ve eğer değilse, kod işlemini sürdürebilir).
Yeni satır atlatma
Ancak, regexp'in başlangıcını sınırlarken preg_match()
sadece kullanıcı girişinin ilk satırını kontrol eder, sonra eğer bir şekilde girişi birkaç satırda gönderebilirseniz, bu kontrolü atlayabilirsiniz. Örnek:
Bu kontrolü atlamak için değeri yeni satırlarla urlencoded (%0A
) gönderebilirsiniz veya JSON verisi gönderebiliyorsanız, bunu birkaç satırda gönderin:
Örnek bulun: https://ramadistra.dev/fbctf-2019-rceservice
Uzunluk hatası atlatma
(Bu atlatma, görünüşe göre PHP 5.2.5'te denenmiş ve PHP 7.3.15'te çalışamadı)
Eğer preg_match()
'e geçerli çok büyük bir giriş gönderebilirseniz, işleyemez ve kontrolü atlayabilirsiniz. Örneğin, eğer bir JSON'u karalistelediyse gönderebilirsiniz:
ReDoS Atlatma
Hile kaynağı: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 ve https://mizu.re/post/pong
Kısacası, sorun, PHP'deki preg_*
fonksiyonlarının PCRE kütüphanesi üzerine kurulması nedeniyle oluşur. PCRE'de belirli düzenli ifadeler, çok sayıda özyineli çağrı kullanılarak eşleştirilir ve bu da çok miktarda yığın alanı tüketir. Özyineli çağrıların miktarına izin verilen bir sınır belirlenebilir, ancak PHP'de bu sınır varsayılan olarak 100.000'dir ve yığın alanına sığmaktan daha fazladır.
Bu sorun hakkında daha detaylı konuşulan yazıda Bu Stackoverflow konu başlığı da paylaşılmıştır. Görevimiz şimdi açıktı:
Regex'in 100.000'den fazla özyineli çağrı yapmasını sağlayacak bir giriş göndermek, SIGSEGV'ye neden olacak ve preg_match()
fonksiyonunun false
döndürmesini sağlayacak, böylece uygulamanın girişimizin kötü niyetli olmadığını düşünmesini sağlayacak ve payload'ın sonunda {system(<çokkötükod>)}
gibi bir sürpriz atarak SSTI --> RCE --> bayrak :).
Evet, regex terimleri açısından, aslında 100k "özyineli çağrı" yapmıyoruz, ancak "geri izleme adımlarını" sayıyoruz, ki bu da PHP belgelerinde belirtildiği gibi pcre.backtrack_limit
değişkeninde varsayılan olarak 1.000.000 (1M) olur.
Buna ulaşmak için, 'X'*500_001
ifadesi 1 milyon geri izleme adımına (500k ileri ve 500k geri) yol açacaktır:
PHP obfuscation için Tür Tipi Dönüşümü
Yönlendirmeden Sonra Yürüt (EAR)
Eğer PHP başka bir sayfaya yönlendiriyorsa ancak die
veya exit
fonksiyonu Location
başlığı ayarlandıktan sonra çağrılmamışsa, PHP yürütmeye devam eder ve verileri gövdeye ekler:
Yol Traversal ve Dosya Dahil Etme Sömürüsü
Kontrol et:
pageFile Inclusion/Path traversalDaha fazla hile
register_globals: PHP < 4.1.1.1 sürümlerinde veya yanlış yapılandırılmışsa, register_globals etkin olabilir (veya davranışları taklit ediliyor olabilir). Bu, global değişkenlerde $_GET gibi bir değer varsa örneğin $_GET["param"]="1234", bu değere $param üzerinden erişebilirsiniz. Bu nedenle, HTTP parametreleri göndererek kod içinde kullanılan değişkenleri üzerine yazabilirsiniz.
Aynı alanın PHPSESSION çerezleri aynı yerde saklanır, bu nedenle bir alan içinde farklı yollarda farklı çerezler kullanılıyorsa bir yolun diğer yolun çerezine erişmesini sağlayabilirsiniz. Böylece her iki yol da aynı isimde bir değişkene erişirse, o değişkenin değerini yol1'e uygulayabilirsiniz. Sonra yol2, yol1'in değişkenlerini geçerli kabul eder (çerezin adını yol2'de karşılık gelen adı vererek).
Makinenin kullanıcılarının kullanıcı adlarını elde ettiğinizde, php dizinlerinin etkin olup olmadığını kontrol etmek için /~<KULLANICIADİ> adresini kontrol edin.
password_hash/password_verify
Bu fonksiyonlar genellikle PHP'de şifrelerden hash'ler oluşturmak ve bir şifrenin bir hash ile karşılaştırıldığında doğru olup olmadığını kontrol etmek için kullanılır. Desteklenen algoritmalar: PASSWORD_DEFAULT
ve PASSWORD_BCRYPT
(başlangıcı $2y$
). PASSWORD_DEFAULT'ın genellikle PASSWORD_BCRYPT ile aynı olduğunu unutmayın. Ve şu anda, PASSWORD_BCRYPT'ın 72 bayt giriş boyutunda bir sınırlaması vardır. Bu nedenle, bu algoritmayla 72 bayttan büyük bir şeyi hashlemeye çalıştığınızda sadece ilk 72B kullanılacaktır:
HTTP başlıkları atlayarak PHP hatalarını istismar etme
Eğer bir PHP sayfası hataları yazdırıyor ve kullanıcı tarafından sağlanan bazı girdileri geri döndürüyorsa, kullanıcı PHP sunucusunun geri bazı içerikleri yeterince uzun yazdırmasını sağlayabilir, böylece yanıt içine başlıkları eklemeye çalıştığında sunucu hata verecektir. Aşağıdaki senaryoda saldırgan sunucunun büyük hatalar vermesini sağladı, ve ekran görüntüsünde görebileceğiniz gibi PHP başlık bilgilerini değiştirmeye çalıştığında (örneğin CSP başlığı kullanıcıya gönderilmedi):
Kod yürütme
system("ls"); `ls`; shell_exec("ls");
Daha fazla faydalı PHP fonksiyonu için buraya bakın
preg_replace() aracılığıyla RCE
"replace" argümanındaki kodu yürütmek için en az bir eşleşme gereklidir. Bu preg_replace seçeneği PHP 5.5.0'dan itibaren kullanımdan kaldırılmıştır.
Eval() Aracılığıyla Uzaktan Kod Çalıştırma (RCE)
Assert() ile RCE
Bu php içindeki fonksiyon, bir dize içinde yazılmış kodu çalıştırmanıza olanak tanır ve buna bağlı olarak true veya false döndürür (ve buna bağlı olarak yürütümü değiştirir). Genellikle kullanıcı değişkeni bir dizenin ortasına yerleştirilir. Örneğin:
assert("strpos($_GET['page']),'..') === false")
--> Bu durumda RCE elde etmek için şunu yapabilirsiniz:
RCE via usort()
Bu fonksiyon, belirli bir işlevi kullanarak öğelerin bir dizisini sıralamak için kullanılır. Bu işlevi kötüye kullanmak için:
Kapanış parantezlerini kaç tane kapatmanız gerektiğini keşfetmek için:
?order=id;}//
: Bir hata mesajı alırız (Parse error: syntax error, unexpected ';'
). Muhtemelen bir veya daha fazla parantezi eksik yapmışızdır.?order=id);}//
: Bir uyarı alırız. Bu doğru gibi görünüyor.?order=id));}//
: Bir hata mesajı alırız (Parse error: syntax error, unexpected ')' i
). Muhtemelen fazla kapanış parantezimiz var.
.httaccess Üzerinden RCE
Eğer bir .htaccess dosyası yükleyebilirseniz, birçok şeyi yapılandırabilir ve hatta kodu çalıştırabilirsiniz (bu dosyaların uzantısını çalıştırılabilir olarak yapılandırabilirsiniz).
Farklı .htaccess kabuklarına buradan ulaşabilirsiniz.
Env Değişkenleri Üzerinden RCE
Eğer PHP'de env değişkenlerini değiştirmenize izin veren bir zayıflık bulursanız (ve başka bir dosya yükleme zayıflığı da bulursanız, daha fazla araştırma ile bunun atlatılabileceği belki), bu davranışı RCE elde etmek için kötüye kullanabilirsiniz.
LD_PRELOAD
: Bu env değişkeni, diğer ikili dosyaları çalıştırırken keyfi kütüphaneleri yüklemenize izin verir (ancak bu durumda işe yaramayabilir).PHPRC
: PHP'ye yapılandırma dosyasını nerede bulacağını söyler, genelliklephp.ini
olarak adlandırılır. Kendi yapılandırma dosyanızı yükleyebiliyorsanız, o zaman, PHP'yi bu dosyaya yönlendirmek içinPHPRC
'yi kullanın. İkinci yüklenen bir dosyayı belirten birauto_prepend_file
girişi ekleyin. Bu ikinci dosya, normal PHP kodunu içerir ve ardından PHP çalışma zamanı tarafından diğer tüm kodlardan önce yürütülür.
Kabuk kodumuzu içeren bir PHP dosyası yükleyin
İkinci bir dosya yükleyin, adım 1'de yüklediğimiz dosyayı yürütmek için PHP ön işleyicisine talimat veren bir
auto_prepend_file
yönergesi içerirPHPRC
değişkenini adım 2'de yüklediğimiz dosyaya ayarlayın.
Bu zinciri nasıl yürüteceğinizle ilgili daha fazla bilgiyi orijinal rapordan edinin.
PHPRC - başka bir seçenek
Eğer dosya yükleyemiyorsanız, FreeBSD'de "dosya"
/dev/fd/0
'ı kullanabilirsiniz, bustdin
içeren birstdin
'e gönderilen isteğin gövdesi:curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
Veya RCE elde etmek için
allow_url_include
'ı etkinleştirin ve base64 PHP kodu içeren bir dosyayı öne ekleyin:curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary $'allow_url_include=1\nauto_prepend_file="data://text/plain;base64,PD8KICAgcGhwaW5mbygpOwo/Pg=="'
Teknik bu rapordan alınmıştır.
PHP Statik analiz
Bu fonksiyonlara çağrılarda kod ekleyip ekleyemediğinizi kontrol edin (buradan):
Eğer bir PHP uygulamasını hata ayıklıyorsanız, display_errors = On
ekleyerek /etc/php5/apache2/php.ini
dosyasında hata yazdırmayı global olarak etkinleştirebilir ve apache'yi yeniden başlatabilirsiniz: sudo systemctl restart apache2
PHP Kodunu Deobfuscating
PHP kodunu deobfuscate etmek için web www.unphp.net kullanabilirsiniz.
PHP Wrappers & Protocols
PHP Wrappers ve protokoller, bir sistemin yazma ve okuma korumalarını atlaymanıza ve onu tehlikeye atmanıza olanak tanıyabilir. Daha fazla bilgi için bu sayfaya bakın.
Xdebug kimlik doğrulamasız RCE
Eğer bir phpconfig()
çıktısında Xdebug'in etkin olduğunu görürseniz, RCE elde etmeyi denemelisiniz: https://github.com/nqxcode/xdebug-exploit
Değişken değişkenler
Yeni $_GET["a"]($_GET["b"]) kötüye kullanarak RCE
Eğer bir sayfada keyfi bir sınıfın yeni bir nesnesini oluşturabiliyorsanız, RCE elde edebilirsiniz, nasıl yapılacağını öğrenmek için aşağıdaki sayfayı kontrol edin:
pagePHP - RCE abusing object creation: new $_GET["a"]($_GET["b"])Harfler olmadan PHP çalıştırma
https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
Sekizliği kullanarak
XOR
XOR (Mantıksal Bağlaç) iki bit dizisini karşılaştırır ve aynı olmayan bitleri 1 olarak ayarlar.
XOR basit kabuk kodu
Bu yazıda belirtildiğine göre, aşağıdaki şekilde basit bir kabuk kodu oluşturmak mümkündür:
Yani, eğer sayı ve harf olmadan keyfi PHP kodu çalıştırabiliyorsanız, aşağıdaki gibi bir istek gönderebilir ve keyfi PHP kodunu çalıştırmak için bu yükü istismar edebilirsiniz:
Daha detaylı bir açıklama için https://ctf-wiki.org/web/php/php/#preg_match
XOR Shellcode (eval içinde)
Perl gibi
Last updated