本文最后更新于 2024-07-26,文章内容可能已经过时。

PHP代码审计——熊海CMS审计实战

免责声明
⚠特别说明:此教程为纯技术教学!严禁利用本教程所提到的漏洞和技术进行非法攻击,本教程的目的仅仅作为学习,
决不是为那些怀有不良动机的人提供技术支持!也不承担因为技术被滥用所产生的连带责任!⚠

熊海CMS系统简介:

熊海CMS是由php语言,熊海开发的一款可广泛应用于个人博客,个人网站,企业网站的一套网站综合管理系统。作为一个早期的系统,里面代码存在许多漏洞利用点,且代码量低适合作为代码审计的入门挑战,本文就带领大家对该系统存在的漏洞进行分析。

搭建环境:

本人使用xmapp在本机搭建,使用的是Mysql版本10.1.38-MariaDB(Mysql5.0)

将源码和安装文件放在xmapp安装目录下的xampp\htdocs目录下

使用xmapp开启Mysql和Apache环境。

image-20240717130251322

提前建好对应数据库(我这里是xhcms)

sql语句导入文件在源码的这个目录下:\xhcms\install\seacms.sql

导入后数据库表结构如下:

image-20240717125426337

访问安装界面并安装即可。

image-20240717130840055

image-20240717130902446

系统首页:http://localhost/xhcms/index.php

image-20240717125642340

管理员页面的url:http://localhost/xhcms/admin/?r=login

管理员账户:admin 密码:138653

image-20240717125703464

源码文件:

image-20240717125932801

文件基本结构

——admin //后台⽂件
——css //css⽂件
——files //功能函数⽂件
——images //图⽚
——index.php //主⽬录⽂件
——install //安装⽂件
——seacmseditor //编辑器
——template //模板⽂件
——upload //⽂件上传⽬录

代码审计流程:

将源码导入seay审计系统,并开始审计

image-20240717142527291

首先自动扫描一波

image-20240717142924138

发现34个漏洞。但是只能做个参考,手动检查后挑几个重要的进行分析,分析内容如下

一、SQL注入

漏洞概要
类目 内容 备注
漏洞位置 /admin/files/editoolumn.php
漏洞类型 SQL注入(报错注入)
严重性
主要危害 SQL注入泄露数据库信息
其他信息
漏洞详情

\xhcms\admin\files\editcolumn.php

image-20240720101451060

image-20240720101501602

源代码这里

参数全是get和post传参

