twitterlinkedinemail

14 Mayıs 2014 Çarşamba

PHP Scriptlerde SQLi Tespiti ve Exploit Etme

NŞA'da PHP scriptler üzerinde iki yöntem ile zafiyet araştırmaları yapılabilir.

  1. Manuel Araştırma
  2. Otomatik Kaynak Kod Tarayıcılarla

Biz bu blog yazısında iki yöntemi de kullanarak temel anlamda PHP scriptlerde zafiyetler (SQLi, XSS, RCE, LFI vb.) nasıl keşfedilir ve nasıl exploit (sömürme) edilebilir bunlara değineceğiz.

SQL Injection Nedir?

Web uygulamalarında birçok işlem için kullanıcıdan alınan veri ile dinamik SQL cümlecikleri oluşturulur. Örneğin; "SELECT * FROM Products" örnek SQL cümleciği basit şekilde veritabanından web uygulamasına tüm ürünleri döndürecektir. Bu SQL cümlecikleri oluşturulurken araya sıkıştırılan herhangi bir meta-karakter SQL Injection'a neden olabilir.

Öncelikle örnek olması açısından SQL Injection açığı barındıran bir betik ile başlayalım.
Betiğimizin görevi; üye id'sine göre veritabanından o id'ye sahip üyenin bilgilerini ekrana yazdırmaktadır.

sqli isimli bir veritabanı oluşturdum ve içinde uye isimli bir tablo mevcut. Tablonun da 4 adet sütunu var. Sütunlar: id, username, password, email
Son olarak da içine örnek birkaç adet veri girişi yaptım:

Betiğimizi oluşturan uye.php dosyasının kodları aşağıdaki gibidir:
<?php 
$baglan = mysql_pconnect("localhost","root","123456");    / veritabanına bağlanıyoruz
$baglan = mysql_select_db("sqli",$baglan);    / oluşturduğumuz veritabanımızı seçiyoruz
$id = $_GET["id"];
$sorgu = "SELECT * FROM uye WHERE id=".$id;

$cek = mysql_fetch_object(mysql_query($sorgu)); 
echo 'Olusan Sorgu: '.$sorgu."<br>";
echo $cek->username."<br>".$cek->email; 
?>
Bu betiği SQL Injection'a uğratan kod kısımlarını kırmızı renkle vurgulayarak gösterdim..
Böyle bir kod yazımı göstere göstere SQL Injection zafiyetine zemin oluşturmaktadır. Zafiyete neden olan id= query stringinin filtrelenmeden dinamik sql sorgusuyla birleştirilmesidir.

Manuel yolla ve genel olarak PHP scriptlerde SQL Injection zafiyetini yukarıdaki kod örneğindeki gibi tespitini yapabiliriz. Yani dinamik sorgu cümleciklerine ve hangi yöntemlerle sorgu çekildiklerine odaklanılmalıdır.

uye.php çalıştırıldığında görüldüğü gibi 1 id'sindeki bilgiler yani benim bilgilerim ekrana yazdırıldı:

Fakat zayıf bir kod yazım şekli kullandığımız için şimdi bunu SQL Injection saldırısına uğratalım, nasıl mı? id=1 ifadesinden sonra ' (tek tırnak) meta-karakterini kullanarak:


Sayfa Warning: mysql_fetch_object()... hatası verdi! Şimdi sıra geldi bunu sömürmeye yani exploit etmeye :) Veritabanından hassas veriyi sızdırıyoruz:

Görüldüğü gibi bilgiler ekrana yansıdı:
username: ismailsaygili
password: iso123

Aynı exploiting işlemini bir de otomatize araç olan SQLMap ile exploit edelim:

Script üzerinde manuel yöntemle SQL Injection zafiyetini keşfetmiştik, şimdi de otomatik olarak RIPS yazılımı aracılığıyla PHP scriptler üzerinde zafiyet araştırması yapalım. Bu arada RIPS; PHP için statik kodlarda zafiyet analizi yapan bir yazılımdır.

RIPS Kurulumu ve Kullanımı

RIPS hiç bir kurulum gerektirmez! Tak-Çalıştır mantığı :)

Öncelikle RIPS'i buradan indirelim. rips klasörünü localhost'unuza kopyalayın ve web tarayıcınızla ilgili URL'e gidin:


1. Adımda: Taramak istediğiniz PHP scriptin klasör yolu belirtilir. Ben yukarıda örneğini yaptığımız betiğin klasör yolunu yazdım, çünkü şuan onu tarayacağız.

2. Adımda: Zafiyet tipi seçilir. Ben SQL Injection zafiyetini seçtim.

