# WriteUp NoSandbox IsitDTU ###### tags: ``Prototype Pollution`` Ở challage này cung cấp cho ta source code và một trang web như sau: ![](https://i.imgur.com/dLkMQdu.png) Nhìn qua source thì ta sẽ thấy 2 endpoint khác là ``/debug`` và ``/api/submit`` Ở endpoint ``/debug`` sẽ nhận param là ``debug`` và thực hiện check xem có xuất hiện những ký tự trong blacklist không, nếu có sẽ return not allow còn nếu không thì sẽ được đưa vào hàm ``eval`` để thực thi ![](https://i.imgur.com/L5XRD5e.png) Còn ở endpoint ``/api/submit`` thì ta phải truy cập qua methods POST. ![](https://i.imgur.com/neEaqLq.png) Để kích hoạt được endpoint này thì ta phải truyền property là ``artist.name`` và set ``Content-Type: application/json``, ta có thể thấy điều này được gợi ý trong file ``/static/js/main.js`` ![](https://i.imgur.com/O8PaIQT.png) Thử truy cập đến ``/api/submit`` với những điều kiện trên: ![](https://i.imgur.com/xadNqdd.png) Ta để ý 2 dòng code sau của endpoint này: ![](https://i.imgur.com/2UcgmLG.png) Nếu ``artitst.name`` là 1 trong 3 admin thì code sẽ thực hiện ghi đề file ``./routes/demo.js`` với nội dung là property ``options.data``. Đến đây mình đặt 1 giả thuyết là nếu ta tìm cách kiểm soát được giá trị của ``options.data`` thi ta hoàn toàn có thể inject bất cứ thứ gì mình muốn vào ``./routes/demo.js`` . Nhìn kỹ vào đoạn code xử lý ta phát hiện, chall dùng ``unflatten`` để featch API ![](https://i.imgur.com/zpVnZh1.png) Và qua vài đường gg ta biết thêm hàm này cho phép ta thực thi được prototype pollution. Từ đây ta sẽ lợi dụng ``unflatten`` thực hiện prototype pollution để thay đổi giá trị của ``option.data`` Gửi payload ![](https://i.imgur.com/NaOPsU4.png) Kết quả: ![](https://i.imgur.com/1htLYEN.png) Mình đã có thể inject bất kỳ đoạn code nào muốn vào ``demo.js`` vậy thì bây giờ làm sao để thực thi ? Hàm ``eval()`` tại ``/debug`` chính là câu trả lời, ta sẽ truyền vào param debug giá trị là: ``/debug?debug=require('./demo.js')`` . Khi đó hàm eval sẽ thực thi ``eval("require('./demo.js')")`` từ đó ta có thể chạy bất kỳ đoạn code nào mà ta mong muốn Mình sẽ dùng module ``child_process`` để thực hiện exec shell command Payload: ![](https://i.imgur.com/F6hErY1.png) Truy cập ``demo.js`` để kích hoạt payload: ![](https://i.imgur.com/aqoON8j.png) Code đã thực thi tuy nhiên request.repo của mình không nhận được gói tin nào cả :<< Sau một hồi debug, mình phát hiện câu lệnh ``eval()`` của mình không trả về gì cả, nghĩa là đoạn payload trong file ``demo.js`` đã không được thực thi đúng ![](https://i.imgur.com/CnGYc0V.png) Nếu eval thực thi đúng thì kết quả sẽ trả về ``true`` Sau một hồi đào bới trên gg thì mình phát hiện, trong quá trình runtime thì hàm ``require`` sẽ chỉ execute một lần và lưu vào bộ nhớ ``require cache`` ![](https://i.imgur.com/Zf57Mh1.png) Đây là cơ chế ``cycles`` của hàm require trong nodejs để hạn chế việc require tạo thành một vòng lặp vô tận. Và trong bài trên thì ta đã require ``demo.js`` rồi nên không thể require ``demo.js`` thêm 1 lần nữa được ![](https://i.imgur.com/xX2n5r2.png) Trong docs của nodejs đề cặp, để thực thi require nhiều lần thì hãy export một function và tiến hành gọi fuction. Có thể ví dụ như sau: ``` module.exports = function() { console.log("IMPORTED"); } ``` Thì khi thực hiện require ta sẽ gọi: ``` require("./my_script")(); ``` Tuy nhiên khi áp dụng cách trên cho challange thì ta xảy ra lỗi: ![](https://i.imgur.com/0fSkPP9.png) Vậy thì còn cách nào khác để bypass hành vi này không? Câu trả lời nằm trong link này (https://stackoverflow.com/questions/52359789/require-multiple-times Ta sẽ tiến hành clear cache sau đó gọi đến file ``demo.js``, dùng đoạn code sau để clear cache: ```javascript delete require.cache[require.resolve('./demo.js')] ``` Giờ chỉ cần thay giá trị của param debug bằng đoạn code trên ta đã có thể thực thi được payload ![](https://i.imgur.com/WBzYFBX.png) ![](https://i.imgur.com/mkhFgaf.png) Giờ thì chỉ cần tìm và đọc flag thôi # __Link tham khảo__: https://nodejs.org/api/modules.html#modules_caching