Casino
Challenge Lab (Medium) - by Tyler Ramsbey
The following post by 0xb0b is licensed under CC BY 4.0
Scenario
Objective
Las Vegas is gearing up for a massive cybersecurity conference, and you've been hired to conduct a penetration test against one of the casinos. The client - Hack Smarter World - is a luxury resort where many of the attendees will be staying. Your objective is to identify all vulnerabilities and elevate your privileges to root (if possible).
Initial Access
You have been provided the IP of the Wifi Captive Portal... but no other information.
Summary
Recon
We use rustscan -b 500 -a 10.1.227.96 --top -- -sC -sV -Pn to enumerate all TCP ports on the target machine, piping the discovered results into Nmap, which runs default NSE scripts -sC, service and version detection -sV, and treats the host as online without ICMP echo -Pn.
A batch size of 500 trades speed for stability, the default 1500 balances both, while much larger sizes increase throughput but risk missed responses and instability.

The target 10.1.227.96 is a Linux host running a Python/Flask web application titled "Hack Smarter World - Guest WiFi & Portal." HTTP is exposed on port 80 via Werkzeug/3.1.8 with Python 3.10.18, redirecting to /login by default. SSH is available on port 22 running OpenSSH 9.6p1 (Ubuntu), and a second SSH instance is exposed on port 2222 running OpenSSH 8.4p1 (Debian).

We visit the hosted website on port 80 and find a guest portal for logging into the Wi-Fi. A room number and the guest's last name are sufficient for authentication.

We try using any combination and get a generic error message. If we enter a number less than or equal to 100, we get an error message telling us to enter a number greater than 100.

We try to enumerate additional directories using Feroxbuster and find the dashboard to be the next very thing we want to reach.

We'll also take a look at the referenced JavaScript client-side code which contains a comment to a source map. A source map is a file that maps minified or bundled JavaScript back to its original, human-readable source code. Let's see if it contains anything else.

The app.min.js.map file contains additional JavaScript that provides a helper function to query the room status. This means we could potentially identify all occupied rooms, if not even their guests.

Access to WiFi Dashboard
Option A: IDOR
We request the API endpoint to reveal all occupied rooms. We get them including the corresponding guests.

We use one of the many combinations to log in, and are successful. We gained access to the dashboard.

Option B: Brute-Force
Alternatively we could brute force with a limited set of rooms and surnames.
To craft our FFuF command to brute the log in page we make a simple login request and review it in Burp Suite. A POST request will be made to /login with a room_number and last_name parameter.

We generate a wordlist of all possible 3-digit room numbers using crunch.

We use the SecList repository for the last names and select the 1.000 most common U.S. family names wordlist.
For fuzzing both parameters simultaneously, use ffuf's multi-wordlist mode with -mode clusterbomb. And we do actually find plenty of combinations.

We use one of the many combinations to log in, and are successful. We gained access to the dashboard.

Shell as www-data
We head to the profile page, and see that we are greeted with our last name and can also make changes to it.
Since our inputs appear to be reflected, we could try to inject an XSS here, for example, but it’s more likely that we're dealing with an SSTI vulnerability. According to the Nmap scan and WappAlyzer, we're dealing with a Python Flask web app. We test for Server Side Template Injection SSTI using the following payload {{7*7}} and see that this expression evaluates to 49.

We may be dealing with Jinja2 a templating engine for Python. To confirm this, we'll use the following {{7*'7'}}. If it evaluates to 7777777 its Jinja.

We see that {{7*'7'}} evalutes 777777, its Jinja2.

We use a payload from Ingo Kleiber to test for RCE on Flask (Jinja2) SSTI and are successful.
On the blog, you can follow in detail how it was built and how it works:

Next, we try to spawn and catch a reverse shell. We spin up our reverse shell catcher Penelope

We prepare a reverse shell using revshells.com.

Next, we adapt our Jinja2 RCE payload and insert our reverse shell. After execution...

... we receive a connection back and are www-data.

We identifie the users george and david on the system.

Both home folders are readable and we are able to spot the user flag in george's home directory.

Shell as david
We'll look also in the .bash_history, since its not empty and contains the commands issued by george. This allows us to find out what is being done on the system, how tools are being used, and to view any credentials entered in plain text. We spot the database credentials for the user david. The password might have been re-used.

We try to change users to david with the found password and are successful.

Shell as root
The user is memeber of the adm group which allows us to read the log files.

We check every file for any sensitive information and are able to spot the root credentials in the provisioning log file.

We use the found password to change users to root and are successful. We find the root flag at /root/root.txt.

Last updated