> For the complete documentation index, see [llms.txt](https://emre-ermenek.gitbook.io/sqli-egitimi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://emre-ermenek.gitbook.io/sqli-egitimi/sql-injection-sqli-egitim-modulu-ve-portswigger/blind-sql-injection.md).

# Blind SQL Injection

In-band SQL Injectiondan farklı olarak, sorgunun sonucu doğrudan ekrana yansıtılmaz. Hata mesajları devre bırakılmış olabilir ancak enjeksiyon hala çalışır. Bu tür saldırılırla çok az geri bildirimle bile veritabanı yapısı keşfedilebilir.

Blind SQL Injection’ın en basit örneklerinden biri Authentication Bypass(Doğrulama Atlama)’da amacımız giriş formu atlatmak veri çalmak değildir, sorgunun sonucunu görmek önemsizdir:

```sql
SELECT * FROM users WHERE username='username' AND password='password' LIMIT 1;
(LIMIT 1) gelen veriyi 1 le limitler, gelen ilk kaydı alır
```

buna basitçe username kısmından `‘ OR 1=1 --` verirsek, sonuç dönmese de başarıyla formu atlatıp ilk kullanıcı kimse onla giriş yapmış oluruz. Genelde de ilk kullanıcı admindir.

***

Blind SQL Injection’ın 2 türü vardır:

1-Boolean-Based Blind SQL Injection

2-Time-Based Blind SQL Injection

***

#### Boolean-Based Blind SQL Injection

Veritabanı görülebilir veri dönmese de, giden sorgudaki true/false koşullarına test edilen sitenin verdiği farklı tepkiler analiz edilerek çıkarım yapılmaya çalışılır.

Peki bu çıkarımı tam olarak nasıl yaparız? Boolean-Based SQL Injection, uygulamanın bize veriyi doğrudan göstermediği, ancak bizim yazdığımız Doğru (True) veya Yanlış (False) SQL koşullarına **farklı tepkiler** verdiği bir türdür. Bu saldırı türü sunucu tarafında sessizce gerçekleşir. Ancak saldırgan, geçerli (doğru) veya geçersiz (yanlış) isteklerin tetiklediği sayfa içeriğindeki ince farklılıkları (örneğin değişen HTML elementlerini, mesajları veya durum kodlarını) yakalayarak veritabanıyla konuşmanın bir yolunu bulur.

**Evet/Hayır Oyunu (Mantık Nasıl Çalışır?)**

Buradaki anlatım bu blogdaki örneği takip ediyor, okumanızı tavsiye ederim:<https://medium.com/@YousefAlotaibi/disclaimer-1699f46cb1a0> Diyelim ki bir sitenin "Şifremi Unuttum" sayfasındayız. Sisteme kayıtlı, doğru bir e-posta adresi girdiğimizde ekranda *"Şifre sıfırlama linki gönderildi"* yazıyor. Sisteme kayıtlı olmayan, yanlış bir e-posta girdiğimizde ise *"Böyle bir kullanıcı bulunamadı"* yanıtını alıyoruz.

> **Hacker Dokunuşu:** Eğer kayıtlı bir mail adresi bilmiyorsak, arama kutusuna `' OR 1=1 --` yazarak her zaman Doğru (True) dönecek bir koşul yaratırız. Eğer ekranda *"Şifre sıfırlama linki gönderildi"* yazısını görürsek, hem sistemde SQL Injection olduğunu kanıtlarız hem de uygulamanın "Doğru" cevabını nasıl verdiğini öğrenmiş oluruz.

Artık elimizde çalışan bir Doğru (True) ve Yanlış (False) mekanizması var. Sorgunun içine sızıp şu iki mantıksal ifadeyi gönderdiğimizi düşünün:

* `' AND 1=1 --` *(Her zaman Doğru/True Koşul)*
* `' AND 1=2 --` *(Her zaman Yanlış/False Koşul)*

Eğer `1=1` (Doğru) gönderdiğimizde sayfa normal çalışıyor ama `1=2` (Yanlış) gönderdiğimizde sayfadaki bir yazı kayboluyor, tasarım bozuluyor veya tepki değişiyorsa, orada kesinlikle bir zafiyet var demektir.

**Doğru Soruları Sormak** Yani veritabanı sorduğumuz soruları anlıyor ve bize Doğru/Yanlış diyerek yanıt veriyor. Bu test sonucunda artık yapmamız gereken tek şey **doğru soruları** sormaktır.

Örneğin, ekranda göremediğimiz o `administrator` şifresini çalmak için şu sorguyu göndeririz: `' AND (SELECT SUBSTRING(password, 1, 1) FROM users WHERE username='administrator') = 'a' --`

Veritabanı bunu şöyle okur: *"Bana şifrenin 1. harfini getir. Bak bakalım bu harf 'a' mı?"*

* **Eğer şifrenin ilk harfi gerçekten 'a' ise:** Koşul Doğru (True) olur. Sayfa normal yüklenir (Örn: "Şifre sıfırlama linki gönderildi" yazar). Biz de *"Aha! İlk harf 'a' imiş!"* deriz.
* **Eğer ilk harf 'a' değilse:** Koşul Yanlış (False) olur. Sayfa bozulur veya hata verir (Örn: "Kullanıcı bulunamadı" yazar). Biz de *"Tamam, 'a' değilmiş, o zaman 'b' harfini deneyeyim"* deriz.

İşte bu yöntemle, veritabanına "20 Soru" oynar gibi sorular sorarak veriyi harf harf (bit by bit) çekeriz ve sistemi exploit ederiz! Tabii ki binlerce harfi tek tek elimizle denemeyeceğiz; bunu bizim yerimize otomatize edecek harika araçları (SQLMap gibi) yazının ilerleyen kısımlarında göreceğiz.

**Alternatif "Hayır" Cevapları (Şartlı Hatalar - Conditional Errors):**

Bazen sistem "Yanlış (False)" bir sorgu gönderdiğimizde sayfada hiçbir şeyi değiştirmez. Böyle durumlarda veritabanını, koşul yanlış olduğunda **kasıtlı olarak hata vermeye** (örneğin sıfıra bölme işlemi yaptırarak) zorlarız. Eğer sayfa normal yükleniyorsa koşul "Doğru", sayfa `*500 Internal Server Error`\* veriyorsa koşul "Yanlış" demektir. Çözeceğiniz 2. Lab tam olarak bu mantık üzerine kuruludur.

***

#### Time-Based Blind SQL Injection

Boolean-Based metoda benzerdir farkı doğru yanlış bildirim almak yerine sorgunun çalıştırılma süresi izlenir. Eğer sorgu başarıyla yürütülürse veritabanı bir süre uyutulur(sleep). Böylece sorgunun başarılı olup olmadığını zaman gecikmesiyle anlarız.

**Temel Mantık:**

→ SLEEP(x) fonksiyonu ile x saniyelik gecikme oluşturulur.

→ Bu gecikme sadece sorgu doğruysa çalışır.

→ Geri dönüş süresi uzun sürerse sorgu başarılı, kısa sürerse sorgu başarısızdır.

**(Dikkat:** Burada kullandığımız `SLEEP()` fonksiyonu **MySQL**'e özgüdür. Hedef sistem **PostgreSQL** ise `pg_sleep()`, **MSSQL** ise `WAITFOR DELAY '0:0:5'`, **Oracle** ise `dbms_pipe.receive_message` gibi farklı geciktirme komutları kullanmanız gerekir. Kör (Blind) saldırılarda hangi veritabanında olduğunuzu bilmek tek pusulanızdır.**)**

#### Adım Adım Time-Based Sömürü Süreci

Diyelim ki bir web sitesinde arka planda çalışan bir referrer (yönlendirme) veya bir kullanıcı adı (cookie) kontrolü var. Sisteme ne gönderirsek gönderelim ekranda hiçbir hata veya farklılık olmuyor. Ancak elimizde bir kronometre var ve veritabanının `SLEEP()` komutuna tepki verip vermediğini izleyeceğiz.

Bu yöntemin en büyük avantajı, UNION saldırılarındaki gibi **sütun sayısı bulmakla uğraşmak zorunda olmamamızdır.** Sorguyu direkt mevcut sistemin içine `AND` veya `OR` ile enjekte edebiliriz.

*(Not: Çözeceğiniz PortSwigger Time-Based labları veritabanı olarak PostgreSQL kullanır. Bu yüzden aşağıdaki örneklerin mantığını MySQL'deki `SLEEP(5)` ile anlatsak da, lablarda `pg_sleep(5)` kullanmanız gerekeceğini unutmayın.)*

**Adım 1: Zafiyeti Doğrulamak (Sistemi Uyutmak)** Önce karmaşık sorular sormadan sistemi sadece uyutmayı deneriz. "Eğer 1=1 ise (ki her zaman öyledir), 5 saniye bekle" deriz.

```sql
admin123' AND (SELECT CASE WHEN (1=1) THEN SLEEP(5) ELSE SLEEP(0) END) = 0--
```

**Sonuç:** Sayfa 5 saniye geç yüklendi. Harika, veritabanı komutumuzu dinliyor ve sistemde kesinlikle Time-Based SQL Injection var.

**Adım 2: Veritabanı Adını Bulmak** Zafiyeti doğruladığımıza göre artık "20 Soru" oyununa başlayabiliriz. "Eğer veritabanı adı 'a' ile başlıyorsa uyu, başlamıyorsa uyuma" mantığını kuruyoruz.

```sql
admin123' AND (SELECT CASE WHEN (database() LIKE 'a%') THEN SLEEP(5) ELSE SLEEP(0) END) = 0--
-- (Sayfa anında yüklendi, demek ki 'a' ile başlamıyor)

admin123' AND (SELECT CASE WHEN (database() LIKE 'u%') THEN SLEEP(5) ELSE SLEEP(0) END) = 0--
-- (Sayfa 5 saniye gecikti!)
```

**Sonuç:** 5 saniyelik gecikmeyi yakaladık! Veritabanı adı kesinlikle 'u' harfiyle başlıyor. Bu mantıkla harf harf giderek veritabanı adını (örneğin `users_db`) buluruz.

**Adım 3: Tablo ve Sütunları Bulmak** Veritabanlarında sistemdeki tüm tablo ve sütun isimlerinin tutulduğu rehberin `information_schema` olduğunu öğrenmiştik. Şimdi `CASE WHEN` koşulumuzun içine bu rehberi yerleştirip tablo adını harf harf arıyoruz. (Not: Alt sorguların tek bir değer döndürmesi için `LIMIT 1` eklemek önemlidir).

**Tablo adını bulmak:**

```sql
admin123' AND (SELECT CASE WHEN ((SELECT table_name FROM information_schema.tables WHERE table_schema='users_db' LIMIT 1) LIKE 'u%') THEN SLEEP(5) ELSE SLEEP(0) END) = 0--
```

*Sonuç: 5 Saniye gecikme. Tablo adı 'u' ile başlıyor. Tek tek deneyerek `users` tablosunu buluruz.*

**Sütun adlarını bulmak:** Aynı mantıkla `information_schema.columns` üzerinden sütun ararız ve `username` ile `password` sütunlarını keşfederiz.

**Adım 4: Veriyi Çekmek** Artık yapıyı anladık; tablomuz `users`, sütunlarımız ise `username` ve `password`. Sıra geldi asıl ganimeti, yani administrator şifresini harf harf sızdırmaya:

```sql
admin123' AND (SELECT CASE WHEN ((SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator') = 'a') THEN SLEEP(5) ELSE SLEEP(0) END) = 0--
-- (Sayfa anında yüklendi, ilk harf 'a' değil)

admin123' AND (SELECT CASE WHEN ((SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator') = '3') THEN SLEEP(5) ELSE SLEEP(0) END) = 0--
-- (Sayfa 5 saniye gecikti!)
```

**Sonuç:** Sayfa geç yüklendiğine göre admin şifresinin ilk karakteri "3" tür. Bu işlemi tekrarlayarak şifrenin geri kalanını karakter karakter ortaya çıkarırız.

**Özetle:** Time-Based (Zaman Tabanlı) saldırılar, her harf için saniyelerce beklememiz gerektiği için Boolean-Based saldırılara göre daha yavaştır. Ancak geri bildirim sıfır olsa bile, sadece zaman ölçerek tüm veritabanını adım adım keşfedebilmemizi sağlayan bir tekniktir.

***

Şimdi sırada Out-of-band SQL Injection var ama geçmeden portswiggerdan aşağıdaki labları çözmenizi istiyorum. Takıldığınız yerde çözümlere bakabilirsiniz. Çözerken portswigger’ın hazırladığı SQLi cheatsheeti de kullanmanızı tavsiye ederim: <https://portswigger.net/web-security/sql-injection/cheat-sheet>

Şu sırayla çözebilirsiniz:

1- Lab: <https://portswigger.net/web-security/sql-injection/blind/lab-conditional-responses>

{% content-ref url="/pages/ZXViXFFoN5AZOdNhK0tr" %}
[Blind SQL injection with conditional responses Çözümü](/sqli-egitimi/sql-injection-sqli-egitim-modulu-ve-portswigger/blind-sql-injection/blind-sql-injection-with-conditional-responses-cozumu.md)
{% endcontent-ref %}

***

2- Lab: <https://portswigger.net/web-security/sql-injection/blind/lab-conditional-errors>

{% content-ref url="/pages/5jlIcl1qeCyF7mBucOgb" %}
[Blind SQL injection with conditional errors Çözümü](/sqli-egitimi/sql-injection-sqli-egitim-modulu-ve-portswigger/blind-sql-injection/blind-sql-injection-with-conditional-errors-cozumu.md)
{% endcontent-ref %}

***

3- Lab: <https://portswigger.net/web-security/sql-injection/blind/lab-time-delays>

{% content-ref url="/pages/vW25sc9fT0tjM5rT3Pmx" %}
[Blind SQL injection with time delays Çözümü](/sqli-egitimi/sql-injection-sqli-egitim-modulu-ve-portswigger/blind-sql-injection/blind-sql-injection-with-time-delays-cozumu.md)
{% endcontent-ref %}

***

4- Lab: <https://portswigger.net/web-security/sql-injection/blind/lab-time-delays-info-retrieval>

{% content-ref url="/pages/lU43Ypcj4HYJOZIpUEF8" %}
[Blind SQL injection with time delays and information retrieval Çözümü](/sqli-egitimi/sql-injection-sqli-egitim-modulu-ve-portswigger/blind-sql-injection/blind-sql-injection-with-time-delays-and-information-retrieval-cozumu.md)
{% endcontent-ref %}
