DASCTF X GFCTF 2024

是赛后复现(难甭

Web

Cool_index

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import express from "express";
import jwt from "jsonwebtoken";
import cookieParser from "cookie-parser";
import crypto from "crypto";
const FLAG = process.env.DASFLAG || "DASCTF{fake_flag}";
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use(express.static("static"));
app.set("view engine", "ejs");

const JWT_SECRET = crypto.randomBytes(64).toString("hex");

const articles = [
{
line1: "我还是在这里 我还是",
line2: "如约而至地出现了"
},
{
line1: "你们有成为更好的自己吗",
line2: "真的吗 那可太好了"
},
{
line1: "你知道吗 我经常说",
line2: "把更多的时间花在 CTF 上(?)"
},
{
line1: "这是一种信念感",
line2: "就像我出来那给你们"
},
{
line1: "我也希望你们能把更多时间花在热爱的事情上",
line2: "我是一个特别固执的人"
},
{
line1: "我从来不会在意别人跟我说什么",
line2: "让我去做以及怎么做 我不管"
},
{
line1: "如果 你也可以像我一样",
line2: "那我觉得 这件事情"
},
{
line1: "欢迎参加 DASCTF x GFCTF 2024!",
line2: FLAG,
},
];

app.get("/", (req, res) => {
const token = req.cookies.token;
if (token) {
try {
const decoded = jwt.verify(token, JWT_SECRET);
res.render("home", {
username: decoded.username,
subscription: decoded.subscription,
articles: articles,
});
} catch (error) {
res.clearCookie("token");
res.redirect("/register");
}
} else {
res.redirect("/register");
}
});

app.get("/register", (req, res) => {
res.render("register");
});

app.post("/register", (req, res) => {
const { username, voucher } = req.body;
if (typeof username === "string" && (!voucher || typeof voucher === "string")) {
const subscription = (voucher === FLAG + JWT_SECRET ? "premium" : "guest");
if (voucher && subscription === "guest") {
return res.status(400).json({ message: "邀请码无效" });
}
const userToken = jwt.sign({ username, subscription }, JWT_SECRET, {
expiresIn: "1d",
});
res.cookie("token", userToken, { httpOnly: true });
return res.json({ message: "注册成功", subscription });
}

return res.status(400).json({ message: "用户名或邀请码无效" });
});

app.post("/article", (req, res) => {
const token = req.cookies.token;
if (token) {
try {
const decoded = jwt.verify(token, JWT_SECRET);
let index = req.body.index;
if (req.body.index < 0) {
return res.status(400).json({ message: "你知道我要说什么" });
}
if (decoded.subscription !== "premium" && index >= 7) {
return res
.status(403)
.json({ message: "订阅高级会员以解锁" });
}
index = parseInt(index);
if (Number.isNaN(index) || index > articles.length - 1) {
return res.status(400).json({ message: "你知道我要说什么" });
}

return res.json(articles[index]);
} catch (error) {
res.clearCookie("token");
return res.status(403).json({ message: "重新登录罢" });
}
} else {
return res.status(403).json({ message: "未登录" });
}
});

app.listen(3000, () => {
console.log("3000");
});

进入页面随便注册一个,发现源码里会有对文章的输出,还是数组形式的,抓包发现的确如此

image-20240423154717719

直接二维数组读就没问题

image-20240423154741955

EasySignin

注册登录后发现一个更改当前用户名密码按钮

抓包更改admin的密码

image-20240423160145365

登录之后康康好看的图片

image-20240423160322862

发现是个ssrf,goper伪协议打mysql就好

image-20240423160038383

需要把%换成%25

image-20240423160552441

解码得到flag

image-20240423160750264