一、前言

打CTF时翻到的一篇文章,反正CTF不会做,正好就记录一下(我太菜了555)

链接:

第一篇

第二篇

首先给本次SQL注入的payload加上了一些条件:

  • 不能出现in或者or等关键词
  • 不能出现information_schema
  • 不能使用union ... select

我测试使用的mysql版本为:5.7.26

二、information_schema

直奔主题吧,还有哪些表可以用?

  • sys.x$schema_flattened_keys,数据库字段为table_schema,表字段为table_name
  • sys.schema_table_statistics,字段名同上,比上面的表数据更多
  • mysql.innodb_table_stats,数据库字段database_name,表字段table_name
  • mysql.innodb_index_stats,同上,显示的比上面多,不过这两个表在这不能用了

sys.x$statement_analysis这个表会保留执行过的SQL语句

三、无字段名注入

重点在这,找到可以用的表后,因为不知道字段名,所以采用这个方法

大概的思路就是:

假如这个表只有一列,那么直接substr((select * from example),1,1)='a'就行了

但是多列多条记录的情况下就会报错,所以这里有个技巧,通过比较来确定字符,假设有两列,那么:

select (0,0) <= (select * from example limit 0,1)

因为一般存在数据库中的都是数字、字母,所以先用0来判断列数,有些字符比0还要小,需要注意

这样就能一个个字符的比较出来了,但是在mysql中是不区分大小写的,可能在CTF中flag存在大小写

这里又是一个小技巧,将字母转换为二进制,这样mysql会按位进行比较

select (0,binary('A')) <= (select * from example limit 0,1)

但是因为过滤了in,所以binary()不能使用

但是mysql中json对象是二进制对象,所以cast(0 as json)会返回一个二进制字符串

select (0,concat('A',cast(0 as json)) <= (select * from example limit 0,1)

因为是一个字符一个字符进行比较的,所以大小写就可以比较出来了

注意点

1、假如example表中的数据为('!','t!S!')

那么上面的例子中,本质上比较的就是(0,'A0') <= ('!','t!S!')

但是我们需要比较的是第二个字段,由于!比0小,这就变成永真了

所以一开始最好将比较的字符设置为最小的空格(' ','A0')

2、假如表中的数据为('!','t!S!')

由于我们连接的二进制字符串总会加上一个0,例如A0

但是我们比较的是第一位A,所以我们不知道0比较的情况

例如(' ','t0') <= ('!','t!S!'),这时结果为0

(' ','t!0') <= ('!','t!S!') 这时结果为1

可以看到第二个例子和我们想要的不一样,所以在特殊情况下,会出现一个字符的偏差

所以在0的位置我们需要加上一个比较大的字符或者比较小的字符,来使我们想要的结果一致

例如:

select (' ',concat('A~',cast(0 as json)) <= (select * from example limit 0,1)

select (' ',concat('A ',cast(0 as json)) <= (select * from example limit 0,1)

这样就不会出现结果不相同的情况了