漏洞分析之Typecho二连爆

本文作者:Ph0rse,根据其之前的文章数量,奖励其 80 元以资鼓励,希望再接再厉。

这段时间 Typecho 在十几天之内连续爆了两个最高可 getshell 的洞,先是 SSRF 可打内网,再是反序列化直接前台 getshell ……安全性这方面堪忧……

跟着师傅们的文章,简单地分析一下这两次漏洞,第二个反序列化的洞的溯源思路值得学习一波~

虽然很多大号都分析过这个漏洞,写的也很详细,我作为一个初学者自己分析学习一下也是很有必要的,官方人员已经对这些漏洞进行的及时的修补并且推出了最新的版本,如果有用到这个博客的同学赶紧升级。

Typecho 1.0 (14.10.10) —— SSRF 可打内网


0x01 漏洞原理

首先是显示了 “源地址服务器错误” 的报错,经过全局搜索发现报错是位于 var/Widget/XmlRpc.php 的 2046 行的 pingbackPing 函数

调用了 get 方法,如果失败则返回 “源地址服务器错误” 的报错,我们跟进 get 方法看一下,大致意思是调用实例化 var/Typecho/Http/Adapter/ 目录下的 Typecho_Http_Client_Adapter_Curl 类和 Typecho_Http_Client_Adapter_Socket 类,分别位于 Curl.php 和 Socket.php 文件中。如果 Curl 存在就使用 Curl 的 curl_setopt 函数打开资源,否则使用 Socket 的 fsockopen 函数打开资源,这两种方式都是打开资源的一种方式?

一般来说 Curl 都是存在的,所以我们继续回到 var/Widget/XmlRpc.php 的 2046 行的 pingbackPing 函数,向下看:

$http->setTimeout(5)->send($source);

直接在 Curl.php 和 Sockt.php 中是找不到 send 函数的, send 函数是在这两个类继承的 Typecho_Http_Client_Adapter 类中在 var/Typecho/Http/Client/Adapter.php 中的第 300 行可以看到 send 函数:

第 338 行,$response = $this->httpSend($url); 调用了本类的 httpSend 函数,转向 var/Typecho/Http/Client/Adapter/Curl.php 中第 41 行开始,一直到 51 行,都没有对传入的 url 进行检测,到 51 行后:

于是一个 SSRF 漏洞产生了

0x02 漏洞利用

这里还是跟着 JoyChou 表哥的思路

我们先看一下业务的逻辑,位于 var/Widget/XmlRpc.php 的 2046 行的 pingbackPing 函数:

如果实例化类失败,返回 '源地址服务器错误',如果探测成功,并且返回码为 200 则返回 '源地址不支持 PingBack ' ,如果探测成功,但返回码不是 200 ,则返回 '源地址服务器错误'

所以我们探测端口主要就是通过返回码 200 这个地方。

利用一:端口检测

根据回显的不同,检测端口是否开启

payload:

curl "https://目标IP/action/xmlrpc" -d '<methodCall><methodName>pingback.ping</methodName><params><param><value><string>http://127.0.0.1:2222</string></value></param><param><value><string>joychou</string></value></param></params></methodCall>'

如果端口开启,则返回 “源地址不支持 PingBack ” ,如果端口没有开启,则返回 “源地址服务器错误”

利用二:攻击Redis

利用 Redis 默认空密码的特性,直接打内网,一般大站才会用 Redis

Typecho20171013前台 Getshell


一处反序列化导致的任意函数执行(可以执行代码和命令),据说是后门,因为找不到这出反序列化的用处

0x01 测试环境

Typecho-1.1-15.5.12-bete PHP-5.5.9 Apache 2.4.7 Ubuntu

0x02 漏洞原理

这是一个反序列化的漏洞

先引用 Th1s 师傅的一段话:

反序列化漏洞的利用有两个条件: ① 进行反序列化的字符串可控 ② 有可利用的pop链

首先看反序列化的可控字符串来源

发生在程序根目录下 install.php 的第 229 行

很突兀的一端代码(这也是被认为是后门的原因),直接接收 cookie 里的 __config 参数,然后进行 base64 解码进行反序列化

同时我们需要满足一些条件才可以控制数据,在 59 - 77 行

即传入 get 的 finish ,令 finish=1 即可,然后传入 Referer 为同源的地址

接下来寻找可利用的 pop 链

敏感的魔术方法(当满足某些条件时会自动调用)有:

进行全局搜索,发现在 var/Typecho/Db.php 中 Typecho_Db 类的第 120 行,__construct 方法中

$adapterName = 'Typecho_Db_Adapter_' . $adapterName;

存在拼接,那如果传入的 $adapterName 为对象的话就会调用 __toString 魔术方法,所以现在寻找有哪些类实现了 __toString 方法,并可以利用。可以用法师的代码审计工具,或者 Sublime 进行全局搜索关键字 __toString 。

var/Typecho/Feed.php 中的 Typecho_Feed 类中实现了 __toString 方法

在290行:

$content .= 'dc:creator' . htmlspecialchars($item['author']->screenName) . '/dc:creator' . self::EOL;

__get方法会在调用私有属性的时候自动执行,如果 $item['author'] 是一个对象,则访问它的 screenName 属性,这个时候要注意,如果screenName 是 $item['author'] 代表的类中的私有属性,那么就会调用 __get方法;

接下来全局搜索 __get 方法

var/Typecho/Request.php 中 Typecho_Request 类的 __get 方法如下:

226 行

跟进到 295 行

跟进 $this->_applyFilter($value) 到 159 行

其中有一个 call_user_func($filter, $value);

就可以执行任意函数了

0x02 漏洞利用

看了很多 POC,发现 Th1s 师傅的思路是最精简的,仿照思路,自己写了一个:

