Web Uygulama Güvenliği: SQL Injection - mysql_real_escape_string

Bu döküman önceki dökümanın devamı niteliğindedir. SQL Injection ile kritik verileri okumada az çok birtakım teknikler öğrendik. Sıra geldi bazı güvenlik önlemlerini atlatarak...

Bu döküman önceki dökümanın devamı niteliğindedir.

SQL Injection ile kritik verileri okumada az çok birtakım teknikler öğrendik.
Sıra geldi bazı güvenlik önlemlerini atlatarak sistemde sorgu çalıştırmaya.

Başlangıç olarak hedef web uygulamasında veritabanıyla etkileşimde olan bir yer tespit edelim.

1 verdik bir veri geldi.
2 verdik başka bir veri geldi.

sqli1.pngsqli1.png

Demekki sayfa dinamik bir şekilde çalışmakta çünkü verdiğimiz veriye göre başka bir veri getiriyor.

Şimdi SQL injection için tek tırnak atalım.

sqli2.pngsqli2.png

Evet hatamızı aldık ama dikkat edelim kutu içine aldığım yere bakın.
Verdiğimiz tek tırnak önünde ters yan çizgi var yani \ işareti var.
Biz tek tırnak verdik önüne \ işareti geldi normalde bu işaret kendinden sonra gelen özel işareti mysql tarafından görmezden gelmek için kullanılıyor.
Bizim saldırımızıda ise tek tırnak işaretlerini bu şekilde ters slash içine alındığından ne yaparsak yapalım içinde bulunduğumuz sorgunun dışına çıkıp yeni sorgular oluşturamayacağız.
Çünkü sorguyu kapayıp yeni sorgu açmamız için tek tırnak kullanmamız lazım.
Tek tırnak işareti ile içinde bulunduğumuz sorguyu kapatırız ve yeni sorgu açarız, hatırlayalım. Bu şekilde veritabanında istediğimiz sorguları gerçekleştirerek saldırı yaparız.
Php'de mysql_real_escape_string fonksiyonu kullanılan sayfalarda içinde bulunduğumuz sorgu kısmını kapayamıyoruz çünkü ' tek tırnak işareti ile kapayabiliriz ve bu tek tırnak görmezden gelindiğinden yani başına ters slash eklendiğinden mysql tarafından işleve alınmıyor ve sonrasında veritabanında sorgulanıldığından dolayı içinde bulunduğumuz sorguyu kapatamıyoruz.

Çok eskiden mysql bazı sürümlerinde bir bug vardı ve sorguyu kapatabiliyorduk ama o bug şimdi güncel olmadığından göstermeyeceğim.

Peki ne anladık kısaca özetleyelim?
Verdiğimiz girdi mysql_real_escape_string fonksiyonuna verilince verimizdeki tek tırnak gibi özel karakterler ters slash içine alınıyor.
Ve sonrasında bu mysql_real_escape_string çıktısı veritabanında sorgulanıyor.
Ama tek tırnak ile sorgu kapatmamız ters slash içine alındığından mysql tarafından görmezden geliniyor ve sorgu kapanmıyor.
Yani bir nevi içinde bulunduğumuz sorgunun kısmında kalıyoruz yeni sorgu açamıyoruz.

Ama burada dikkat bütün bu işlemler tek tırnak kapamak için kullanılıyor.
Eğer verdiğimiz veri veritabanında integer gibi sayısal bir değer olarak sorgulanıyorsa biz yine zararlı SQL sorgularımızı çalıştırabiliriz.
Neden?
Çünkü veri zaten direkt olarak alınıyor başında tek tırnak ile sonunda tek tırnak yok eğer o şekilde alınsaydı string veritipi olarak alınırdı.
Ama integer veri tipi olarak alındığından mysql_real_escape_string kullanılsa dahi SQL injection saldırısı yapabiliriz.

sqli3.pngsqli3.png

Sayfanın statik kodlarını incelersek gördüğümüz gibi user_id anahtar değerindeki veri sayısal bir değer olarak alındığından tek tırnak işareti kullanmamıza gerek kalmaz yeni sorgular gerçekleştirebiliriz.
Ve tek tırnak kullanmamıza gerek kalmadığından mysql_real_escape_string fonksiyonun sağladığı güvenlik önlemi bir işlevi olmayacaktır.
Neden çünkü tek tırnak gibi bazı özel karakterler mysql_real_escape_string fonksiyonu içerisinde ters slash içerisine alınıyordu.
Ve veritabanı ters slash'tan sonra gelen özel karakteri görmezden geliyordu.
Eğer tek tırnak kullanılmayan bir yerde yani sayısal değer olarak verimiz sorgulanıyorsa biz yine SQL injection açığını çıkarabiliriz.
Çok uzattım farkındayım ama mantığı önemli arkadaşlar.

sqli4.pngsqli4.png

Örneğin 1 and 1=1 ile sorgumuzu gerçekleştirelim.
Sonunda yorum satırı içine alması gereken # işaretini koymadım çünkü veri sayısal olarak alınıyor yani sonunda bir tek tırnak dahi yok.
Ha belki sorgunun başka özellikleri de olabilirdi o durumda yine yorum içine almalıydık. Örneğin like sorgu komutu gibi.
1'den sonrada tek tırnak eklemedik çünkü veri sayısal bir değer olarak alınıyor bunu biliyoruz sayfanın kaynak kodundan.

1 and 1=2 yaptığımızda bir çıktı görmüyoruz demekki sorguya yeni sorgular ekleyebiliyoruz.
Tabi and 1=1 neden bir çıktı sağlıyor neden and 1=2 bir çıktı sağlamıyor önceki konularda anlattım.
Kısaca 1=1 true olduğundan -çünkü 1 1'e eşittir- önceki kısma da and ile bağlandığından and true olur ve ilk kısım varsa çıktı çıkar.
Ama and 1=2 false olduğundan -çünkü 1 2'ye eşit değildir- and false olur ve and iki kısmın doğruluğunu kontrol ettiğinden eğer biri false ise çıktı vermez.

Hemen order by ile içinde bulunduğumuz sorguda kullanılmakta olan kolon sayısını bulalım.

sqli5.pngsqli5.png

Sonrasında o kolonların sayfada nerede kullanıldığını bulmak için union select kullanalım.

sqli6.pngsqli6.png

Şimdide information_schema veritabanından içinde bulunduğumuz veritabanının tablolalarını çekelim.
group_concat fonksiyonu kullanmamızın sebebi eğer veri çıktısında bir döngü yoksa sadece 1 tane çıktı yani ilk çıktıyı verir biz bütün tablolaları görmek istediğimizden group_concat ile tablo isimlerini gruplayabilirek bütün tablo isimlerini öğrenebiliriz.

sqli7.pngsqli7.png

Seçtiğimiz tablonun kolonlarına ulaşmak için normalde sorgumuzun sonunda table_name='tabloismi' olurdu ancak burada tek tırnak kullanıldığından mysql_real_escape_string fonksiyonu devreye girecektir.
Bunu atlatmak içinde tablo ismini hex ile encode ediyoruz ve başına 0x koyarak MySQL sisteminde bulunan bir veri olarak tabloya ulaşıyoruz.

sqli8.pngsqli8.png

Yine son olarak tablonun verilerine erişiyoruz.
0x0a diyerek aralarını boşluk olarak ayırıyoruz. Yine dediğim gibi MySQL özelliği bunlar.

sqli9.pngsqli9.png
 
131,893Konular
3,272,351Mesajlar
316,483Kullanıcılar
Zina_CheckSon Üye
Üst Alt