if ($type==1){
$query = "SELECT * FROM nav WHERE id='$id'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$nav = mysql_fetch_array($resul);
}
if ($type==2){
$query = "SELECT * FROM navclass WHERE id='$id'";
$resul = mysql_query($query) or die('SQL语句有误:'.mysql_error());
$nav = mysql_fetch_array($resul);

直接打印出来了mysql的报错信息,导致能执行sql报错注入。

漏洞验证

http://localhost/xhcms/admin/?r=columnlist

后台管理页面-》栏目管理

image-20240720103510883

排序哪里添加单引号,修改保存,出现mysql报错信息

image-20240720103619874

构造payload获取当前数据库名字,成功实现报错注入

1' and updatexml(1,concat(0x7e,database(),0x7e),1)--+#

image-20240720103841201

#爆出表名字
1' and updatexml(1,concat(0x7e,(select(group_concat(table_name))from information_schema.tables where table_schema=database()),0x7e),1)--+#

image-20240720104856734

#爆出列名
1' and updatexml(1,concat(0x7e,(select(group_concat(column_name))from information_schema.columns where table_name=database()),0x7e),1)--+#

image-20240720105203027

#爆出数据
1' and updatexml(1,concat(0x7e,(select(group_concat(date))from xhcms.adword),0x7e),1)--+#

image-20240720110025232

修复建议
  1. 使用参数化查询:使用预处理语句和绑定参数的方式来执行 SQL 查询,确保用户输入的数据不会被直接拼接到 SQL 查询语句中,从而避免 SQL 注入攻击。
  2. 过滤和验证输入:对用户输入的数据进行适当的过滤和验证,确保输入符合预期的格式和范围,可以使用过滤函数或正则表达式来验证输入数据。
  3. 不要在页面中写出mysql的报错信息。

二、文件包含

漏洞概要
类目 内容 备注
漏洞位置 http://localhost/xhcms/index.php
漏洞类型 文件包含
严重性
主要危害 文件包含敏感信息文件
其他信息
漏洞详情

\xhcms\index.php

image-20240717144659101

源代码index.php中文件包含函数中存在变量,存在文件包含漏洞。

$_GET['r']能直接接受用户输入的内容

include()函数可以包含指定文件,include('files/'.$action.'.php');这里file变量能接受第四行GET方法传递的参数‘r’,参数值‘r’没有进行过滤处理,所以导致文件包含漏洞产生。

$action=$file==''?'index':$file;这段代码意思是 如果file的值为空action就等于index否则等于 $file变量

漏洞验证

准备一个PHP文件,写入如下的payload:

<?php phpinfo();?>

放入网站根目录

image-20240717145703241

浏览器访问,成功获取到phpinfo信息

image-20240717145824197

修复建议

在包含文件之前,应该对 $action 变量进行验证,确保只包含预期的文件,可以使用白名单机制或者限制文件路径等方式来增强安全性。

此外,代码中使用了 error_reporting(0) 关闭了错误显示,这样会导致在出现错误时无法及时发现问题并进行调试,不利于代码的健壮性和可维护性。应该修改成E_ALL

以下是修复的代码:

<?php
// 单一入口模式
error_reporting(E_ALL); // 设置错误报告级别为显示所有错误

$allowed_files = ['index', 'about', 'contact']; // 允许包含的文件列表

$file = isset(\$_GET['r']) ? addslashes(\$_GET['r']) : ''; // 接收文件名
$action = in_array(\$file, \$allowed_files) ? \$file : 'index'; // 判断是否在允许的文件列表中,否则默认为index

include('files/' . \$action . '.php'); // 载入相应文件
?>

三、XSS

XSS反射型——1

漏洞概要
类目 内容 备注
漏洞位置 http://localhost/xhcms/seacmseditor/php/controller.php
X漏洞类型 XSS(反射型)
严重性 中危
主要危害 可获取到用户敏感信息,如Cookie;钓鱼攻击等
其他信息
漏洞详情

\xhcms\seacmseditor\php\controller.php

image-20240717162455789

可以看到源码中使用了 $_GET["callback"]这参数直接进行拼接输出到echo语句中,导致可以使用XSS攻击,存在被恶意用户利用进行跨站脚本攻击(XSS)的风险。

漏洞验证

访问浏览器页面:

http://localhost/xhcms/seacmseditor/php/controller.php?callback=123

image-20240717164248599

页面回显,\u8bf7\u6c42\u5730\u5740\u51fa\u9519

是使用 Unicode 编码的中文。解码后,它的含义是 "请求地址出错"。

说明代码进入到了第41行这里,说明文件可以写入

image-20240717164348824

写入一个payload进行尝试

<script>alert('XSS')</script>

image-20240717171039445没有写入成功 因为代码中 preg_match("/^[\w_]+$/"正则过滤掉了<>这些符号,导致执行到下面去被Unicode 转码了

修复建议

修复建议是对 $_GET["callback"] 参数进行合适的过滤和验证,可以使用正则表达式或其他方法确保参数的安全性。另外,建议在输出时使用适当的转义函数来防止XSS攻击。

以下是修复后的代码:

/* 输出结果 */
if (isset(\$_GET["callback"])) {
    if (preg_match("/^[\\w_]+$/", \$_GET["callback"])) {
        \$callback = htmlspecialchars(\$_GET["callback"]);
        echo \$callback . '(' . \$result . ')';
    } else {
        echo json_encode(array(
            'state'=> 'callback参数不合法'
        ));
    }
} else {
    echo \$result;
}

在修复后的代码中,对 ​_GET["callback"] 参数进行了 htmlspecialchars() 处理,确保输出的安全性。同时,将处理后的参数赋值给 callback 变量,然后再输出到页面上,有效防止了XSS攻击的风险。

XSS反射型——2

漏洞概要
类目 内容 备注
漏洞位置 http://localhost/xhcms/index.php?r=contact
X漏洞类型 XSS(反射型)
严重性 中危
主要危害 XSS攻击可获取到用户敏感信息,如Cookie
其他信息
漏洞详情

\xhcms\files\content.php

53行,59行使用了 addslashes()函数,防止 SQL 注入

image-20240720111810106

但是139行这里直接使用$page进行拼接导致出现了反射型XSS

image-20240720111604751

漏洞验证

页面中输入如下url验证

http://localhost/xhcms/index.php?r=contact&page=<img src=1 onerror=alert(/xss/)>

image-20240720111340340

修复建议
  1. 输入验证和过滤:对用户输入的数据进行严格的验证和过滤,确保输入数据符合预期的格式和范围。可以使用白名单过滤来只允许特定的字符或格式通过验证。

  2. 输出编码:在将用户输入数据输出到网页上时,确保对数据进行适当的编码,以防止恶意脚本被执行。可以使用 HTML编码、JavaScript编码等方式对输出内容进行转义处理,

    可以将代码修复成如下

    $page = htmlspecialchars($_GET['page'], ENT_QUOTES, 'UTF-8');
    

    htmlspecialchars函数将特殊字符转换为HTML实体,确保用户输入的内容不会被当做HTML代码执行。这样可以有效防止XSS漏洞的利用。

  3. CSP(内容安全策略):通过设置内容安全策略(CSP),限制页面加载的资源来源,防止恶意脚本的执行。可以通过 CSP 头部来指定允许加载的资源来源,从而减少 XSS 攻击的可能性。

  4. HttpOnly 标记:对于敏感的 Cookie,可以设置 HttpOnly 标记,防止 JavaScript 脚本访问这些 Cookie,减少 XSS 攻击的影响范围。

XSS存储型

漏洞概要
类目 内容 备注
漏洞位置 http://localhost/xhcms/admin/?r=manageinfo
X漏洞类型 XSS存储型
严重性
主要危害 XSS存储到数据库中,与数据库进行交互,盗取用户Cookie
其他信息
漏洞详情

漏洞源码位置

\admin\files\manageinfo.php

image-20240717181213342

可以看到源码中是直接使用POST进行传参,参数没有进行过滤,直接与数据库进行交互,导致出现储存型XSS漏洞。

漏洞利用

在资料修改页面

http://localhost/xhcms/admin/?r=manageinfo

名称输入框中输入如下payload:

<script>alert(/reflect_xss/)</script>

image-20240717181955624

image-20240717181919324

修复建议

确保输入的名称和密码都经过验证

使用 htmlspecialchars函数对输出进行转义,避免存储型XSS攻击。

四、后台登录绕过(垂直越权)

漏洞概要
类目 内容 备注
漏洞位置 http://localhost/xhcms/admin/?r=login
漏洞类型 越权漏洞
严重性 严重
主要危害 不需要密码直接登录管理员后台页面
其他信息
漏洞详情

\xhcms\inc\checklogin.php

image-20240717172533243

在checklogin.php这里发现了,控制后台登录逻辑的代码,在 cookie 中寻找到 user 的值,若 user 为空,则跳转到登录页面。但是这个 $user 没有在数据库中查找,只要Cookie的user值不为空不需要密码就能登录成功,抓包将user的cookie值设置成admin,即可跳转管理员界面。

漏洞验证

浏览器访问后台登录页面

image-20240717172052049

抓包修改cookie值为admin1,返回登录成功

image-20240717174640585

http://localhost/xhcms/admin/?r=index

image-20240717174204702

修复建议

将$user值添加SQL查询语句,如果没有这个用户就拒绝登录,限制严格的登录条件。

五、CSRF

漏洞概述
类目 内容 备注
漏洞位置 http://localhost/xhcms/admin/?r=wzlist
漏洞类型 CSRF
严高重性
主要危害 跨站请求伪造漏洞,攻击者可以通过恶意url发送给受害者伪造管理员进行登录或者修改
其他信息
漏洞详情

/admin/files/wzlist.php

image-20240717185033837

可以看到这里没有对输入进行验证:没有对用户输入的 delete 参数进行验证,没有进行验证,同时存在SQL注入,这里略过SQL注入,只说CSRF

漏洞利用

页面进行一下delete操作,使用burp抓包后查看

image-20240717185927350

image-20240717190010183

构造payload:

http://localhost/xhcms/admin/?r=wzlist&delete=17

换个浏览器,url输入访问这个payload,并抓包修改Cookie出的user值为admin

image-20240717190425828

发现CSRF攻击成功,执行了管理员的操作。

image-20240717190525979

修复建议

CSRF漏洞通常发生在恶意网站利用用户在已登录的受信任网站的身份执行未经授权的操作

如删除操作,应该采取一些预防措施来防止 CSRF 攻击。可以通过在表单中添加随机生成的 token,并在后端验证 token 的方式来防止 CSRF 攻击。这样可以确保请求是从合法的来源发起的,而不是恶意网站。

六、文件下载

漏洞概述
类目 内容 备注
漏洞位置 http://localhost/xhcms/admin/?r=manageinfo
漏洞类型 任意文件下载
严重性
主要危害 可下载任意文件读取敏感文件
其他信息
漏洞详情

\xhcms\admin\files\newsoft.php

image-20240717195011072

image-20240717193855899

通过editsoft的发布下载功能中设置该服务器的任意文件路径,可以通过前端页面进行下载。导致服务器的敏感文件泄露

漏洞利用

在后台页面修改内容管理,下载列表中修改文件地址。保存退出

image-20240717194221162

访问前台页面,下载一

image-20240717194409555

image-20240717194441287

image-20240717194621852

修改文件后缀名为txt文件,打开查看,发现是下载的指定的源码文件index.php

image-20240717194610611

修复建议
  1. 文件类型检查:在下载文件之前,首先要确保用户只能下载特定类型的文件,而不是任意文件。可以通过检查文件的扩展名或 MIME 类型来验证文件类型。
  2. 文件路径验证:在构建文件下载路径时,不要直接使用用户提供的文件名或路径,而是应该使用一个白名单机制,只允许下载指定目录下的文件。
  3. 权限控制:确保用户有权限下载所请求的文件。在验证文件路径时,还应该检查用户是否有权限访问该文件。
  4. 下载链接过期时间:为下载链接设置过期时间,确保用户不能无限期地下载文件。一旦链接过期,用户将无法再次下载文件。
  5. 安全的文件存储:确保下载的文件存储在安全的位置,防止恶意用户进行

测试总结及建议

本次渗透测试未对系统做出任何更改,上传的测试shell已删除。本次测试给出的主要综合建议如下:

1、对用户传入的参数进行严格过滤

2、对登录次数做限制,防止密码爆破

3、严格判断包含中的参数是否外部可控,因为文件包含漏洞利用成功与否的关键点就在于被包含的文件是否可被外部控制;

4、路径限制:限制被包含的文件只能在某一文件内,一定要禁止目录跳转字符,如:"../"

5、尽量不要使用动态包含,可以在需要包含的页面固定写好,如:include('head.php')。

6、对输入(和 URL 参数)进行过滤,对输出进行编码。

7、鉴权,服务端对请求的数据和当前用户身份做校验;

8、代码层最佳防御 sql 漏洞方案:采用 sql 语句预编译和绑定变量,是防御 sql 注入的最佳方法。