const express = require("express"); const Handlebars = require("handlebars"); const app = express(); app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.get("/", (req, res) => { res.send(`

Content Renderer



`); }); app.post("/render", (req, res) => { try { // [STEP 1 - ENTRY POINT] // Nhận dữ liệu từ request body (user-controlled input) // req.body.payload là một JSON string do attacker gửi lên const payload = JSON.parse(req.body.payload); // Parse JSON string thành JavaScript object (AST object) // Đây chính là điểm attacker inject AST thay vì template string // Nếu attacker gửi object có structure hợp lệ (type: "Program"), // Handlebars sẽ tin tưởng và sử dụng trực tiếp // [STEP 2] // Người dùng truyền payload vào Handlebars.compile() const template = Handlebars.compile(payload); // payload ở đây KHÔNG phải string template bình thường // mà là AST object (Program node) do attacker kiểm soát // [STEP 5] // Gọi function template đã được compile trước đó → function được thực thi const result = template({}); // [STEP 35] res.send(`
${result}
`); } catch (e) { res.send(`
${e.stack}
`); } }); console.log(require.resolve("handlebars")); app.listen(3000, () => { console.log("http://localhost:3000"); });