无需“in”的SQL盲注

iso60001  290天前

22.png

为了锻炼安全技术,我在TetCTF上想寻找一些新奇的网络挑战,并注意到一个有趣的系统——“Secure System”。

其中挑战目标是制作一个和SQL盲注有关的payload,并且不使用:

  • UNION … SELECT

  • information_schema

  • “in”和“or”等关键词

尽管还有其他安全过滤,但以上关键词是最难克服的障碍。

33.png

information_schema的替代方法

44.png

我在网上搜索了一下从MySQL数据库中检索表名的替代方法,但没有找到任何可行的方法。所有的技术都依赖于information_schemamysql.innodb_table_stats,但这两者都会被“in”关键词过滤掉。所以,我需要寻找新方法,并在研究了一段时间后成功发现了替代品sys.x$schema_flattened_keys

55.png

在上述示例中,不仅包含一个table_name列,还包含“索引列”。但这不是唯一的方法,还有另一个表sys.schema_table_statistics可显示更多的表:

66.png

通过这种方法和SQL盲注技术,我成功得到了目标表名Th1z_Fack1n_Fl4444g_Tabl3

他人的解决方案

在尝试检索列名的时候,我遇到了不小的困难,尝试了很多方法都不成功。但我发现的表格sys.x$statement_analysis可让我查看其他参与者的解决方案。

77.png

我很好奇是否有人找到了列名,但脚本运行要花费很多时间,所以我只检索上面示例中的内容。这也许能在将来帮我解决其他SQL注入挑战!

在没有列名的情况下检索数据

88.png

如果一个表只包含一列,那么很轻易就可在不知道列名的情况下检索出数据,只需一个简单的SUBSTR((SELECT * FROM table),1,1)='x'就可,但如果一个表包含多个列,那么这个查询就会抛出一个错误。不过这里有个技巧,就是将查询语句与相同数量的列进行比较!

99.png

通过小于号替换等号,你可以逐字符检索出数据。不过还有一个问题——MySQL中的字符串比较在默认情况下是不区分大小写的。

区分大小写

100.png

通过以上方法我可以得到全是小写字母的flag,现在就需要一个区分大小写的方法。我发现将字符串转换为二进制格式后,会强制进行字节对字节的比较,这正是我所需要的。但问题是,BINARY函数中的“in”被过滤掉了。

110.png

此时我注意到,当一个字符串连接一个二进制的值时CONCAT("aa", BINARY("BB")),其得到的也将是二进制。因此我需要找到一个方法,将一个二进制字符串插入CONCAT函数中。

经过反复试验,我终于发现MySQL中的JSON对象是二进制对象,因此,CAST(0 AS JSON)会返回一个二进制字符串,进而SELECT CONCAT(“A”, CAST(0 AS JSON))也会返回一个二进制字符串。

120.png

综合以上改进,我成功地获得了完整的flag,它实际上只含有一个大写字符,但还是花了我几个小时。

TetCTF{0wl_d0nkey_means_Liarrrrrrr}

有趣的挑战和解决方案

这正是我喜欢CTF的地方,一个简单的安全挑战就可以引导出很棒的研究。我不确定我的解决方案是否为最好,但对我来说这是一个伟大的旅程!

此外(关于这个挑战的其他内容),我们一开始希望使用ORD(SUBSTR((SELECT smth),x,1))=77去检索值,但是由于过滤了“or”关键词,ORD被禁止了。不过还是可以通过CONV(HEX(SUBSTR((SELECT ...),x,1)),16,10)=77绕过。以下是Oracle盲注的payload:

130.png

最后根据这些方法和已经检索到的表名,payload如下:

140.png

详细链接点击这里

本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952

最新评论

啥也不会啊  :  没有复现成功,但不知道哪里的问题,希望师傅帮忙解决下,谢谢师傅。第一位没有问题,第二位的时候拼接起来aA0,不是很明白师傅在文中是如何**作,拿到flag的。。。。。mysql> select * from **1 where id=((select 1,concat('aA',cast('0' as json))) <= (select * from **1))+1;+------+------+| id   | name |+------+------+|    1 | aA   |+------+------+1 row in set (0.00 sec)mysql> select * from **1 where id=((select 1,concat('aBB',cast('0' as json))) <= (select * from **1))+1;+------+------+| id   | name |+------+------+|    1 | aA   |+------+------+1 row in set (0.00 sec)mysql> select * from **1 where id=((select 1,concat('aa',cast('0' as json))) <= (select * from **1))+1;+------+------+| id   | name |+------+------+|    1 | aA   |+------+------+1 row in set (0.00 sec)mysql> select * from **1 where id=((select 1,concat('a',cast('0' as json))) <= (select * from **1))+1;Empty set (0.00 sec)mysql> mysql> select * from **1 where id=((select 1,concat('b',cast('0' as json))) <= (select * from **1))+1;+------+------+| id   | name |+------+------+|    1 | aA   |+------+------+1 row in set (0.00 sec)
290天前 回复
啥也不会啊  :  select concat("aA",CAST(0 as JSON))>="aA"; 和 select concat("aa",CAST(0 as JSON))>="aA"; 执行结果都是1,讲道理这俩返回应该有差异才对
290天前 回复
222222  :  如果后面是aA,前面无论大小写都返回0如果后面是aa,前面大小写结果不同
290天前 回复
222222  :  如果后面是aA,前面无论大小写都返回0如果后面是aa,前面大小写结果不同
290天前 回复
啥也不会啊  :  后面是flag 当然要有大小写 假设是aA,所以前面无论大小写都返回一样。 
290天前 回复
昵称
邮箱
提交评论