目录

Fragrans 的个人博客

记录精彩的程序人生

代码审计之某企业网站管理系统

1、部署源码

1.1 系统简介

某企业网站管理系统 Company Content Management System

某企业网站管理系统是一款基于php+mysql+samrty的免费开源建站系统。

1.2 部署

1)使用phpstudy进行网站部署。

2)网站界面如下:image.png

3、漏洞审计之sql注入

1)index.html部分代码(已添加说明注释)

<?php
if(!file_exists('includes/install.lock')){  //判断是否存在install.lock文件
header("location:install/index.php");exit;
}
define('xsd', true);
define('root',dirname(__file__));  //定义常量root,通过dirname(_file_)获取当前文件所在目录的绝对路径,_file_表示当前文件
session_start();
require_once(root.'/includes/db_class.php');
require_once(root.'/includes/config.php');
require_once(root.'/includes/function.php');
require_once(root.'/includes/page_class.php');
require_once(root.'/includes/comm.php'); //检查文件是否被包含过,如果被包含过,则不会运行,报错显示详细信息

$bid = (isset($_GET["bid"]) && ereg("^[0-9]+$", $_GET["bid"])) ? $_GET["bid"]: 0;
$cid = (isset($_GET["cid"]) && ereg("^[0-9]+$", $_GET["cid"])) ? $_GET["cid"]: 0;
$did = (isset($_GET["did"]) && ereg("^[0-9]+$", $_GET["did"])) ? $_GET["did"]: 0;
$setpage = (isset($_GET["setpage"]) && ereg("^[0-9]+$", $_GET["setpage"])) ? $_GET["setpage"]: 0;
$setid = (isset($_GET["setid"]) && ereg("^[0-9]+$", $_GET["setid"])) ? $_GET["setid"]: 0;//正则匹配,只匹配0-9内的数字

if (isset($_GET["action"]))
{
	if (in_array($_GET["action"], array("0","1","2","3","5","6",'7'))){ 

		switch ($_GET["action"])
		{
		case 0:
			//单页图文
			include_once(root.'/includes/single_page.php');
			break;

		case 1:
			//新闻列表
			include_once(root.'/includes/news_page.php');
			break;
		case 2:
			//产品列表
			include_once(root.'/includes/products_page.php');
			break;
		case 3:
			//客户反馈
			include_once(root.'/includes/feedback_page.php');
			break;
		case 5:
			//新闻详细
			include_once(root.'/includes/news_page_show.php');
			break;
		case 6:
			//产品详细
			include_once(root.'/includes/products_page_show.php');
			break;
		case 7:
			//搜索
			include_once(root.'/includes/search.php');
			break;
		}
	}else{
	die("参数出错");
	}

}

else{

		if (@$_SESSION["l"]==1){
		$showurl = "index_en.html";
		}else{
		$showurl = "index.html";
		}
	}

if(!file_exists(root."/templete/".templete_url."/".$showurl))die(templete_url."/".$showurl."此模版文件不存在"); //检查模版文件是否存在
$smarty->display($showurl); //显示模板


?>

分析index.php中参数有bid、cid、did,参数传入都已做过正则处理,不存在sql注入。可以看到引入的includes文件中包含文件comm.php。

2)查看comm.php中代码,如果打开了magic_quotes_gpc,那么传过来的值会自动addslashes()。

<?php
/*
* 通用函数库
* @Copyright (c) 2009.02 新生代软件
* @author feng QQ:13019489 <@link [url]http://www.37241.net[/url]>
* @name comm.php 
*/

//php解码javascript的escape
function unescape($str) 
{ 
         $str = rawurldecode($str); 
         preg_match_all("/%u.{4}|&#x.{4};|&#d+;|.+/U",$str,$r); 
         $sar = $r[0]; 
         foreach($sar as $k=>$v)
         { 
                  if(substr($v,0,2) == "%u") 
                           $sar[$k] = iconv("UCS-2","GBK",pack("H4",substr($v,-4))); 
                  elseif(substr($v,0,3) == "&#x") 
                           $sar[$k] = iconv("UCS-2","GBK",pack("H4",substr($v,3,-1))); 
                  elseif(substr($v,0,2) == "&#")
                           $sar[$k] = iconv("UCS-2","GBK",pack("n",substr($v,2,-1))); 
         } 
         return join("",$sar); 
}
function safe($str)
{
if (get_magic_quotes_gpc()) {
return $str;
} else {
return addslashes($str);
}
}

