top of page

SQL Injection (SQLi) — Notlarım

Yazarın fotoğrafı: Songül ÖZÜGÜRLER
Songül ÖZÜGÜRLER
28 Nis
6 dakikada okunur

SQL Injection (SQLi) — Notlarım

SQL Injection (SQLi) — Notlarım

SQLi , uygulamanın veritabanına attığı SQL sorgusuna kullanıcı girdisi üzerinden müdahale edebilmen demek. Sonuç: Normalde göremeyeceğin veriyi görürsün, hatta bazı durumlarda veri değiştirme/silme ve daha ileri compromise mümkün.

Etkisi (impact)

Yetkisiz veri erişimi: şifreler, kart bilgileri, kişisel veriler

Veri bütünlüğü bozulur: update/delete ile kalıcı hasar

İş sürekliliği riski: DoS’e kadar gidebilir

Kurumsal tokat: itibar kaybı + regülasyon cezaları + uzun süre fark edilmeyen backdoor ihtimali

2) SQLi nasıl tespit edilir? (manual test mantığı)

Her giriş noktasında sistematik denersin. Mantık: “Ben bunu değiştirince uygulamanın cevabı tutarlı şekilde değişiyor mu?”

Klasik test seti

' (tek tırnak) → SQL hatası / anomali var mı?

“base value” ve “different value” üreten SQL syntax → response farkı var mı?

Boolean denemeler: OR 1=1 vs OR 1=2 → sayfa/sonuç farkı?

Time-based payload → yanıt süresi farkı?

OAST payload → dışarıya DNS/HTTP etkileşimi var mı? (Burp Collaborator

Pratik bakış: Hata , içerik farkı , süre farkı , out-of-band sinyal = 4 ana “sensör”.

3) SQLi sorgunun neresinde olur?

Çoğu kişi WHERE’e takılı kalır ama SQLi her yerde çıkabilir:

WHERE (SELECT’in klasiği)

UPDATE (set edilen değerlerde / WHERE’de)

INSERT (insert edilen değerlerde)

SELECT içinde table/column name

ORDER BY içinde

Bu ayrım önemli çünkü her konumda aynı teknik çalışmaz.

4) SQLi örnek “senaryoları” (hangi saldırı tipi neye yarar?)

Hidden data retrieval : normalde gizli olan kayıtları görünür yapmak

Logic subversion : login bypass gibi, uygulama mantığını kırmak

UNION attack : başka tablolardan veri çekmek

Blind SQLi : sonuç/hatayı göremesen bile veri sızdırmak

5) Hidden data retrieval mantığı (WHERE + comment)

Uygulama şunu yapıyor gibi düşün:

category='Gifts' AND released=1 → sadece yayınlananlar

Sen girdiyle sorgunun kalanını “yorum satırı” yapınca released=1 devre dışı kalabiliyor. Bu sınıfın özeti: filtreyi etkisizleştir → daha fazla kayıt dönsün.

OR 1=1 gibi şeyler bazen masum görünür ama aynı input başka sorguya (UPDATE/DELETE) taşınırsa, “kazara kıyamet” çıkabilir.

6) Login bypass (uygulama mantığını sabote etme)

Login sorgusu:

username='wiener' AND password='bluecheese'

Sen password kısmını devre dışı bırakacak şekilde WHERE’i kırarsan, parolasız giriş mümkün olur. Bu sınıfın özeti: AND password kontrolünü etkisizleştir .

7) UNION Attacks (görünür sonuç varsa en tatlısı)

Uygulama response içinde SQL sonucunu gösteriyorsa UNION ile başka SELECT ekleyebilirsin.

UNION için 2 şart

Kolon sayısı aynı olmalı

Kolon tipleri uyumlu olmalı (string ↔ string vs)

(A) Kolon sayısını bulma

İki yöntem:

Yöntem 1: ORDER BY index

ORDER BY 1 , ORDER BY 2 … hata verene kadar artır Hata aldığın yer “limitin aşıldığı” yerdir.

Yöntem 2: UNION SELECT NULL,…

UNION SELECT NULL

UNION SELECT NULL,NULL

UNION SELECT NULL,NULL,NULL … Hata kesildiği anda kolon sayısını yakalamış olursun.

DB notu:

Oracle’da SELECT ... FROM dual gerekir (dual diye built-in tablo var)

