İçeriğe atla
0 XP 0
13 dkderinleşmeyle 14 dk55 XP8 etkinlik

SQL enjeksiyonu: sorgudan veri çekmek

Bu derste
  • SQL enjeksiyonu, sorgunun WHERE koşulunu saldırganın yazdığı mantıkla değiştirmesidir; türlerini, tespitini ve parametreli savunmayı öğrenirsin.
  • Giriş formunu atlatan klasik hileyi çözer, UNION ile sütun sayısını bulur, parametreli sorgu ve en az yetkili hesapla kapıyı kapatırsın.

Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +55 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.

SQL enjeksiyonu, enjeksiyon ailesinin en eski ve en çok belgelenmiş üyesidir. Uygulama, kullanıcı girdisini bir SQL sorgusunun metnine metin birleştirmeyle katıyorsa, girdi artık sorgunun mantığını değiştirebilir. Bu derste önce klasik giriş atlatmayı, sonra SQL enjeksiyonu türlerini, adım adım veri çekmeyi ve otomasyonun logda bıraktığı izi görürsün.

En sonda kalıcı çözümü, yani parametreli sorguyu ve onu tamamlayan katmanları kurarsın. Örnekler Altay Kargo uygulamasının test ortamında geçer.

Sorgunun mantığı ve SQLi türleri

Altay Kargo'nun giriş formu, kullanıcı adını ve parolayı doğrudan sorgu metnine ekliyor olsun. Sorgu şuna benzer: SELECT id FROM kullanici WHERE ad='<ad>' AND parola='<parola>'. Uygulama, dönen satır sayısı sıfırdan büyükse girişi onaylar.

Kullanıcı adı alanına ' OR 1=1-- yazan biri (iki tireden sonra bir boşlukla), sorguyu WHERE ad='' OR 1=1-- ' AND parola='...' hâline getirir. İki tire ve boşluk satırın geri kalanını yoruma çevirir; parola koşulu hiç çalışmaz. Kalan koşul her satır için doğrudur; sorgu tablodaki ilk satırı döner ve giriş açılır.

Parolayı hiç bilmeden, yalnız sorgunun mantığını değiştirerek içeri girilir. Kök neden aynı kalır: girdi, metin birleştirmeyle sorgunun içine karışmıştır. Bu tek örnek, SQL enjeksiyonunun neden bu kadar tehlikeli olduğunu özetler.

Saldırgan ne parola çalar ne de şifre kırar; yalnız sorgunun mantığını kendi lehine çevirir. Aynı hile kullanıcı listeleme, sipariş görüntüleme ve rapor üretme gibi her sorguda tekrarlanabilir. Sorunun ölçeği tek bir giriş formuyla sınırlı değildir; metin birleştirmeyle kurulan her sorgu aynı kapıyı taşır.

Etkinlik 1 / 8

Altay Kargo giriş ucunda enjeksiyona açık satırı bul.

Zafiyetli satıra tıkla.

SQL enjeksiyonu tek bir teknik değil, sonucu nasıl geri aldığına göre ayrılan bir ailedir. Doğrudan (in-band) türde sonuç aynı yanıtta gelir. Hata tabanlı teknik, veritabanı sürücüsünün ürettiği hata mesajından veriyi sızdırır.

UNION tabanlı teknik ikinci bir sorguyu ilkine ekler ve sonucu doğrudan sayfada gösterir. Çıkarımsal, yani kör (blind) türde uygulama veriyi hiç basmaz; saldırgan koşulu doğru ve yanlış kurup yanıt farkını okur. Boolean tabanlı kör teknik sayfanın içeriğine bakar, zamana dayalı kör teknik ise bir bekleme fonksiyonuyla yanıt süresini ölçer.

Bant dışı (out-of-band) teknik, sonucu ayrı bir kanaldan, örneğin bir DNS sorgusuyla dışarı taşır ve yanıt hiç değişmese bile çalışır. Savunmacı için önemli olan şudur: hata mesajını kapatmak hata tabanlı tekniği zorlaştırır ama kör teknikleri durdurmaz.