3. Adımda: subdirs'i seçersek belirttiğiniz klasör yolunun alt klasörleri de taranacaktır.

4. Adımda: Son olarak scan butonuna basarak taramayı başlatıyoruz.

Ben taramamı yaptım ve sonuç bu şekilde:

Görüldüğü üzere RIPS, 7. satırda SQL Injection zafiyeti tespit etti. Yukarıda biz manuel denetim yaparken keşfettik hatırladınız mı? :)

Hocam zayıf kodu paylaştınız, peki bu kodun güvenli hali nasıl yazılır?
Güvenli Kod 1:
<?php

$baglan = mysql_pconnect("localhost","root","123456");
$baglan = mysql_select_db("sqli",$baglan); 
$id = (int) intval($_GET["id"]); // değişken tipi belirlenerek integer koruması sağlandı
$sorgu = "SELECT * FROM uye WHERE id=".$id;
$cek = mysql_fetch_object(mysql_query($sorgu)); 
echo 'Olusan Sorgu: '.$sorgu."<br>";
echo $cek->username."<br>".$cek->email;

?>
id değişkeninin tipini belirleyerek integer koruması sağlamış olduk. Yani saldırgan http://localhost/sqli/uye.php?id=1 URL'inden sonra tek tırnak meta-karakterini eklediğinde amacına ulaşamayacaktır çünkü id= query'sinden sonra sadece integer değerler kabul edilecektir. String yani karakter dizileri kabul edilemeyecektir.
Gördüğünüz gibi kullanıcı adı ve parolayı veritabanından çekemiyoruz :(

SQL Injection'dan korunma tabi ki sadece bununla sınırlı değildir.. Örneğin id değişkeni mysql_real_escape_string fonksiyonu içine alınarak SQL sorguları için zararlı olabilecek karakterlerin başına \ ekler.

Diğer SQL Injection'dan Korunma Yöntemleri

  • Web uygulamalarında SQL Injection saldırısı yapmakta kullanılan komut ve karakterlerin geçişi engellenmelidir. Veri girişinin filtrelenmesi kadar veri çıkışının da incelenmesi web uygulamanın güvenliğini arttıracaktır.
  • Aşağıda belirtilen karakterlerin filtrelenmesi web uygulamanın SQL Injection ve olası diğer saldırılara karşı güvenliğini sağlayacaktır:
    • ['],[<],[>],[;],[/],[?],[=],[&],[#],[%],[{],[}],[|],[@],[\],[union],[exec],[select],[insert], [update],[delete],[drop],[sp],[xp],["]
  • Veritabanı Bağlantılarının Yetkilerinin Düşürülmesi
    • Web uygulamanın veritabanına bağlanıp kayıtları okurken ve yazarken kullandığı hesabın yetkilerinin minimumda tutulması olası SQL Injection saldırısının zararlarını azaltacaktır.
  • Hata Mesajlarının Engellenmesi
    • Saldırganların hata mesajlarından bilgi almasını engellemek için hata mesajlarının görüntülenmesini engellemek sistemi daha güvenli hale getirecektir.
  • SA Hesabının Korunması
    • MS SQL sunucu üzerinde bulunan SA hesabının güçlü bir parolaya sahip olması brute-force saldırına karşı sistemin güvenliğini arttırmak için gerekli etkenlerden biridir. Web uygulamalarının SA hesabı ile veritabanına bağlanmasını engellemeliyiz! Olası SQL Injection sonucu saldırganın SA yetkilerinde kod çalıştırabileceğini unutmayınız.
  • Kaynak Kodların Kontrol Edilmesi
    • Web uygulamalarının kaynak kodlarının olası saldırılara karşı denetlenmesi gerekmektedir. Özellikle kullanıcının veri girişine müsade edilen alanlar ve URL alanında yapılabilecek değişikliklere karşı filtrelemelerin uygulanmasını sağlamalıyız.
  • Veritabanındaki Kayıtların Şifrelenmesi
    • Özellikle kullanıcıların parolalarının tutulduğu alanların şifrelenerek veritabanına yazılması olası veritabanındaki bilgilere ulaşılması durumuna karşı ekstra güvenlik sağlayacaktır.
  • Yazılımsal veya donanımsal olarak Web Application Firewall (WAF) kullanımı

Pekiştirmek açısından bir örnek daha yapmak istiyorum.
PHP script olan TopGames v1.2 sürümünde daha önceden SQL Injection açığı keşfedilmiş (http://www.exploit-db.com/exploits/26405/).

Haydi bunun sağlamasını RIPS ile tarayarak yapalım.. sonuç ortada:

SQL Injection dışında bir de Cross-Site Scripting (XSS) zafiyeti keşfettik :)

play.php dosyasının 4. satırında SQL Injection zafiyeti ($_GET["gid"]) ve cat.php dosyasının 4. satırında ($_GET["id"]) XSS zafiyeti mevcutmuş.

SQL Injection zafiyetini bu seferde Havij ile exploit edelim:

Bir de bulduğumuz XSS zafiyetini test edelim:

Sonuç başarılı...

TopGames scriptinde bulduğumuz XSS zafiyetini Exploit-DB'ye mi bildirsek ne? :)

12 yorum:

  1. Hocam bomba gibi bir makale olmuş tebrik ediyorum.

    YanıtlaSil
  2. Gerçekten elinize sağlık çok güzel olmuş.
    birde bu php scriptleri içinde zararlı kod varmı yokmu onu kontrol edebileceğimiz yazılımlar varmı acaba?
    Özellikle tema dosyalarında böyle virüsler vb. şeyler çok bulaşıyor :(

    YanıtlaSil
    Yanıtlar
    1. Merhaba,
      Teşekkür ederim. Öncelikle scripti güncel bir antivirus programıyla taradıktan sonra "base64_decode, system, passthru, popen, exec, shell_exec, eval, move_uploaded_file vb." gibi zararlı olabilecek fonksiyonları dosyalarda aratıp ve dosyaları manuel incelemekte fayda var.
      Bu işlemi otomatik yapan araçlar vardır ancak ben pek kullanmadığım için size öneremeyeceğim. Eğer bulursanız buradan yorum olarak paylaşabilirsiniz. İyi çalışmalar.

      Sil
    2. Aslında tam olarak ne istediğimi bilmiyordum. Sadece öyle bir proğramın olduğunu sanıyordum ve biraz araştırınca aslında bu sitelerdeki açıkları bulmak için kullanılan proğramlar ile karıştırmışım.
      Gr3eNoX gibi "SQLi/XSS/LFi/RFi" açıklarını kontrol ediyormuş.
      Yinede kullanmadım bunları.
      Kendi web sitemizdeki açıkları çok üstdüzey bilgi sahibi olmasakta gerçekten nasıl test edebiliriz?
      Sizin öneriniz nedir hocam?

      Sil
    3. Merhaba,
      Kendi web sitenizin güvenlik açıklarının olup olmadığını Acunetix, Netsparker veya w3af gibi yazılımlarla denetleyebilirsiniz.

      Sil
    4. Merhabalar,
      Ben bu konuda hiçbir bilgi sahibi değilim o yüzden verdiğiniz proğramlar nedir, nasıl kullanılır onuda bilmiyorum.
      Ama verdiğiniz proğramları araştıracağım ve kendi sitemi test edeceğim.
      Yinede bu proğramları nasıl kullanıldığı hakkında bir makaleniz olursa daha güzel olurdu. :) Yinede Teşekkürler ilginiz için.

      Sil
    5. Merhaba,
      Bahsettiğim programların kullanımını araştırırsanız kolayca öğrenebilirsiniz. Ben teşekkür ederim, iyi çalışmalar.

      Sil
  3. Windows ortaminda acunetix ve netsparker kullaniyordum ama linux ortamina gectim. vega diye bir uygulama var ancak true false orani cok kotu. suana kadar begendigim uygulamalar acunetix ve netsparker. acunetix cok fazla parametre denedigi icin yavas fakat diger programlarin bulamadigin bulabiliyor. netsparker da parametreler daha sadelesis daha hizli calisiyor. sorum: linuxta kullanabilecegim acunetix gibi saglam scannerlar varmi? tesekkurler

    YanıtlaSil
  4. Gerçekten benim için çok faydalı oldu bu güzel bilgilendirmenizden dolayı teşekkür ederim.

    YanıtlaSil
  5. faydalı bilgi fakat eksik ve hatalar göze çarpıyor. yazıyı tekrardan gözden geçirmelisin ismail.

    YanıtlaSil
  6. Userinput reaches sensitive sink. For more information, press the help icon on the left side. (Blind exploitation)
    27: odbc_execute odbc_execute($stmt, $args))
    26: $args = $username // array()
    6: $username = trim($_POST[‘username’]) : ”;
    requires:
    13: if(isset($_POST) && !empty($_POST))
    21: if(ctype_alnum($username) === false) else

    sql İnjection açığı alıyorum yardımcı olabilirmisiniz.

    YanıtlaSil
  7. Değişik bir yaklaşım olmuş ama başarılı

    YanıtlaSil