MySQL’de -- yorumunun çalışması için çoğu zaman sonra boşluk gerekir; # da comment olabilir.

(B) String taşıyabilen kolonu bulma

Kolonlara sırayla 'a' koyup hangisi patlamıyor bakarsın. Patlamıyorsa o kolon text uyumlu .

İlginç veriyi çekme

Kolon sayısı + text kolon(lar) bulundu mu:

kullanıcı adı/şifre gibi hedef alanları uygun kolonlara map edersin.

Tek kolonda çok değer (concat)

Bazen sayfa sadece 1 kolon basar. O zaman username ~ password gibi birleştirirsin. Concat operatörü DB’ye göre değişir (Oracle: || , bazıları farklı).

8) Database’i “tanıma” (enum mantığı)

SQL standart gibi dursa da DB’ler farklı:

string concat

comment

stacked queries

error mesaj formatları

DB tipi & versiyon

MySQL / MSSQL: @@version

PostgreSQL: version()

Oracle: v$version

Bu sorgulardan hangisi çalışıyor → DB tipi hakkında sinyal verir.

Tablo/kolon listeleme

Çoğu DB: information_schema.tables ve information_schema.columns

Oracle: all_tables ve all_tab_columns

Bu bölümün özeti: Önce şema bilgisi → sonra doğru tablo/kolon adlarıyla veri çekme.

9) SQLi “farklı context’lerde”

SQLi sadece query string değil:

JSON body

XML body

cookie

header

Bazı WAF filtreleri keyword arar; input farklı formatta olunca encoding/escaping ile bypass denenebilir. Örnek: XML entity ile SELECT’in bir harfini encode etmek gibi.

10) Blind SQL Injection (sonuç yoksa “dedektiflik” başlar)

Blind SQLi : response içinde ne query sonucu var, ne de DB hatası.

Burada 3 ana yaklaşım var:

10.1 Conditional responses (boolean-based)

Sayfada “Welcome back” gibi fark edilebilir bir davranış varsa:

Koşul doğruysa mesaj var

Yanlışsa mesaj yok Buradan tek tek karakter çıkarırsın (SUBSTRING/SUBSTR ile).

Özet: True/False → UI farkı → bit bit veri .

10.2 Error-based (conditional error veya verbose errors)

İki alt tip:

A) Conditional error ile çıkarım Koşul doğruysa hata üret (divide-by-zero gibi), yanlışsa üretme. Response farkı = koşulun cevabı.

B) Verbose error ile veri sızdırma Bazı DB’ler hatayı fazla konuşur. CAST ile “string’i int’e çevir” deyip hatada o stringi görebilirsin. Özet: Hata mesajı = data taşıyıcısı .

10.3 Time-based

Uygulama hata yakalıyorsa ve response farkı yoksa:

Koşul doğruysa sleep/delay

yanlışsa normal dön MSSQL örneği: WAITFOR DELAY mantığı.

Özet: Süre farkı = True/False .

10.4 Out-of-band (OAST)

Asenkron query / response farkı yok / time da zor → en güçlü seçenek. DB’den senin kontrolündeki domaine DNS/HTTP isteği attırırsın (Burp Collaborator). Hatta bazı senaryolarda veriyi subdomain içine gömüp direkt exfil yaparsın.

Özet: Uygulama sessizse, DB’yi konuştur: dışarı trafik .

11) Second-order SQLi (stored SQLi)

First-order: Input gelir → aynı request’te sorguya girer → patlar. Second-order: Input güvenli kaydedilir gibi görünür → sonra başka bir yerde tekrar kullanılırken SQL’e gömülür → patlar.

Özet: “Bunu daha önce DB’ye güvenli yazdım” rehaveti = klasik dev hatası.

12) SQLi nasıl önlenir? (gerçek çözüm)

Altın kural: Parameterized queries / Prepared statements

String birleştirme ile query kurma = risk. Prepared statement ile input data olarak gider, query yapısını bozamaz.

Parametrizasyonun yetmediği yerler

Tablo adı / kolon adı / ORDER BY gibi “query yapısı” parçaları parametrelenemez. Burada yaklaşım:

Whitelist (izinli değer listesi)

veya bambaşka bir mantıkla feature’ı tasarlamak

Ek not (çok kritik)

“Bazı input trusted ya” diye concatenation’a geri dönme. Bug’ların çoğu bu “case-by-case güven” saflığından çıkıyor.

