PHP渗透测试之五个比较常见的小示例

1,483 阅读2分钟
原文链接: bingyishow.top

前言

在前两篇文章中已经实践过了很多比较常见的漏洞。在这篇文章中将介绍如下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 可绕过命令执行

修复建议:不要让用户可控的内容带入命令执行中

修复代码


普通注入漏洞

简介

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 型注入,差不多的注入方式

修复建议: 对 SQL 拼接时一定要单引号保护,整数型也不例外,并且传入的值要经过 addslashes 函数过滤。不过最好的方案还是用 PDO 预处理

修复代码

$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' 之后会引起宽字节注入漏洞,绕过单引号达到注入效果

修复建议: 字符集编码设置成 utf8

修复代码

$mysqli->query("SET NAMES 'utf8'");