Rating:

# Harekaze 2019 "[a-z().]" (200)

Writeup by Ben Taylor

## Description

Description
if (eval(your_code) === 1337) console.log(flag);

http://(redacted) ([server/Dockerfile](https://github.com/TeamHarekaze/HarekazeCTF2019-challenges/tree/master/a-z/server))

- [a-z.tar.xz](https://github.com/TeamHarekaze/HarekazeCTF2019-challenges/blob/master/a-z/attachments/a-z.tar.xz)

## Solution

Wow, this was a fun problem! Maybe my favorite CTF problem yet. If you haven't tried working through it already, I highly recommend you give it a shot. There will be spoilers.

Since we we're graciously provided the source code, let's start by taking a look inside. Line 15 is what's important here:

``` JavaScript
12 app.get('/', function (req, res, next) {
13 let output = '';
14 const code = req.query.code + '';
15 if (code && code.length < 200 && !/[^a-z().]/.test(code)) {
16 try {
17 const result = vm.runInNewContext(code, {}, { timeout: 500 });
18 if (result === 1337) {
19 output = process.env.FLAG;
20 } else {
21 output = 'nope';
22 }
23 } catch (e) {
24 output = 'nope';
25 }
26 } else {
27 output = 'nope';
28 }
29 res.render('index', { title: '[a-z().]', output });
30 });
```

For the code to run it must (a) exist, (b) have a length less than 200, and (c) can only contain lowercase letters, parenthesis, and dots. Once these checks pass, we get to run in a [super locked down node context](https://nodejs.org/api/vm.html#vm_script_runinnewcontext_sandbox_options). If the code evaluates to the number `1337` (note the triple equals here — a string won't cut it).

My first thought was something along the lines of BF's competitor, [non alphanumeric JavaScript](http://patriciopalladino.com/blog/2012/08/09/non-alphanumeric-javascript.html). However, this JS standard relies heavily on `[`, `]`, and `+`, all of which we don't have access to.

Instead, we'll start more basic than what the challenge calls for — how do we get a string with our limited alphabet? Digging around in documentation, we find the [typeof](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) operator. If we try to find the type of an undefined variable we get `"undefined"`. What if we try to get the type of that? We unlock the string `"string"`. Also note that we can get `"boolean"` by looking at the type of `true`.

``` JavaScript
(typeof(x)) == "undefined"
(typeof(typeof(x))) == "string"
(typeof(true)) == "boolean"
```

Great, we have strings. From here, we can use any string methods or properties that don't contain uppercase letters. For instance, `length`! This unlocks the numbers 6, 7, and 9. While we can't use `indexOf()` due to the uppercase `O`, inspecting a strings properties in any JavaScript console reveals the [search](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/search) method, which means we can search `"undefined"` for `"undefined"` to get `0` and `"undefined"` for `"boolean"` to get `-1`. Also note that since we have access to numbers, we also have access to the string `"number"` through `typeof`.

``` JavaScript
(typeof(x)).length == 9
(typeof(typeof(x))).length == 6
(typeof(true)).length == 7
(typeof((typeof(x)).length)) == "number"
(typeof((typeof(x)).length)).length == 6
(typeof(x)).search((typeof(x))) == 0
(typeof(x)).search((typeof(true))) == -1
```

Because we can use `concat`, it might be a good idea to form the digits individually and concatenate them since we're lacking any mathematical methods. How can we turn a number into a string? We can't use `toString`, `String`, or `+ ""`. But because JavaScript is a prototype based language, every instance is itself a "class". So using one string, we can access it's constructor with the `constructor` property! We can extend this ideas to numbers to get access to the `Number` class as well to turn strings back into numbers — remember, the final expression must evaluate to a number.

``` JavaScript
(typeof(x)).constructor == String
((typeof(x)).length).constructor == Number
(typeof(x)).constructor((typeof(true)).length) == "7" // we have our first digit to concatenate!
((typeof(x)).length).constructor("123") == 123
```

Lets see if we can get a `"1"`. Because JavaScript is stupid-typed, `true` == 1. But if we try to pull a `String(true)` using our equivalence above, we get `"true"`. Therefore, we need to first cast the boolean to a number, then the number to a string, leaving us with the monstrosity below. (true => 1 => "1")

``` JavaScript
((typeof(x)).length).constructor(true) == 1
(typeof(x)).constructor(((typeof(x)).length).constructor(true)) == "1"
```

The last digit that we need is a `"3"`. If you're dumb like me, you'll sit down for an hour or two and come up with something along the lines of `(typeof(x)).constructor((typeof(x)).constructor((typeof(x)).length.constructor(typeof(x))).length)`. No, I don't remember how this works and I don't plan on reverse engineering it. The point is, if you recall the rest of the constraints, we have to have an expression under 200 characters, so having _two_ 98 character expressions to get the `"3"`'s might be a problem. Thankfully, one of my teammates saved the day and brought up (in another conversation!) the `name` property of functions. This bad boy returns a string with the name of the function, which we can then take the length of. So really we just need any function with a three letter name. I decided to go with `(typeof(x)).big.name.length` to get `3`, which we can then cast to a string.

``` JavaScript
(typeof(x)).constructor((typeof(x)).constructor((typeof(x)).length.constructor(typeof(x))).length) == "3"
(typeof(x)).big.name.length == 3
(typeof(x)).constructor((typeof(x)).big.name.length) == "3"
```

Here is what the combined expression looks like right now. We're making a `"1"`, then concatenating the rest of the digits and parsing to an integer.

``` JavaScript
((typeof(x)).length).constructor((typeof(x)).constructor(((typeof(x)).length).constructor(true)).concat((typeof(x)).constructor((typeof(x)).big.name.length)).concat((typeof(x)).constructor((typeof(x)).big.name.length)).concat((typeof(x)).constructor((typeof(true)).length)))
```

If you look closely, you'll see this won't actually get us the flag. Why? It's 274 characters long. We need to do some optimizing.

Once again, JavaScript's stupid-typing comes in handy. We can append a number to a string and get a string, so we don't need to parse each number to a string, just the first digit. This gets us the following, clocking in at just 199 characters! We can also optimize `1 == (typeof(x)).match().length` to get down to 187 characters, and there might be a few extra parenthesis (though most are necessary due to `typeof`'s weird precedence), but either way, 199 < 200, and we get the flag!

``` JavaScript
((typeof(x)).length).constructor((typeof(x)).constructor(((typeof(x)).length).constructor(true)).concat((typeof(x)).constructor((typeof(x)).big.name.length)).concat((typeof(x)).constructor((typeof(x)).big.name.length)).concat((typeof(x)).constructor((typeof(true)).length)))
```

Flag: `HarekazeCTF{sorry_about_last_year's_js_challenge...}`

Original writeup (https://github.com/swv-l/writeups/blob/master/2019-harekaze-a-z.md).