Flashcard gibi son tekrar

UNION çalışması için şartlar? → kolon sayısı aynı + tip uyumu

Blind SQLi’de 3 sinyal? → content farkı / error farkı / time farkı / (bonus: OAST)

DB enum niye önemli? → DB tipi + tablo/kolon adları = hedef veriye giden yol

En sağlam önlem? → prepared statements

SQL Injection Checklist

Temel Tanım & Etki

- ☐ SQLi = Kullanıcı girdisiyle SQL sorgusunun yapısını bozabilme

- ☐ Yetkisiz veri okuma (password, PII, kart bilgisi)

- ☐ Veri değiştirme / silme (UPDATE, DELETE)

- ☐ Auth bypass / privilege escalation

- ☐ Uzun vadeli compromise, DoS ihtimali

SQLi Tespit (Manual Test)

Her input için aşağıdakiler denenir:

- ☐ ' → hata / anomali var mı?

- ☐ Base value vs farklı value → response farkı?

- ☐ Boolean test:

- ☐ OR 1=1

- ☐ OR 1=2

- ☐ Time-based payload → response süresi farkı?

- ☐ OAST payload → DNS / HTTP etkileşimi?

Sinyaller: Content farkı | Error farkı | Time farkı | Out-of-band trafik

SQLi Nerelerde Olur?

- ☐ SELECT → WHERE

- ☐ UPDATE → SET / WHERE

- ☐ INSERT → VALUES

- ☐ SELECT → table adı / column adı

- ☐ ORDER BY

Klasik SQLi Senaryoları

- ☐ Hidden data retrieval (filtre bypass)

- ☐ Login bypass (password check öldürme)

- ☐ UNION ile başka tablodan veri çekme

- ☐ Blind SQLi (sonuç görünmüyorsa)

Database Enum (Tanıma)

DB Tipi & Versiyon

- ☐ MySQL / MSSQL → @@version

- ☐ PostgreSQL → version()

- ☐ Oracle → v$version

Tablo & Kolonlar

- ☐ information_schema.tables

- ☐ information_schema.columns

- ☐ Oracle için:

- ☐ all_tables

- ☐ all_tab_columns

UNION Attacks (Visible SQLi)

Ön Koşullar

- ☐ Kolon sayısı aynı

- ☐ Kolon tipleri uyumlu

Kolon Sayısı Bulma

- ☐ ORDER BY 1,2,3…

- ☐ UNION SELECT NULL,…

String Kolon Bulma

- ☐ 'a' → hata vermeyen kolon(lar)

Veri Çekme

- ☐ username , password , vs.

- ☐ Tek kolon varsa → concat kullan

DB farkları:

- ☐ Oracle → FROM dual

- ☐ MySQL → -- (boşluk şart) / #

Blind SQL Injection

Boolean-Based

- ☐ True/False → sayfa davranışı farkı

- ☐ SUBSTRING / SUBSTR ile karakter karakter çıkarım

Error-Based

- ☐ Conditional error (CASE + divide by zero)

- ☐ Verbose error (CAST ile data’yı hataya taşıma)

Time-Based

- ☐ Koşul true → delay

- ☐ Süre farkından true/false çıkarımı

Out-of-Band (OAST)

- ☐ DNS / HTTP isteği tetikleniyor mu?

- ☐ Veriyi subdomain içine gömerek exfil mümkün mü?

Second-Order SQLi

- ☐ Input önce DB’ye güvenli gibi yazılıyor

- ☐ Sonra başka request’te query’ye girip patlıyor

Farklı Context’ler

- ☐ Query string

- ☐ POST body

- ☐ JSON

- ☐ XML (encoding ile bypass)

- ☐ Cookie / Header

Önleme (Savunma Tarafı)

- ☐ Prepared / Parameterized Queries

- ☐ String concatenation YOK

- ☐ Table / column / ORDER BY için:

- ☐ Whitelist

- ☐ Alternatif iş mantığı

- ☐ “Trusted input” varsayımı YAPMA

Son Kontrol Soruları

- ☐ UNION neden çalışmıyor? → kolon sayısı / tip uyumu

- ☐ Blind SQLi’de veri nasıl çıkar? → boolean / error / time / OAST

- ☐ En sağlam önlem ne? → Prepared statements

 
 
bottom of page