if (!get_magic_quotes_gpc())  //如果打开了magic_quotes_gpc,那么传过来的值会自动addslashes()。
{
    if (!empty($_GET))
    {
        $_GET  = addslashes_deep($_GET);
    }
    if (!empty($_POST))
    {
        $_POST = addslashes_deep($_POST);
    }

    $_COOKIE   = addslashes_deep($_COOKIE);
    $_REQUEST  = addslashes_deep($_REQUEST);
}

function addslashes_deep($value)
{
    if (empty($value))
    {
        return $value;
    }
    else
    {
        return is_array($value) ? array_map('addslashes_deep', $value) : addslashes($value);
    }
}


?>

说明:打开magic_quotes_gpc来防止SQL注入

SQL注入是非常危险的问题,小则网站后台被入侵,重则整个服务器沦陷,

所以一定要小心。php.ini中有一个设置:

magic_quotes_gpc = Off

这个默认是关闭的,如果它打开后将自动把用户提交对sql的查询进行转换,

比如把 ' 转为 '等,这对防止sql注射有重大作用。所以我们推荐设置为:

magic_quotes_gpc = On

虽然国内很多PHP程序员仍在依靠addslashes防止SQL注入,还是建议大家加强中文防止SQL注入的检查。addslashes的问题在于黑客可以用0xbf27来代替单引号,而addslashes只是将0xbf27修改为0xbf5c27,成为一个有效的多字节字符,其中的0xbf5c仍会被看作是单引号,所以addslashes无法成功拦截。

当然addslashes也不是毫无用处,它是用于单字节字符串的处理,多字节字符还是用mysql_real_escape_string吧。

另外对于php手册中get_magic_quotes_gpc的举例:
if (!get_magic_quotes_gpc()) {

$lastname = addslashes($_POST[‘lastname’]);

} else {

$lastname = $_POST[‘lastname’];

}

最好对magic_quotes_gpc已经开放的情况下,还是对$_POST[’lastname’]进行检查一下。

再说下mysql_real_escape_string和mysql_escape_string这2个函数的区别:

mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用。否则只能用 mysql_escape_string ,两者的区别是:mysql_real_escape_string 考虑到连接的

当前字符集,而mysql_escape_string 不考虑。

总结一下:

  • addslashes() 是强行加\;
  • mysql_real_escape_string() 会判断字符集,但是对PHP版本有要求;
  • mysql_escape_string不考虑连接的当前字符集。

示例:PHP addslashes() 函数

clipboard.png
image.png

3)审计save.php页面(客户反馈功能)

审计save.php页面,发现在留言提交时,分析代码可以看到,变量abc的值是由text’.$rs[“id”].'的值拼接特殊符号|@;而来,由于使用post方法提交,且未做sql过滤,而且开头文件并未包含comm.php.故此处可以拼接sql语句导致sql注入。

<?php
require_once(dirname(__file__).'/db_class.php');
require_once(dirname(__file__).'/config.php');
function ar($str){
if (is_array($str)){
	foreach($str as $key1=>$value1){ 
	 $a.=$str[$key1]." ";
	}
}else{
$a=$str;
}
return $a;
}
$bid = intval($_GET["bid"]);
$title = $_POST["title"];
$riqi = date("Y-n-j G:i:s");
$title1 ='';
$text1  ='';
$text2  ='';
$abc = '';
$que=$db->query("select * from xsd_feedback_set where bid = '$bid'  ORDER BY rootid");
while($rs=$db->fetch_array($que)){
$text1	='$abc.=ar($_POST["text'.$rs["id"].'"])."|@";';//此处eval()中参数使用单引号,不存在代码执行漏洞
eval ($text1);
}

foreach($title as $key=>$value)
{ 
$title1	.= htmlspecialchars($title[$key])."|@";
}
$qu=$db->query("insert into xsd_feedback set title = '$title1',content = '$abc',bid = '$bid',riqi='$riqi'");//
//此处存在注入点$abc,由于使用post方法提交,且未做sql过滤,而且开头文件并未包含comm.php.故此处可以拼接sql语句导致sql注入。
if ($qu){
echo "<script language='javascript'>alert('提交成功')</script>";
echo"<script language='javascript'>history.back(-1)</script>";
}else{
echo "<script language='javascript'>alert('提交失败')</script>";
echo"<script language='javascript'>history.back(-1)</script>";
}

?>

$text1 ='text1=′$abc.=ar($_POST["text'.POST["text′.$rs["id"].'"])."|@";';

image.png

4)渗透测试复现sql注入:

4.1.访问页面

clipboard.png

4.2.使用burp抓包,使用工具sqlmap。发现sql注入

clipboard.png

4.3.数据库中数据表的存储结构(数据存储都放在content字段中):clipboard.png


标题:代码审计之某企业网站管理系统
作者:Fragrans
地址:http://gsolo.xhtk.top/articles/2021/07/01/1625107573990.html