PHP Tricks
Last updated
Last updated
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)
Web uygulamalarınız, ağınız ve bulutunuz hakkında bir hacker perspektifi edinin
Gerçek iş etkisi olan kritik, istismar edilebilir güvenlik açıklarını bulun ve raporlayın. Saldırı yüzeyini haritalamak, ayrıcalıkları artırmanıza izin veren güvenlik sorunlarını bulmak ve temel kanıtları toplamak için otomatik istismarları kullanmak için 20'den fazla özel aracımızı kullanın, böylece sıkı çalışmanızı ikna edici raporlara dönüştürün.
Bu, phpMyAdmin çerezleri için de geçerlidir.
Çerezler:
Konumlar:
Eğer ==
PHP'de kullanılıyorsa, beklenmedik durumlar ortaya çıkabilir ve karşılaştırma beklenildiği gibi davranmayabilir. Bunun nedeni, "==" sadece aynı tipe dönüştürülmüş değerleri karşılaştırmasıdır; eğer karşılaştırılan verilerin tipinin de aynı olmasını istiyorsanız ===
kullanmalısınız.
PHP karşılaştırma tabloları: https://www.php.net/manual/en/types.comparisons.php
"string" == 0 -> True
Sayı ile başlamayan bir dize, bir sayıya eşittir
"0xAAAA" == "43690" -> True
Onaltılık veya ondalık formatta sayılardan oluşan dizeler, sayılar aynıysa diğer sayılarla/dizelerle True sonucu ile karşılaştırılabilir (bir dizideki sayılar sayı olarak yorumlanır)
"0e3264578" == 0 --> True
"0e" ile başlayan ve ardından herhangi bir şey gelen bir dize, 0'a eşit olacaktır
"0X3264578" == 0X --> True
"0" ile başlayan ve ardından herhangi bir harf (X herhangi bir harf olabilir) ve ardından herhangi bir şey gelen bir dize, 0'a eşit olacaktır
"0e12334" == "0" --> True
Bu çok ilginçtir çünkü bazı durumlarda "0" dizesinin girdiğini ve bununla karşılaştırılan bazı içeriklerin kontrolünü sağlayabilirsiniz. Bu nedenle, "0e" ile başlayan ve herhangi bir harf içermeyen bir hash oluşturacak bir değer sağlayabilirseniz, karşılaştırmayı atlatabilirsiniz. Bu formatta zaten hashlenmiş dizeleri burada bulabilirsiniz: https://github.com/spaze/hashes
"X" == 0 --> True
Bir dizideki herhangi bir harf, int 0'a eşittir
Daha fazla bilgi için https://medium.com/swlh/php-type-juggling-vulnerabilities-3e28c4ed5c09
Tip Değiştirme varsayılan olarak in_array()
fonksiyonunu da etkiler (katı bir karşılaştırma yapmak için üçüncü argümanı true olarak ayarlamanız gerekir):
Eğer bu fonksiyon herhangi bir kimlik doğrulama kontrolü için kullanılıyorsa (şifre kontrolü gibi) ve kullanıcı karşılaştırmanın bir tarafını kontrol ediyorsa, şifre değeri olarak bir dize yerine boş bir dizi gönderebilir (https://example.com/login.php/?username=admin&password[]=
) ve bu kontrolü atlayabilir:
strcasecmp()
ile aynı hata meydana gelir
===
kullanılıyor olsa bile, karşılaştırmayı zayıf hale getiren hatalar olabilir. Örneğin, eğer karşılaştırma karşılaştırmadan önce veriyi farklı bir tür nesneye dönüştürüyorsa:
preg_match()
kullanıcı girişi doğrulamak için kullanılabilir (kullanıcı girişi üzerinde herhangi bir kelime/regex kara liste'den varsa kontrol eder ve eğer yoksa, kod çalışmaya devam edebilir).
Ancak, regexp'nin başlangıcını belirlerken preg_match()
kullanıcı girişinin sadece ilk satırını kontrol eder, eğer bir şekilde girişi birden fazla satırda gönderebilirseniz, bu kontrolü atlatabilirsiniz. Örnek:
Bu kontrolü atlamak için değerleri yeni satırlarla urlencoded (%0A
) gönderebilir veya JSON verisi gönderebiliyorsanız, bunu birkaç satırda gönderebilirsiniz:
Bir örneği burada bulabilirsiniz: https://ramadistra.dev/fbctf-2019-rceservice
(Bu atlatma, görünüşe göre PHP 5.2.5 üzerinde denendi ve PHP 7.3.15 üzerinde çalıştırmayı başaramadım)
preg_match()
'e geçerli çok büyük bir girdi gönderebilirseniz, işleyemeyecek ve kontrolü atlatabileceksiniz. Örneğin, bir JSON'u kara listeye alıyorsa, şunu gönderebilirsiniz:
From: https://medium.com/bugbountywriteup/solving-each-and-every-fb-ctf-challenge-part-1-4bce03e2ecb0
Trick from: https://simones-organization-4.gitbook.io/hackbook-of-a-hacker/ctf-writeups/intigriti-challenges/1223 and https://mizu.re/post/pong
Kısacası, sorun PHP'deki preg_*
fonksiyonlarının PCRE kütüphanesi üzerine inşa edilmesinden kaynaklanıyor. PCRE'de belirli düzenli ifadeler, çok sayıda özyinelemeli çağrı kullanılarak eşleştirilir, bu da çok fazla yığın alanı kullanır. İzin verilen özyineleme sayısı için bir sınır belirlemek mümkündür, ancak PHP'de bu sınır varsayılan olarak 100.000 olup, bu yığının içine sığacak olandan fazladır.
Bu Stackoverflow başlığı da bu konunun daha derinlemesine tartışıldığı gönderide bağlantılıydı. Görevimiz şimdi açıktı:
Regex'in 100_000+ özyineleme yapmasını sağlayacak bir girdi gönderin, bu da SIGSEGV'ye neden olacak, preg_match()
fonksiyonunun false
döndürmesini sağlayacak ve böylece uygulamanın girdimizin kötü niyetli olmadığını düşünmesine neden olacak, yükün sonunda {system(<verybadcommand>)}
gibi bir sürpriz atarak SSTI --> RCE --> flag :).
Aslında, regex terimleriyle, 100k "özyineleme" yapmıyoruz, bunun yerine "geri izleme adımlarını" sayıyoruz, ki PHP belgeleri bunun pcre.backtrack_limit
değişkeninde varsayılan olarak 1_000_000 (1M) olduğunu belirtmektedir.
Buna ulaşmak için, 'X'*500_001
1 milyon geri izleme adımına (500k ileri ve 500k geri) yol açacaktır:
Eğer PHP başka bir sayfaya yönlendiriyorsa ancak başlık Location
ayarlandıktan sonra die
veya exit
fonksiyonu çağrılmadıysa, PHP çalışmaya devam eder ve verileri gövdeye ekler:
Kontrol et:
File Inclusion/Path traversalregister_globals: PHP < 4.1.1.1'de veya yanlış yapılandırıldığında, register_globals aktif olabilir (veya davranışları taklit ediliyor olabilir). Bu, $_GET gibi global değişkenlerde bir değer varsa örneğin $_GET["param"]="1234", $param üzerinden erişebileceğiniz anlamına gelir. Bu nedenle, HTTP parametreleri göndererek, kod içinde kullanılan değişkenleri geçersiz kılabilirsiniz.
Aynı alanın PHPSESSION çerezleri aynı yerde saklanır, bu nedenle bir alanda farklı çerezler farklı yollarla kullanılıyorsa, bir yolun diğer yolun çerezine erişmesini sağlayarak diğer yol çerezinin değerini ayarlayabilirsiniz. Bu şekilde, eğer her iki yol da aynı isimde bir değişkene erişiyorsa, o değişkenin path1'deki değeri path2'ye uygulanabilir. Ve ardından path2, path1'in değişkenlerini geçerli olarak alacaktır (çereze path2'deki karşılık gelen ismi vererek).
Makinenin kullanıcılarının kullanıcı adlarını aldığınızda, php dizinlerinin etkin olup olmadığını kontrol etmek için adresi kontrol edin: /~<USERNAME>.
Bu fonksiyonlar genellikle PHP'de şifrelerden hash oluşturmak ve bir hash ile karşılaştırıldığında bir şifrenin doğru olup olmadığını kontrol etmek için kullanılır.
Desteklenen algoritmalar: PASSWORD_DEFAULT
ve PASSWORD_BCRYPT
( $2y$
ile başlar). PASSWORD_DEFAULT genellikle PASSWORD_BCRYPT ile aynıdır. Ve şu anda, PASSWORD_BCRYPT'in girişte 72baytlık bir boyut sınırlaması vardır. Bu nedenle, bu algoritma ile 72 bayttan daha büyük bir şeyi hashlemeye çalıştığınızda yalnızca ilk 72B kullanılacaktır:
bu twitter dizisinden görebilirsiniz ki, 1000'den fazla GET parametresi veya 1000'den fazla POST parametresi veya 20 dosya gönderildiğinde, PHP yanıtında başlıkları ayarlamayacaktır.
Bu, örneğin CSP başlıklarının kodlarda ayarlanmasını bypass etmeye olanak tanır:
Eğer bir PHP sayfası hataları yazdırıyorsa ve kullanıcı tarafından sağlanan bazı girdileri geri ekrana basıyorsa, kullanıcı PHP sunucusunun geri dönen bazı içerikleri yeterince uzun bir şekilde yazdırmasını sağlayabilir, böylece sunucu başlıkları yanıtın içine eklemeye çalıştığında bir hata verecektir. Aşağıdaki senaryoda saldırgan sunucunun büyük hatalar vermesini sağladı ve ekranda görebileceğiniz gibi PHP başlık bilgilerini değiştirmeye çalıştığında, başaramadı (örneğin CSP başlığı kullanıcıya gönderilmedi):
Sayfayı kontrol et:
PHP SSRFsystem("ls"); `ls`; shell_exec("ls");
Daha fazla yararlı PHP fonksiyonu için bunu kontrol edin
"replace" argümanında kodu çalıştırmak için en az bir eşleşme gereklidir. Bu preg_replace seçeneği PHP 5.5.0 itibarıyla kullanımdan kaldırılmıştır.
Php içindeki bu fonksiyon, bir dizi içinde yazılmış kodu çalıştırmanıza olanak tanır ve true veya false döndürür (ve buna bağlı olarak yürütmeyi değiştirir). Genellikle kullanıcı değişkeni bir dizenin ortasına yerleştirilecektir. Örneğin:
assert("strpos($_GET['page']),'..') === false")
--> Bu durumda RCE elde etmek için şunu yapabilirsiniz:
Kod sözdizimini bozmanız, payload'ınızı eklemeniz ve sonra tekrar düzeltmeniz gerekecek. "and" veya "%26%26" veya "|" gibi mantıksal işlemler kullanabilirsiniz. "or", "||" çalışmaz çünkü ilk koşul doğruysa payload'ımız çalışmayacaktır. Aynı şekilde ";" çalışmaz çünkü payload'ımız çalışmayacaktır.
Diğer bir seçenek, dizeye komutun yürütülmesini eklemektir: '.highlight_file('.passwd').'
Diğer bir seçenek (eğer iç kodunuz varsa) bazı değişkenleri değiştirerek yürütmeyi değiştirmektir: $file = "hola"
Bu fonksiyon, belirli bir fonksiyonu kullanarak bir dizi öğeyi sıralamak için kullanılır. Bu fonksiyonu kötüye kullanmak için:
You can also use // to comment the rest of the code.
To discover the number of parenthesis that you need to close:
?order=id;}//
: bir hata mesajı alıyoruz (Parse error: syntax error, unexpected ';'
). Muhtemelen bir veya daha fazla parantez eksik.
?order=id);}//
: bir uyarı alıyoruz. Bu doğru görünüyor.
?order=id));}//
: bir hata mesajı alıyoruz (Parse error: syntax error, unexpected ')' i
). Muhtemelen fazla kapanış parantezimiz var.
Eğer .htaccess yükleyebiliyorsanız, o zaman birkaç şeyi yapılandırabilir ve hatta kod çalıştırabilirsiniz (uzantısı .htaccess olan dosyaların çalıştırılabilir olduğunu yapılandırarak).
Farklı .htaccess shell'leri burada bulunabilir.
Eğer PHP'de env değişkenlerini değiştirmeye izin veren bir zafiyet bulursanız (ve dosya yüklemeye izin veren başka bir zafiyet, daha fazla araştırmayla belki bu aşılabilir), 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 rastgele kütüphaneleri yüklemenize izin verir (bu durumda çalışmayabilir).
PHPRC
: PHP'ye konfigürasyon dosyasını nerede bulacağını belirtir, genellikle php.ini
olarak adlandırılır. Kendi konfigürasyon dosyanızı yükleyebilirseniz, o zaman PHPRC
'yi PHP'yi ona yönlendirmek için kullanın. İkinci bir yüklenmiş dosyayı belirten bir auto_prepend_file
girişi ekleyin. Bu ikinci dosya, PHP çalışma zamanı tarafından diğer kodlardan önce çalıştırılan normal PHP kodunu içerir.
Shell kodumuzu içeren bir PHP dosyası yükleyin.
Adım 1'de yüklediğimiz dosyayı çalıştırması için PHP ön işleyicisine talimat veren bir auto_prepend_file
direktifi içeren ikinci bir dosya yükleyin.
PHPRC
değişkenini adım 2'de yüklediğimiz dosyaya ayarlayın.
Bu zinciri nasıl çalıştıracağınız hakkında daha fazla bilgi orijinal rapordan alın.
PHPRC - başka bir seçenek
Eğer dosya yükleyemiyorsanız, FreeBSD'de stdin
'i içeren "file" /dev/fd/0
kullanabilirsiniz:
curl "http://10.12.72.1/?PHPRC=/dev/fd/0" --data-binary 'auto_prepend_file="/etc/passwd"'
Ya da RCE elde etmek için allow_url_include
'yi etkinleştirip base64 PHP kodu ile bir dosya 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.
Web sunucusu HTTP isteklerini ayrıştırır ve bunları http://host/cgi.php?foo=bar
gibi bir isteği çalıştıran bir PHP betiğine iletir, bu da bir parametre enjeksiyonuna izin verir. Bu, gövde içindeki PHP kodunu yüklemek için aşağıdaki parametreleri enjekte etmeye izin verecektir:
Ayrıca, PHP'nin sonraki normalizasyonu nedeniyle "-" parametresini 0xAD karakteri kullanarak enjekte etmek mümkündür. bu gönderiden istismar örneğini kontrol edin:
Bu yazıda çok az izin verilen karakterle bir brain fuck PHP kodu oluşturmak için harika fikirler bulmak mümkündür. Ayrıca, birkaç kontrolü atlatmalarını sağlayan fonksiyonları çalıştırmanın ilginç bir yolu da önerilmektedir:
Bu fonksiyonlara yapılan çağrılarda kod ekleyip ekleyemeyeceğinizi kontrol edin (buradan): here
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 deşifre etmek için web www.unphp.net kullanabilirsiniz.
PHP Wrapper'ları ve protokolleri, bir sistemde yazma ve okuma korumalarını atlamanıza ve onu tehlikeye atmanıza olanak tanıyabilir. daha fazla bilgi için bu sayfayı kontrol edin.
Eğer phpconfig()
çıktısında Xdebug'ın etkin olduğunu görüyorsanız, https://github.com/nqxcode/xdebug-exploit üzerinden RCE elde etmeyi denemelisiniz.
Bir sayfada rastgele bir sınıfın yeni bir nesnesini oluşturabiliyorsanız RCE elde etme şansınız olabilir, nasıl yapılacağını öğrenmek için aşağıdaki sayfayı kontrol edin:
PHP - RCE abusing object creation: new $_GET["a"]($_GET["b"])https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
bu yazıya göre, kolay bir shell kodu bu şekilde oluşturmak mümkündür:
Yani, eğer rakamlar ve harfler olmadan rastgele PHP çalıştırabiliyorsanız, aşağıdaki gibi bir istek gönderebilirsiniz, bu yükü kullanarak rastgele PHP çalıştırmak için:
Daha derin bir açıklama için https://ctf-wiki.org/web/php/php/#preg_match adresini kontrol edin.
Web uygulamalarınız, ağınız ve bulutunuz hakkında bir hacker perspektifi edinin
Gerçek iş etkisi olan kritik, istismar edilebilir güvenlik açıklarını bulun ve raporlayın. Saldırı yüzeyini haritalamak, ayrıcalıkları artırmanıza izin veren güvenlik sorunlarını bulmak ve temel kanıtları toplamak için otomatik istismarları kullanmak için 20'den fazla özel aracımızı kullanın, böylece sıkı çalışmanızı ikna edici raporlara dönüştürebilirsiniz.
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)