# SECCON 2020 Online CTF - Capsule & Beginner's Capsule - Author's Writeup

## Author

@hakatashi

## Challenge Summary

The task is quite obvious from the appearence of the given website.

![](https://i.imgur.com/6WZBHgQ.png)

You can arbitrarily change the code below the given header and the task is to
get the value stored in ESNext's [Private Class
Field](https://v8.dev/features/class-fields#private-class-fields).
*Decapsulation.*

```js  
const fs = require('fs');  
const {enableSeccompFilter} = require('./lib.js');

class Flag {  
#flag;  
constructor(flag) {  
this.#flag = flag;  
}  
}

const flag = new Flag(fs.readFileSync('flag.txt').toString());  
fs.unlinkSync('flag.txt');

enableSeccompFilter();

// input goes here  
```

`enableSeccompFilter` function is just for preventing dumb solution to read
out `/proc/self/mem` so you don't have to care about it.

## Capsule: Intended Solution

You can access [V8's inspector API](https://chromedevtools.github.io/devtools-
protocol/) from [Node.js](https://nodejs.org/api/inspector.html) and get
hidden property like this.

Note that you must put `flag` variable to the global scope to inspect.

```js  
global.flag = flag;  
const inspector = require('inspector');  
const session = new inspector.Session();  
session.connect();  
session.post('Runtime.evaluate', {expression: 'flag'}, (e, d) => {  
session.post('Runtime.getProperties', {objectId: d.result.objectId}, (e, d) =>
{  
console.log(d.privateProperties[0].value.value);  
});  
});  
```

(I didn't know it, but this is mentioned
[here](https://github.com/nodejs/node/issues/27404#issuecomment-569924796))

## Capsule: Unintended Solution

You can inject fake `require` function using [function
hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting) and read
`flag.txt` before it is removed.

```js  
function require() {  
const fs = process.mainModule.require('fs');  
console.log(fs.readFileSync('flag.txt').toString());  
}  
```

So basic... :man-facepalming:

## Capsule: Unintended Solution

We expected Node.js cannot directly read memory without `/proc/self/mem`, but
actually it is possible using
[v8.getHeapSnapshot](https://nodejs.org/api/v8.html#v8_v8_getheapsnapshot).

```js  
const v8 = require('v8');  
const memory = v8.getHeapSnapshot().read();  
const index = memory.indexOf('SEC' + 'CON');  
const len = memory.slice(index).indexOf('}');  
const flagBuffer = memory.slice(index, index + len + 1);  
console.log(flagBuffer.toString());  
```

Original writeup (https://hackmd.io/@hakatashi/ryLh2okDD).