Bu türler arasındaki seçim koşullara bağlıdır. Uygulama sürücü hatalarını ekrana basıyorsa hata tabanlı teknik en hızlısıdır; saldırgan bir alt sorguyu bilerek hataya sokar ve veri, hata metninin içinde geri döner. Uygulama hata basmıyor ama içerik koşula göre değişiyorsa boolean tabanlı kör teknik çalışır.

Ne hata ne de içerik değişiyorsa geriye zaman kalır: bir bekleme fonksiyonu koşula bağlanır, yanıt gecikiyorsa koşul doğrudur. Hiçbiri olmuyorsa bant dışı teknik denenir; sorgu, veritabanına saldırganın izlediği bir adrese DNS sorgusu yaptırır ve veri o sorgunun içine gömülü çıkar. Savunma açısından ders açıktır: hata mesajını gizlemek yalnız en gürültülü tekniği kapatır.

Etkinlik 2 / 8

Her belirtiyi ait olduğu SQL enjeksiyonu türüne göre ayır.

Önce bir seçeneğe, sonra aşağıdaki uygun kutuya bas. İstersen seçeneği kutuya sürükleyip bırak. Yerini değiştirmek için aynı işlemi tekrarla.

0/4 seçenek yerleşti.

Adım adım: sütun sayısından veriye

UNION tabanlı teknik iki adım ister. Önce iki sorgunun sütun sayısı eşleşmelidir, yoksa veritabanı sorguyu reddeder. Saldırgan sütun sayısını ORDER BY ile sayar: sıralama numarasını bir artırarak dener, numara sütun sayısını aşınca motor hata verir ve sayı ortaya çıkar. Sonra UNION SELECT ile aynı sayıda sütun ekler ve istediği tabloyu, örneğin personel tablosunun bir alanını ilk sorgunun çıktısına yazdırır.

Aşağıdaki akış her adımın döndürdüğü yanıtı gösterir. Bu adımları yalnız yazılı iznin olan bir hedefte dene.

# Hedef: Altay Kargo test ortamı
GET /urunler?sirala=1     -> 200, liste 1. sütuna göre sıralı
GET /urunler?sirala=7     -> 200, hâlâ geçerli
GET /urunler?sirala=8     -> 500, "ORDER BY position 8 is not in select list"
# 7 sütun var. Şimdi UNION için sütun sayısı eşleşmeli:
GET /urunler?sirala=1 UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL
    -> 500, "each UNION query must have the same number of columns"  (6 sütun denenirse)
GET /urunler?sirala=1 UNION SELECT NULL,NULL,ad,NULL,NULL,NULL,NULL FROM personel
    -> 200, personel adları ürün listesinin içinde görünür
ORDER BY sütun sayısını sayar; UNION SELECT eşit sütunla ikinci tablodan veri çeker. Hata mesajları saldırgana yol gösterir.

UNION SELECT'te sütunları NULL ile doldurmanın nedeni tür uyumudur. İki sorgunun karşılıklı sütunları uyumlu tür taşımalıdır; NULL her türle uyar, bu yüzden saldırgan önce hepsini NULL yapar, sonra veri koyacağı sütunu metne çevirir. Hangi sütunun ekranda göründüğünü de böyle bulur: tek bir sütuna belirgin bir imza yazar ve sayfada hangisinin çıktığına bakar. Bu deneme yanılma, logda art arda gelen ve yalnız bir sütunu değişen UNION sorguları olarak görünür.

Etkinlik 3 / 8

UNION tabanlı bir enjeksiyonda adımları doğru sıraya koy.

Sürükleyip doğru sıraya koy.

Bir öğeye odaklan, yukarı ve aşağı ok tuşlarıyla taşı. Home tuşu en üste, End tuşu en alta alır.

  • 1Hata çıkana kadar denemeyi sürdür, son geçerli numarayı not et
  • 2Hedef tablonun alanını çıktı sütununa yerleştir
  • 3Aynı sütun sayısıyla UNION SELECT yaz
  • 4ORDER BY numarasını artırarak sütun sayısını bul

Bu adımlar elle de, otomatik araçla da yapılır. sqlmap gibi bir araç sütun sayısını, tür tespitini ve veri çekmeyi kendisi dener. Yetkili bir sızma testinde araç şöyle çağrılır: hedef adres verilir, --batch ile soru sormadan çalışır, --technique ile hangi türlerin denendiği sınırlanır, --dbs ile veritabanları listelenir. Aracın kendisi tarafsızdır; onu yetkin olmadığın bir sisteme karşı çalıştırmak suçtur.

