前言
在前两篇文章中已经实践过了很多比较常见的漏洞。在这篇文章中将介绍如下5个漏洞的示例:preg_replace 漏洞、回调漏洞、命令执行漏洞、普通注入漏洞、宽字节注入漏洞。
preg_replace 漏洞
简介
preg_replace /e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法
的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。
漏洞代码1
<?php
echo preg_replace("/test/e",$_GET["h"],"jutst test");
?>
漏洞代码2
<?php
function test($str)
{
}
echo preg_replace("/s*[php](.+?)[/php]s*/ies", 'test("\1")', $_GET["h"]);
?>
修复建议: 避免使用 /e 模式,第一、二个参数不让用户可控。第二个参数单引号改成双引号分析:语法不当的情况下,会导致代码执行漏洞。
修复代码
echo preg_replace("/s*[php](.+?)[/php]s*/ies", "test('\1')", $_GET["h"]);
回调漏洞
简介
在 PHP 一些回调函数中,如果函数输入可控,可以利用回调 assert 等方法进行命令执行漏洞
漏洞代码1
<?php
call_user_func($_REQUEST['fun'], $_REQUEST['pass']);
?>
漏洞代码2
<?php
array_map($_REQUEST['fun'], $_REQUEST['pass']);
?>
- 分析:在 fun 传递可控的情况下,会引起代码执行漏洞
修复代码
array_map('addslashes', $_REQUEST['pass']);
命令执行漏洞
简介
exec 、 system 、 shell_exec 、 passthru 等命令执行函数,在传入的命令过滤不严,可导致任意命令执行漏洞,危及服务器。
漏洞代码1
<?php
$url = $_GET['url'];
$content = system("curl $url");
echo $content;
?>
- 分析:直接将可控内容带入命令执行中,导致产生漏洞
漏洞代码2
<?php
if(isset($_REQUEST[ 'ip' ])) {
$target = trim($_REQUEST[ 'ip' ]);
$substitutions = array(
'&' => '',
';' => '',
'|' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
$cmd = shell_exec( 'ping -c 4 ' . $target );
echo $target;
echo "<pre>{$cmd}</pre>";
}
?>
- 分析:虽然进行了一些过滤,但是过滤不严, %0a 可绕过命令执行
修复代码
- 可以参考这里:www.freebuf.com/articles/we…
普通注入漏洞
简介
SQL 注入是攻击者通过把恶意 SQL 命令插入到 Web 表单的输入域或页面请求的查询字符串中,来达到欺骗服务器执行恶意的 SQL 命令的一种攻击方式
漏洞代码1
<?php
$mysqli = new mysqli('localhost', 'root', 'root', 'code');// 数据库连接
$id = !empty($_GET['id']) ? $_GET['id'] : '1';
$data = $mysqli->query("select content from test where id=$id");
if($data->num_rows !== '0')
{
$arr = $data->fetch_all();
foreach($arr as $a)
{
echo ' 内容: '.$a[0].'<br>';
}
}
?>
- 分析:对于传入的内容未过滤,且 SQL 拼接的时候没有单引号保护
修复代码
$id = !empty($_GET['id']) ? addslashes($_GET['id']) : '1';
$data = $mysqli->query("select content from test where id='$id'");
漏洞代码2
<?php
$mysqli = new mysqli('localhost', 'root', 'root', 'code');// 数据库连接
$id = !empty($_GET['id']) ? $_GET['id'] : '1';
$data = $mysqli->query("select content from test where id='$id'");
if($data->num_rows !== '0')
{
$arr = $data->fetch_all();
foreach($arr as $a)
{
echo ' 内容: '.$a[0].'<br>';
}
}
?>
- 分析:即使使用了单引号保护,但是传入内容未过滤,导致 SQL 注入
代码漏洞3
<?php
$mysqli = new mysqli('localhost', 'root', 'root', 'code');// 数据库连接
if(!empty($_POST['content']))
{
$name = $_POST['name'];
$content = $_POST['content'];
if($mysqli->query("insert into test (content)values('$name','$content')"))
{
echo ' 发言成功 ';
}else{
echo ' 发言失败 ';
}
}
?>
- 分析:insert 型注入,差不多的注入方式
修复代码
$name = addslashes($_POST['name']);
$content = addslashes($_POST['content']);
if($mysqli->query("insert into test (content)values('$name','$content')"))
宽字节注入漏洞
简介
宽字节注入发生的位置就是 PHP 发送请求到 MYSQL 时字符集使用 charactersetclient 设置值进行了一次编码
漏洞代码
<?php
$mysqli = new mysqli('localhost', 'root', 'root', 'code');// 数据库连接
$id = !empty($_GET['id']) ? addslashes($_GET['id']) : '1';
$mysqli->query("SET NAMES 'gbk'");
$data = $mysqli->query("select content from test where id='$id'");
if($data->num_rows !== '0')
{
$arr = $data->fetch_all();
foreach($arr as $a)
{
echo ' 内容: '.$a[0].'<br>';
}
}
?>
- 分析:执行 SET NAMES 'gbk' 之后会引起宽字节注入漏洞,绕过单引号达到注入效果
修复代码
$mysqli->query("SET NAMES 'utf8'");