将生成的 payload 复制下来

然后直接访问:

http://【被攻击的网站】/install.php?finish=1

抓包添加:

Referer: http://45.32.90.22:666/admin/

添加 cookie 中 __typecho_config=【payload】

发过去,就能成功写 shell 了

回显 500 是因为反序列化执行完毕之后,再执行到后面参数不符合DB方法中要求,所以报 500 ,但木马已经写入

如果我们想让数据回显呢?也是有办法的,在反序列化之前执行了 ob_start ,开启了缓存区,而在反序列化之后把缓存区清零了,也就没有了输出;然而,如果我们在反序列化的过程中让 php 报错,就会终止脚本的执行,然后直接将缓存区的东西输出出来,这一点 LR 师傅的文章:

https://paper.tuisec.win/detail/68ea208985e5c7a.jsp

写的很详细,调用了不存在的 ['name'] 导致报错,然后把 payload 中的 phpinfo() 信息爆了出来.

0x03 漏洞复现

已经在我的 DockerHub 仓库:

https://hub.docker.com/r/ph0rse/typecho_17_10/)

中发布了,欢迎来 pull ,使用说明在仓库界面。

个人作品展

CTF初识与深入

SQL注入的常规思路及奇葩技巧

Mysql注入导图-学习篇

Windows下优雅地书写MarkDown

【作者投稿】奇葩webshell技巧

【作者投稿】一道反序列化CTF引起的思考

【作者投稿】PHP代码审计-sprintf函数中的安全问题

个人简介

ID:Ph0rse ,

博客:Ph0rse.me

目前就读于成都信息工程大学( CUIT )实验班道格小组成员 …… 嗨呀,和上一个作者好多一样的地方 …… 不过我比他帅,嘿嘿,我俩是很好的朋友。

我的安全之路说起来还真有一点鸡汤的感觉:

进入大学之前,完全没接触过安全,唯一一次用外挂,还中毒了 …… 那时候重装电脑都不会 ……

暑期的时候学习了修改 Hosts 文件翻墙,那时候感觉自己吊炸天……进了 CUIT 之后就各种被虐,大佬太多了,尤其是当看到那些比你优秀的人还比你更努力的时候,很受打击。不过,或许是有一种所谓的信念在内心吧,高考的时候已经输给了 985/211 ,不能再输了。于是就开始我的死磕之路,大一上死磕 C 语言和汇编,感觉自己应该是属于那种真的没有天赋的人,学了半年什么都不会,脱个壳都脱不好。然后大一寒假的时候,由道格的学长指导,转了入门稍微容易一点的 Web 方向,开始了第二次、也是更认真的一次死磕,然后我进入了安全这个世界,后天性地找到了自己的兴趣,后面的事情就很顺利了,加入小组、校赛拿奖(学长带飞)、考入实验班、人生第一个 CVE ,四处投稿,广结基友~就到了今天。

之前遇到问题就想放弃,现在遇到问题,我知道,解决它,只是时间问题。

看看一年前头痛无比的比赛题目(极客大挑战),现在无论是逆向还是渗透,大部分都可以秒了。

之前有人和我说,安全领域的大牛都是野路子,必须要有天赋才能在这行混下去。我不这么认为,所谓天赋,不过是经验的积累加上正确的方式罢了。一次不行我就 N 次,然后不断总结错误和正确的思路,不断优化自己的 “天赋“,这才是安全之路的真谛。

一路走来,才发现自己仍在起点,如果说我悟到了什么,那就是“行百里者,都靠死磕”。

原文发布于微信公众号 - 信安之路(xazlsec)

原文发表时间:2017-10-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏逍遥剑客的游戏开发

GameEngineArchitecture读书笔记(二)

16750
来自专栏web前端教室

前端开发就是这样,“看似简单的东西,反而会很复杂。”

今天的零基础前端课讲到了一个tab地址切换的菜单,就下面这个东西, ? 第一眼看起来超级简单,无非是点击上面的title显示下面的菜单,然后点省市区把内容选上去...

22760
来自专栏编程

Pwnhub 第一次线下沙龙竞赛Web题解析

Pwnhub在8月12日举办了第一次线下沙龙,我也出了两道Web相关的题目,其中涉及好几个知识点,这里说一下。 # 《国家保卫者》 国家保卫者是一道MISC题目...

20580
来自专栏deed博客

day01笔记

17450
来自专栏Golang语言社区

golang websocket总结(问题贴)

因为工作的需要,接触了websocket,开始的一些很简单的代码,都不知道该怎样运行起来,所以,总是有一层神秘感,却没有太多的兴趣去研究它。不过,还是免不了要了...

31530
来自专栏ChaMd5安全团队

zctf web100的简单分析

zctf web100的简单分析 From ChaMd5安全团队核心成员 Pcat web100 xctf2017第二站的zctf,web100的链接点开之后...

375150
来自专栏cloudskyme

linux内存查看方式

如下显示free是显示的当前内存的使用,-m的意思是M字节来显示内容.我们来一起看看. $ free -m total ...

53740
来自专栏杨建荣的学习笔记

初探Redis

大概在2010年的时候,有一次和一个同事聊天,那个时候知道了Redis,对于技术的追随至今,还没有下载一个Redis版本玩玩, 只有1万多行代码,以性...

45290
来自专栏微服务生态

Akka简单的性能测试

这种方案是采用MQ作为中间的媒介,在服务端采用线程池异步处理任务,处理完成之后将结果发送到MQ中,客户端采用侦听的方式得到结果继续进行处理。

20210
来自专栏非典型技术宅

Swift多线程之Operation:按优先级加载图片1. 进程和线程2. Operation3. Basic Demo4. 案例实现

15330

扫码关注云+社区

领取腾讯云代金券