Savunmacı için asıl değerli bilgi, aracın nasıl göründüğüdür. Tek uca saniyeler içinde yüzlerce, birbirinden yalnız birkaç karakter farklı istek gelir. Bu tekrar deseni logda insana ait olmayan bir imza bırakır.

# Yetkili sızma testi kapsamında, Altay Kargo test ortamına
sqlmap -u "https://portal.altaykargo.example/urunler?sirala=fiyat" --batch --technique=BU --dbs
# Araç önce parametreyi sınar, injectable ise veritabanlarını listeler.
# Log tarafında: aynı uca art arda yüzlerce ufak varyasyonlu istek.
sqlmap manuel adımları otomatikleştirir. Savunmacı bu yoğun, tekrarlı istek desenini WAF ve SIEM kuralıyla yakalar.

Etkinlik 4 / 8

Bir uca karşı otomatik SQL enjeksiyonu aracı çalıştırıldığında savunmacı loglarda en belirgin ne görür?

Logda SQL enjeksiyonu

SQL enjeksiyonu veritabanı loglarında da kendini belli eder. Normal bir giriş sorgusu sabit bir kalıp izler: aynı yapı, yalnız iki değişken değişir. Enjeksiyon denemesinde sorgu metninin uzunluğu ve içerdiği anahtar kelime aniden değişir; OR, UNION, SELECT ardışık geçer. Veritabanı sunucusunun yavaş sorgu kaydı da ipucu taşır.

Zamana dayalı bir bekleme fonksiyonu içeren bir sorgu, zamana dayalı kör enjeksiyonun imzasıdır ve normal iş mantığında hiç görünmez. Bu yüzden veritabanı sorgu kaydını toplamak ve anahtar kelime örüntülerini bir kuralla izlersen, uygulamadaki açık henüz kapatılmadan saldırıyı görürsün. Bu izlerin neden önemli olduğunu bir gerçek olay gösterir.

2023'te bir dosya transfer ürününde bulunan SQL enjeksiyonu açığı (CVE-2023-34362), kimliği doğrulanmamış saldırganların veritabanına ulaşmasına ve kayıtları okumasına yol açtı; açık geniş çaplı veri sızıntılarıyla sonuçlandı. Olayın ortak dersi hep aynıdır: uygulama açığı kapatılana kadar, veritabanı ve uygulama loglarındaki anormal sorgu deseni çoğu zaman ilk ve tek erken uyarıdır.

Etkinlik 5 / 8

Veritabanı sorgu kaydında enjeksiyon denemesine ait satırları işaretle.

Şüpheli satırlara tıkla. Birden fazla olabilir.

Parametreli sorgu ile kapatmak

Doğru çözüm parametreli sorgudur (prepared statement). Sorgunun iskeleti önce veritabanına gönderilir, kullanıcı verisi ayrı bir kanaldan parametre olarak yollanır. Veritabanı motoru o değeri sorgunun bir parçası değil, aranacak sabit bir veri olarak işler; içindeki tırnak ya da OR kelimesi hiçbir şeyi değiştirmez.

Çoğu dil ve çatı bunu doğrudan destekler: sürücünün parametre listesi kabul eden çalıştırma fonksiyonu, ORM'nin bağlı değişkeni, hazır ifade nesnesi. İlke tektir: sorgunun söz dizimi sabittir, veri onun dışında taşınır. Parametreli sorgunun neden kesin çözüm olduğunu bir kez daha düşün.

Sorgu iki aşamada işlenir: önce iskelet derlenir, veritabanı hangi tabloya ve hangi koşula bakacağını bu aşamada belirler; sonra parametreler yerine oturur. Veri geldiğinde plan çoktan sabittir, hiçbir karakter planı değiştiremez. Metin birleştirmede ise plan, veri de içindeyken kurulur; sınırın kaybolduğu an tam burasıdır.

// Güvensiz: metin birleştirme
sorgu = "SELECT id FROM kullanici WHERE ad='" + ad + "' AND parola='" + parola + "'"
baglanti.execute(sorgu)

