SQL注入系列文章:
初识SQL注入-CSDN博客
目录
技巧1:利用科学计数法注入
技巧2:information_schema数据库被过滤的注入
技巧3:无列名注入
利用 join-using 注列名绕过
利用子查询绕过
当反引号被禁用时,就可以使用起别名的方法来代替
上一篇和大家分享了SQL注入的基础知识和手工注入,自动注入的注入流程,对SQL注入有了基本的了解,在本篇中将会和大家通过复习+练习的方式来一起看一下SQL注入中联合查询的三个技巧,这些也都是周老师课中讲的,我将会在本篇中进行演示三个技巧的使用场景和方法,那么现在就开始啦ヾ(◍°∇°◍)ノ゙
事情的开始还是从一个正则表达式的WAF开始的
当sqli-labs的第一关的后端页面使用下面这样一个正则表达式进行防御后,我们应该怎么应对呢?
if(preg_match('/SELECT\b[\s\S]*\bFROM/is', $id))
{
die('SQL Injection');
}
可以看到这里对我们输入的select 和 from中间增加了一个正则表达式的匹配,如果匹配上了,则就会输出 SQL Injection
可以看到结果是SQL Injection
可以将它放到exrepo - 搜索 (regex101.com)中分析一下:
可以看到想要使用concat来进行查询数据库中的数据,但是被正则表达式匹配上了,无法查询到
现在就需要绕过这个正则表达式才能查询到数据
那么首先就要想办法怎么才能不被该正则表达式匹配上,这里再regex101网站反复的测试后,我发现了只要让select,或者,from字符串不完整了,给它的前后加字符就会逃出正则表达式的匹配
但是还有一个问题就是不管是给select还是from 关键字前后加字符后就语法就会报错,就没有办法查询出数据库中的数据了,因此现在我们要找到一个不影响SELECT 和 from 本身含义,且又不能是select 或者 from的办法,这里龙哥想出了一个好办法,使用科学技术法的方法,给from的前面加上一个科学计数法的值则可以绕过该正则表达式
啥,科学计数法,很多小伙伴和我一样,听到了科学计数法和注入挂钩了,他们两个到底有什么关系呢?
那么我们不妨在网上搜下看mysql是否支持科学计数法
可以看到mysql是支持科学计数法的
那么我们先来在本地的mysql中试试,看是否可以
可以看到在from前面加了一个1e1进行查询的时候居然报错了
可以在前面再加一个,来解决这个问题:
可以看到这样就查询成功了,那么看看这样是否会被正则表达式匹配到:
从结果可以看到,这样确实逃出了正则表达式的限制
那么最后我们在有正则表达式限制的第一关来尝试注入一下:
payload:
-1' union select 1,concat(username,0x3a,password),3 ,1e1from users --+
可以看到这里却说我们的列数不同,这里是因为1e1是独占一列的,因此我们需要将第3列去掉,再来试试看:
payload:
-1' union select 1,concat(username,0x3a,password) ,1e1from users --+
可以看到这样就巧妙的利用科学计数法绕过了该正则表达式的限制
第二个技巧的原因就是我们所利用的information数据库被过滤了,相信看过前面一篇文章的小伙伴都知道,上一篇我就是是通过该数据库来注入出表名,列名的,如果该数据库被过滤掉了,那么应该从何处入手呢?
比如说后端页面增加了下面的限制:
if(preg_match('/information/is', $id)) {
die('SQL Injection');
}
infromation数据库被过滤了,如果我们输入中存在infromation就会被判定为SQL注入,例如:
这里的解决办法其实很简单,那就是不使用inforamtion数据库就可以了,那么到底有那些数据库中还存储着其他 数据库中的各种信息呢?
在 Mysql 5.7 版本中新增了 sys.schema , 基础数据 来自于 performance_schema和information_sche两个库中,其本身并不存储数据。
查询表的统计信息,其中还包括Innodb缓冲池统计信息,默认情况下按照增删改查操作的总表I/O延迟时间(执行时间)降序排序
sys.x$schema_table_statistics_with_buffer
sys.x$schema_table_statistics
sys.x$ps_schema_table_statistics_io
那么来看看这些表都有哪些字段:
可以看到每个表中都有看起来存储数据库和表的字段
但是 需要注意的是这几个表有点局限 需要root 才能访问。
类似的,可以利用的表还有 :
mysql.innodb_table_stats、mysql.innodb_table_index同样存放有库名表名
总结一下,一下数据库或者表均可以代替 information_schema数据库:
sys.schema_auto_increment_columns
sys.schema_table_statistics_with_buffer
mysql.innodb_table_stats
mysql.innodb_table_index
这里可以使用mysql.innodb_table_stats数据库为例来查询一下security数据库中的表:
那么我们再到inforamtion数据库被过滤的第一关尝试进行注入:
id=-1' union select 1,group_concat(table_name),3 from mysql.innodb_table_stats where database_name="security" --+
可以看到成功注入出了security数据库中的所有的表名
但是上面的数据库中最多都只能查找到表名,并没有列名,因此第三个技巧就是需要进行无列名注入的技巧。
相信熟悉mysql数据库的小伙伴一定知道join的作用,通过join 可建立两表之间的内连接,在实际应用中经常会用到join连接
我们就可以使用join来解决上面那些数据库注入出了表名但是没有列名的问题
比如可以使用下面的这种方法来获取第一列的字段名及后面每一列字段名
?id=-1' union select*from (select * from users as a join users as b)as c--+
这里利用的原理就是将两张相同的表连接,将连接的结果给c,查c,数据库就会报错,说我们的id字段重复了,这样我们就知道了id这个字段,如果想要查询别的值可以使用using来去掉我们已知大id,就可以查到除了id以外的值
?id=-1' union select*from (select * from users as a join users b using(id,username))c--+
依次类推,就可以查出所有的字段名,直到完成
?id=-1' union select*from (select * from users as a join users b using(id,username,password))c--+
注:数据库中as作用是起别名,as是可以省略的,为了增加可读性,建议不省略。
select 1,2,3 union select * from users;
无列名注入关键 就是要猜测表里有多少个列,要一一对应上,上面例子是有3个列 1,2,3的作用就是对列起别名,替换为后面无列名注入做准备
这里我们就将列名重命名为了1,2,3,这样我们就不需要知道列名是什么就可以查询出指定例的值
例如:要查询第二列的值,可以使用下面的语句
select `2` from (select 1,2,3 union select * from users)as a;
这里我们是在前面使用的``来查询的
还是查询第二列的值,这里使用起别名的方式
select b from (select 1,2 as b,3 union select * from users)as a;
可以看到这里也可以达到同样的效果
到此,SQL注入联合查询的三个绕过技巧就介绍完毕了,后面还会和大家分享更多的关于SQL注入的技巧和实验(^▽^)