// Güvenli: parametreli sorgu
sorgu = "SELECT id FROM kullanici WHERE ad=%s AND parola_ozeti=%s"
baglanti.execute(sorgu, (ad, parola_ozeti))
Parametreli sürümde ad ve parola_ozeti veri olarak gönderilir; sorgunun söz dizimi sabit kalır.

Etkinlik 6 / 8

Parametreli sorguya ' OR '1'='1 değeri ad alanına yazılırsa ne olur?

Önce kodu oku, sonra çıktıyı seç.

sorgu = "SELECT id FROM kullanici WHERE ad=%s AND parola_ozeti=%s"
baglanti.execute(sorgu, (ad, parola_ozeti))

Katmanlı savunma

Parametreli sorgu birincil savunmadır, ama tek katman değildir. Uygulamanın veritabanı hesabı, yalnız ihtiyaç duyduğu tabloya ve işleme yetkili olmalıdır. Giriş ucu yalnız okuma hakkına sahipse, bir enjeksiyon denemesi tabloyu silemez ya da başka bir şemaya sıçrayamaz.

ORM (nesne-ilişki eşleyici) kütüphaneleri de sorguyu kendileri parametreli kurar; yine de ORM'nin ham SQL çalıştıran yardımcı fonksiyonunu dikkatsiz kullanmak aynı açığı geri getirir. Hata mesajlarını kullanıcıya olduğu gibi göstermemek de ayrı bir katmandır; sürücünün ham hatası, tablo ve sütun adlarını saldırgana bedava verir.

En az yetki ilkesini somut düşün. Giriş ucunun kullandığı veritabanı hesabı yalnız kullanıcı tablosunu okuyabiliyorsa, başarılı bir enjeksiyon bile personel tablosuna, ödeme kayıtlarına ya da yönetim şemasına uzanamaz.

Yazma ve silme hakkı ayrı bir hesapta durur. Buna ek olarak saklı yordam (stored procedure) ve görünüm (view), uygulamanın ham tablolara doğrudan değil, sınırlı bir arayüzden erişmesini getirir. Bu katmanlar açığı kapatmaz ama sömürülse bile zararı dar bir alana hapseder.

Etkinlik 7 / 8

Bir ORM kullanan uygulamada geliştirici, arama özelliğini kullanıcı terimini metin birleştirmeyle ham bir SQL yardımcı fonksiyonuna veren bir satırla yazmış. Bu satır için doğru değerlendirme hangisidir?

Aynı ilke arama, filtre ve sıralama uçlarında da geçerlidir. Altay Kargo'nun ürün filtresi, kategori parametresini doğrudan ORDER BY ifadesine ekliyor olsun. Parametreli sorgu burada işe yaramaz, çünkü sütun adı parametre olarak bağlanamaz; tek güvenli çözüm izin verilen sütun adlarının beyaz listesidir.

Kullanıcının seçtiği değer bu listede yoksa istek reddedilir, sorgu hiç kurulmaz. Sütun adı sorgunun iskeletine aittir; parametre yalnız değer alanını bağlar, iskeleti değil. Beyaz liste bu yüzden değer bağlamanın yapamadığı işi yapar.

Etkinlik 8 / 8

Sütun ya da tablo adı gibi parametre olarak bağlanamayan yerlerde tek güvenli çözüm, izin verilen değerleri sen yazdığın bir ____ listesidir.

Derinleş:Neden UNION sütun sayısı ister

UNION, iki sorgunun sonucunu tek bir sonuç kümesinde birleştirir. İlişkisel modelde bir sonuç kümesinin her satırı aynı sütun sayısını ve uyumlu türleri taşımak zorundadır; aksi hâlde tek bir tablo çıkmaz. Bu yüzden veritabanı motoru UNION'ın iki tarafındaki sütun sayısını eşit ister ve eşit değilse sorguyu daha çalıştırmadan reddeder.

PostgreSQL bu durumda each UNION query must have the same number of columns hatasını verir. Saldırganın ORDER BY ile sütun saymasının nedeni de budur: doğru sayıyı bilmeden UNION hiç çalışmaz. Aynı kural savunmacıya bir tespit fırsatı sunar, çünkü art arda artan ORDER BY numaraları ve dolduran NULL dizileri normal iş sorgularında görünmez.

Bu derste bir hata mı gördün? Bildir