rex 2.0.5 → 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rex/exploitation/egghunter.rb +4 -6
- data/lib/rex/exploitation/powershell/psh_methods.rb +9 -0
- data/lib/rex/java/serialization.rb +2 -1
- data/lib/rex/java/serialization/builder.rb +94 -0
- data/lib/rex/java/serialization/model.rb +29 -18
- data/lib/rex/java/serialization/model/annotation.rb +2 -2
- data/lib/rex/java/serialization/model/field.rb +2 -2
- data/lib/rex/java/serialization/model/new_array.rb +8 -3
- data/lib/rex/java/serialization/model/new_class_desc.rb +3 -3
- data/lib/rex/java/serialization/model/new_enum.rb +4 -4
- data/lib/rex/java/serialization/model/new_object.rb +17 -10
- data/lib/rex/ole/direntry.rb +1 -1
- data/lib/rex/ole/samples/create_ole.rb +0 -0
- data/lib/rex/ole/samples/dir.rb +0 -0
- data/lib/rex/ole/samples/dump_stream.rb +0 -0
- data/lib/rex/ole/samples/ole_info.rb +0 -0
- data/lib/rex/parser/foundstone_nokogiri.rb +1 -1
- data/lib/rex/parser/fs/ntfs.rb +252 -0
- data/lib/rex/parser/openvas_nokogiri.rb +2 -0
- data/lib/rex/payloads/win32/kernel.rb +3 -3
- data/lib/rex/post/meterpreter/client_core.rb +172 -64
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +3 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +12 -10
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +64 -37
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +8 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +15 -3
- data/lib/rex/post/meterpreter/packet.rb +41 -38
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +7 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +17 -4
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +11 -4
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +1 -1
- data/lib/rex/proto.rb +2 -0
- data/lib/rex/proto/acpp.rb +17 -0
- data/lib/rex/proto/acpp/client.rb +29 -0
- data/lib/rex/proto/acpp/message.rb +183 -0
- data/lib/rex/proto/http/client.rb +1 -2
- data/lib/rex/proto/iax2/call.rb +22 -3
- data/lib/rex/proto/iax2/client.rb +1 -0
- data/lib/rex/proto/kerberos.rb +13 -0
- data/lib/rex/proto/kerberos/client.rb +213 -0
- data/lib/rex/proto/kerberos/credential_cache.rb +19 -0
- data/lib/rex/proto/kerberos/credential_cache/cache.rb +81 -0
- data/lib/rex/proto/kerberos/credential_cache/credential.rb +151 -0
- data/lib/rex/proto/kerberos/credential_cache/element.rb +49 -0
- data/lib/rex/proto/kerberos/credential_cache/key_block.rb +62 -0
- data/lib/rex/proto/kerberos/credential_cache/principal.rb +70 -0
- data/lib/rex/proto/kerberos/credential_cache/time.rb +69 -0
- data/lib/rex/proto/kerberos/crypto.rb +21 -0
- data/lib/rex/proto/kerberos/crypto/rc4_hmac.rb +65 -0
- data/lib/rex/proto/kerberos/crypto/rsa_md5.rb +15 -0
- data/lib/rex/proto/kerberos/model.rb +133 -0
- data/lib/rex/proto/kerberos/model/ap_req.rb +98 -0
- data/lib/rex/proto/kerberos/model/authenticator.rb +143 -0
- data/lib/rex/proto/kerberos/model/authorization_data.rb +85 -0
- data/lib/rex/proto/kerberos/model/checksum.rb +59 -0
- data/lib/rex/proto/kerberos/model/element.rb +67 -0
- data/lib/rex/proto/kerberos/model/enc_kdc_response.rb +215 -0
- data/lib/rex/proto/kerberos/model/encrypted_data.rb +171 -0
- data/lib/rex/proto/kerberos/model/encryption_key.rb +106 -0
- data/lib/rex/proto/kerberos/model/kdc_request.rb +166 -0
- data/lib/rex/proto/kerberos/model/kdc_request_body.rb +315 -0
- data/lib/rex/proto/kerberos/model/kdc_response.rb +141 -0
- data/lib/rex/proto/kerberos/model/krb_error.rb +219 -0
- data/lib/rex/proto/kerberos/model/last_request.rb +82 -0
- data/lib/rex/proto/kerberos/model/pre_auth_data.rb +104 -0
- data/lib/rex/proto/kerberos/model/pre_auth_enc_time_stamp.rb +126 -0
- data/lib/rex/proto/kerberos/model/pre_auth_pac_request.rb +81 -0
- data/lib/rex/proto/kerberos/model/principal_name.rb +116 -0
- data/lib/rex/proto/kerberos/model/ticket.rb +151 -0
- data/lib/rex/proto/kerberos/pac.rb +36 -0
- data/lib/rex/proto/kerberos/pac/client_info.rb +53 -0
- data/lib/rex/proto/kerberos/pac/element.rb +52 -0
- data/lib/rex/proto/kerberos/pac/logon_info.rb +566 -0
- data/lib/rex/proto/kerberos/pac/priv_svr_checksum.rb +29 -0
- data/lib/rex/proto/kerberos/pac/server_checksum.rb +30 -0
- data/lib/rex/proto/kerberos/pac/type.rb +121 -0
- data/lib/rex/proto/rmi.rb +7 -0
- data/lib/rex/proto/rmi/model.rb +31 -0
- data/lib/rex/proto/rmi/model/call.rb +60 -0
- data/lib/rex/proto/rmi/model/continuation.rb +76 -0
- data/lib/rex/proto/rmi/model/dgc_ack.rb +62 -0
- data/lib/rex/proto/rmi/model/element.rb +143 -0
- data/lib/rex/proto/rmi/model/output_header.rb +86 -0
- data/lib/rex/proto/rmi/model/ping.rb +41 -0
- data/lib/rex/proto/rmi/model/ping_ack.rb +41 -0
- data/lib/rex/proto/rmi/model/protocol_ack.rb +100 -0
- data/lib/rex/proto/rmi/model/return_data.rb +60 -0
- data/lib/rex/socket.rb +9 -1
- data/lib/rex/socket/tcp_server.rb +3 -0
- data/lib/rex/ui/text/dispatcher_shell.rb +4 -4
- data/lib/rex/ui/text/output/tee.rb +2 -0
- data/lib/rex/zip/samples/comment.rb +0 -0
- data/lib/rex/zip/samples/mkwar.rb +0 -0
- data/lib/rex/zip/samples/mkzip.rb +0 -0
- data/lib/rex/zip/samples/recursive.rb +0 -0
- data/rex.gemspec +1 -1
- metadata +56 -2
@@ -355,7 +355,13 @@ module PacketDispatcher
|
|
355
355
|
|
356
356
|
begin
|
357
357
|
if ! dispatch_inbound_packet(pkt)
|
358
|
-
#
|
358
|
+
# Keep Packets in the receive queue until a handler is registered
|
359
|
+
# for them. Packets will live in the receive queue for up to
|
360
|
+
# PacketTimeout, after which they will be dropped.
|
361
|
+
#
|
362
|
+
# A common reason why there would not immediately be a handler for
|
363
|
+
# a received Packet is in channels, where a connection may
|
364
|
+
# open and receive data before anything has asked to read.
|
359
365
|
if (::Time.now.to_i - pkt.created_at.to_i < PacketTimeout)
|
360
366
|
incomplete << pkt
|
361
367
|
end
|
@@ -69,7 +69,7 @@ class Console::CommandDispatcher::Core
|
|
69
69
|
# whatever reason it is not adding core_migrate to its list of commands.
|
70
70
|
# Use a dumb platform til it gets sorted.
|
71
71
|
#if client.commands.include? "core_migrate"
|
72
|
-
if client.platform =~ /win/
|
72
|
+
if client.platform =~ /win/ || client.platform =~ /linux/
|
73
73
|
c["migrate"] = "Migrate the server to another process"
|
74
74
|
end
|
75
75
|
|
@@ -321,7 +321,11 @@ class Console::CommandDispatcher::Core
|
|
321
321
|
end
|
322
322
|
|
323
323
|
def cmd_migrate_help
|
324
|
-
|
324
|
+
if client.platform =~ /linux/
|
325
|
+
print_line "Usage: migrate <pid> [writable_path]"
|
326
|
+
else
|
327
|
+
print_line "Usage: migrate <pid>"
|
328
|
+
end
|
325
329
|
print_line
|
326
330
|
print_line "Migrates the server instance to another process."
|
327
331
|
print_line "NOTE: Any open channels or other dynamic state will be lost."
|
@@ -331,7 +335,8 @@ class Console::CommandDispatcher::Core
|
|
331
335
|
#
|
332
336
|
# Migrates the server to the supplied process identifier.
|
333
337
|
#
|
334
|
-
# @param args [Array<String>] Commandline arguments,
|
338
|
+
# @param args [Array<String>] Commandline arguments, -h or a pid. On linux
|
339
|
+
# platforms a path for the unix domain socket used for IPC.
|
335
340
|
# @return [void]
|
336
341
|
def cmd_migrate(*args)
|
337
342
|
if ( args.length == 0 or args.include?("-h") )
|
@@ -345,6 +350,10 @@ class Console::CommandDispatcher::Core
|
|
345
350
|
return
|
346
351
|
end
|
347
352
|
|
353
|
+
if client.platform =~ /linux/
|
354
|
+
writable_dir = (args.length >= 2) ? args[1] : nil
|
355
|
+
end
|
356
|
+
|
348
357
|
begin
|
349
358
|
server = client.sys.process.open
|
350
359
|
rescue TimeoutError => e
|
@@ -385,7 +394,11 @@ class Console::CommandDispatcher::Core
|
|
385
394
|
server ? print_status("Migrating from #{server.pid} to #{pid}...") : print_status("Migrating to #{pid}")
|
386
395
|
|
387
396
|
# Do this thang.
|
388
|
-
client.
|
397
|
+
if client.platform =~ /linux/
|
398
|
+
client.core.migrate(pid, writable_dir)
|
399
|
+
else
|
400
|
+
client.core.migrate(pid)
|
401
|
+
end
|
389
402
|
|
390
403
|
print_status("Migration completed successfully.")
|
391
404
|
|
@@ -503,10 +503,17 @@ class Console::CommandDispatcher::Stdapi::Fs
|
|
503
503
|
client.framework.events.on_session_upload(client, src, dest) if msf_loaded?
|
504
504
|
}
|
505
505
|
elsif (stat.file?)
|
506
|
-
client.fs.file.
|
507
|
-
|
508
|
-
|
509
|
-
|
506
|
+
if client.fs.file.exists?(dest) and client.fs.file.stat(dest).directory?
|
507
|
+
client.fs.file.upload(dest, src) { |step, src, dst|
|
508
|
+
print_status("#{step.ljust(11)}: #{src} -> #{dst}")
|
509
|
+
client.framework.events.on_session_upload(client, src, dest) if msf_loaded?
|
510
|
+
}
|
511
|
+
else
|
512
|
+
client.fs.file.upload_file(dest, src) { |step, src, dst|
|
513
|
+
print_status("#{step.ljust(11)}: #{src} -> #{dst}")
|
514
|
+
client.framework.events.on_session_upload(client, src, dest) if msf_loaded?
|
515
|
+
}
|
516
|
+
end
|
510
517
|
end
|
511
518
|
}
|
512
519
|
|
data/lib/rex/proto.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
#
|
3
|
+
# Support for the protocol used by Apple Airport products, typically on
|
4
|
+
# 5009/TCP. This protocol is not documented and doesn't appear to have a name,
|
5
|
+
# so I'm calling it ACPP because that is the protocol header.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'rex/proto/acpp/client'
|
9
|
+
require 'rex/proto/acpp/message'
|
10
|
+
|
11
|
+
module Rex
|
12
|
+
module Proto
|
13
|
+
module ACPP
|
14
|
+
DEFAULT_PORT = 5009
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
##
|
4
|
+
# ACPP protocol support
|
5
|
+
##
|
6
|
+
|
7
|
+
module Rex
|
8
|
+
module Proto
|
9
|
+
module ACPP
|
10
|
+
|
11
|
+
class Client
|
12
|
+
|
13
|
+
def initialize(sock, opts = {})
|
14
|
+
@sock = sock
|
15
|
+
@opts = opts
|
16
|
+
end
|
17
|
+
|
18
|
+
def authenticate(password = 'public')
|
19
|
+
login = Message.new
|
20
|
+
login.password = password
|
21
|
+
login.type = 20
|
22
|
+
@sock.put(login.to_s)
|
23
|
+
# TODO: the checksum never validates here
|
24
|
+
Message.decode(@sock.get_once(128), false)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
module Rex
|
4
|
+
module Proto
|
5
|
+
module ACPP
|
6
|
+
# From what I've been able to gather from the very limited findings on the
|
7
|
+
# web about this protocol, playing with it against a real Airport device and
|
8
|
+
# referencing the airport-utils package in Debian/Ubuntu, the format of (at
|
9
|
+
# least) the login message is:
|
10
|
+
#
|
11
|
+
# acpp # the header tag, always exactly acpp (4 bytes)
|
12
|
+
# unknown1 # unknown 4-byte field. Almost always 0x00000001
|
13
|
+
# messageChecksum # checksum of the message, 4 bytes
|
14
|
+
# payloadChecksum # checksum of the payload, 4 bytes
|
15
|
+
# payloadSize # size of the payload, 4 bytes
|
16
|
+
# unknown2 # unknown 8-byte field. probably some sort of
|
17
|
+
# request/response identifier. generally 0 for requests, 1 for replies
|
18
|
+
# messageType # the type of message, 4 bytes. see below.
|
19
|
+
# status # the status of this message, 4 bytes.
|
20
|
+
# generally 0 for success and !0 for failure.
|
21
|
+
# unknown3 # unknown 12-byte field, seemingly always 0. Probably 'reserved'
|
22
|
+
# password # 32-byte password, 'encrypted' by XOR'ing it with a 256-byte static key (see XOR_KEY)
|
23
|
+
# unknown4 # unknown 48-byte field, always 0.
|
24
|
+
#
|
25
|
+
# There are several possible message types:
|
26
|
+
#
|
27
|
+
# * 20 -- retrieve settings (payload is some list of settings to obtain)
|
28
|
+
# * 21 -- update setttings (and if the 'acRB' setting is set, it reboots)
|
29
|
+
# * 3 -- Upload firmware
|
30
|
+
#
|
31
|
+
# TODO: if you find more, add them above.
|
32
|
+
#
|
33
|
+
# When the message type is anything other than 20 or 3, payloadSize is set to -1 and
|
34
|
+
# payloadChecksum is set to 1. It may be a bug that 21 doesn't look at the
|
35
|
+
# checksum. Adler32 is used to compute the checksum.
|
36
|
+
#
|
37
|
+
# The message payload is a bit of an unknown right now, as it *seems* like
|
38
|
+
# the payload always comes in a subsequent request. Simply appending
|
39
|
+
# a payload to the existing message does not appear to work (but this needs
|
40
|
+
# more testing)
|
41
|
+
|
42
|
+
# This was taken from airport-util's AirportInforRecord for ease of copying, but can
|
43
|
+
# also be obtained by XOR'ing the null-padded known plain text with the appropriate 32-byte
|
44
|
+
# ciphertext from an airport-util request
|
45
|
+
XOR_KEY = [
|
46
|
+
14, 57, -8, 5, -60, 1, 85, 79, 12, -84,
|
47
|
+
-123, 125, -122, -118, -75, 23, 62, 9, -56, 53,
|
48
|
+
-12, 49, 101, 127, 60, -100, -75, 109, -106, -102,
|
49
|
+
-91, 7, 46, 25, -40, 37, -28, 33, 117, 111,
|
50
|
+
44, -116, -91, -99, 102, 106, 85, -9, -34, -23,
|
51
|
+
40, -43, 20, -47, -123, -97, -36, 124, 85, -115,
|
52
|
+
118, 122, 69, -25, -50, -7, 56, -59, 4, -63,
|
53
|
+
-107, -113, -52, 108, 69, -67, 70, 74, 117, -41,
|
54
|
+
-2, -55, 8, -11, 52, -15, -91, -65, -4, 92,
|
55
|
+
117, -83, 86, 90, 101, -57, -18, -39, 24, -27,
|
56
|
+
36, -31, -75, -81, -20, 76, 101, -35, 38, 42,
|
57
|
+
21, -73, -98, -87, 104, -107, 84, -111, -59, -33,
|
58
|
+
-100, 60, 21, -51, 54, 58, 5, -89, -114, -71,
|
59
|
+
120, -123, 68, -127, -43, -49, -116, 44, 5, -3,
|
60
|
+
6, 10, 53, -105, -66, -119, 72, -75, 116, -79,
|
61
|
+
-27, -1, -68, 28, 53, -19, 22, 26, 37, -121,
|
62
|
+
-82, -103, 88, -91, 100, -95, -11, -17, -84, 12,
|
63
|
+
37, 29, -26, -22, -43, 119, 94, 105, -88, 85,
|
64
|
+
-108, 81, 5, 31, 92, -4, -43, 13, -10, -6,
|
65
|
+
-59, 103, 78, 121, -72, 69, -124, 65, 21, 15,
|
66
|
+
76, -20, -59, 61, -58, -54, -11, 87, 126, 73,
|
67
|
+
-120, 117, -76, 113, 37, 63, 124, -36, -11, 45,
|
68
|
+
-42, -38, -27, 71, 110, 89, -104, 101, -92, 97,
|
69
|
+
53, 47, 108, -52, -27, 93, -90, -86, -107, 55,
|
70
|
+
30, 41, -24, 21, -44, 17, 69, 95, 28, -68,
|
71
|
+
-107, 77, -74, -70, -123, 39
|
72
|
+
].pack("C*")
|
73
|
+
|
74
|
+
class Message
|
75
|
+
# @return [Integer] the type of this message
|
76
|
+
attr_accessor :type
|
77
|
+
# @return [String] the password to attempt to authenticate with
|
78
|
+
attr_accessor :password
|
79
|
+
# @return [String] the optional message payload
|
80
|
+
attr_accessor :payload
|
81
|
+
# @return [Integer] the status of this message
|
82
|
+
attr_accessor :status
|
83
|
+
|
84
|
+
def initialize
|
85
|
+
@payload = ''
|
86
|
+
@type = 0
|
87
|
+
@status = 0
|
88
|
+
@password = ''
|
89
|
+
@unknown1 = 1
|
90
|
+
@unknown2 = ''
|
91
|
+
@unknown3 = ''
|
92
|
+
@unknown4 = ''
|
93
|
+
end
|
94
|
+
|
95
|
+
# Determines if this message has a successful status code
|
96
|
+
#
|
97
|
+
# @return [Boolean] true iff @status is 0, false otherwise
|
98
|
+
def successful?
|
99
|
+
@status == 0
|
100
|
+
end
|
101
|
+
|
102
|
+
# Get this Message as a String
|
103
|
+
#
|
104
|
+
# @return [String] the string representation of this Message
|
105
|
+
def to_s
|
106
|
+
with_checksum(Zlib.adler32(with_checksum(0)))
|
107
|
+
end
|
108
|
+
|
109
|
+
# Compares this Message and another Message for equality
|
110
|
+
#
|
111
|
+
# @param other [Message] the Message to compare
|
112
|
+
# @return [Boolean] true iff the two messages are equal, false otherwise
|
113
|
+
def ==(other)
|
114
|
+
other.type == @type &&
|
115
|
+
other.status == @status &&
|
116
|
+
other.password == @password &&
|
117
|
+
other.payload == @payload
|
118
|
+
end
|
119
|
+
|
120
|
+
# Decodes the provided data into a Message
|
121
|
+
#
|
122
|
+
# @param data [String] the data to parse as a Message
|
123
|
+
# @param validate_checksum [Boolean] true to validate the message and
|
124
|
+
# payload checksums, false to not. Defaults to true.
|
125
|
+
# @return [Message] the decoded Message
|
126
|
+
def self.decode(data, validate_checksum = true)
|
127
|
+
data = data.dup
|
128
|
+
fail "Incorrect ACPP message size #{data.size} -- must be 128" unless data.size == 128
|
129
|
+
fail 'Unexpected header' unless 'acpp' == data.slice!(0, 4)
|
130
|
+
_unknown1 = data.slice!(0, 4)
|
131
|
+
read_message_checksum = data.slice!(0, 4).unpack('N').first
|
132
|
+
read_payload_checksum = data.slice!(0, 4).unpack('N').first
|
133
|
+
_read_payload_size = data.slice!(0, 4).unpack('N').first
|
134
|
+
_unknown2 = data.slice!(0, 8)
|
135
|
+
type = data.slice!(0, 4).unpack('N').first
|
136
|
+
status = data.slice!(0, 4).unpack('N').first
|
137
|
+
_unknown3 = data.slice!(0, 12)
|
138
|
+
password = Rex::Encoding::Xor::Generic.encode(data.slice!(0, 32), XOR_KEY).first.strip
|
139
|
+
_unknown4 = data.slice!(0, 48)
|
140
|
+
payload = data
|
141
|
+
m = new
|
142
|
+
m.type = type
|
143
|
+
m.password = password
|
144
|
+
m.status = status
|
145
|
+
m.payload = payload
|
146
|
+
|
147
|
+
# we can now validate the checksums if desired
|
148
|
+
if validate_checksum
|
149
|
+
actual_message_checksum = Zlib.adler32(m.with_checksum(0))
|
150
|
+
if actual_message_checksum != read_message_checksum
|
151
|
+
fail "Invalid message checksum (expected #{read_message_checksum}, calculated #{actual_message_checksum})"
|
152
|
+
end
|
153
|
+
# I'm not sure this can ever happen -- if the payload checksum is wrong, then the
|
154
|
+
# message checksum will also be wrong. So, either I misunderstand the protocol
|
155
|
+
# or having two checksums is useless
|
156
|
+
actual_payload_checksum = Zlib.adler32(payload)
|
157
|
+
if actual_payload_checksum != read_payload_checksum
|
158
|
+
fail "Invalid payload checksum (expected #{read_payload_checksum}, calculated #{actual_payload_checksum})"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
m
|
162
|
+
end
|
163
|
+
|
164
|
+
def with_checksum(message_checksum)
|
165
|
+
[
|
166
|
+
'acpp',
|
167
|
+
@unknown1,
|
168
|
+
message_checksum,
|
169
|
+
Zlib.adler32(@payload),
|
170
|
+
@payload.size,
|
171
|
+
@unknown2,
|
172
|
+
@type,
|
173
|
+
@status,
|
174
|
+
@unknown3,
|
175
|
+
Rex::Encoding::Xor::Generic.encode([@password].pack('a32').slice(0, 32), XOR_KEY).first,
|
176
|
+
@unknown4,
|
177
|
+
payload
|
178
|
+
].pack('a4NNNNa8NNa12a32a48a*')
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -86,7 +86,7 @@ class Client
|
|
86
86
|
typ = self.config_types[var] || 'string'
|
87
87
|
|
88
88
|
# These are enum types
|
89
|
-
if
|
89
|
+
if typ.is_a?(Array)
|
90
90
|
if not typ.include?(val)
|
91
91
|
raise RuntimeError, "The specified value for #{var} is not one of the valid choices"
|
92
92
|
end
|
@@ -719,4 +719,3 @@ end
|
|
719
719
|
end
|
720
720
|
end
|
721
721
|
end
|
722
|
-
|
data/lib/rex/proto/iax2/call.rb
CHANGED
@@ -72,7 +72,14 @@ class Call
|
|
72
72
|
end
|
73
73
|
|
74
74
|
chall = nil
|
75
|
-
|
75
|
+
|
76
|
+
# Look for IAX_AUTH_MD5 (2) as an available auth method
|
77
|
+
if res[2][14].unpack("n")[0] & 2 <= 0
|
78
|
+
dprint("REGAUTH: MD5 authentication is not enabled on the server")
|
79
|
+
return
|
80
|
+
end
|
81
|
+
|
82
|
+
if res[2][IAX_IE_CHALLENGE_DATA]
|
76
83
|
self.dcall = res[0][0]
|
77
84
|
chall = res[2][IAX_IE_CHALLENGE_DATA]
|
78
85
|
end
|
@@ -114,9 +121,21 @@ class Call
|
|
114
121
|
# Handle authentication if its requested
|
115
122
|
if res[1] == IAX_SUBTYPE_AUTHREQ
|
116
123
|
chall = nil
|
117
|
-
|
124
|
+
|
125
|
+
# Look for IAX_AUTH_MD5 (2) as an available auth method
|
126
|
+
if res[2][14].unpack("n")[0] & 2 <= 0
|
127
|
+
dprint("REGAUTH: MD5 authentication is not enabled on the server")
|
128
|
+
return
|
129
|
+
end
|
130
|
+
|
131
|
+
if res[2][IAX_IE_CHALLENGE_DATA]
|
118
132
|
self.dcall = res[0][0]
|
119
|
-
chall = res[2][
|
133
|
+
chall = res[2][IAX_IE_CHALLENGE_DATA]
|
134
|
+
end
|
135
|
+
|
136
|
+
if chall.nil?
|
137
|
+
dprint("REGAUTH: No challenge data received")
|
138
|
+
return
|
120
139
|
end
|
121
140
|
|
122
141
|
self.client.send_authrep_chall_response(self, chall)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
# Kerberos 5 implementation according to RFC 1510
|
4
|
+
|
5
|
+
require 'openssl'
|
6
|
+
require 'rex/socket'
|
7
|
+
require 'rex/text'
|
8
|
+
require 'rex/proto/kerberos/crypto'
|
9
|
+
require 'rex/proto/kerberos/pac'
|
10
|
+
require 'rex/proto/kerberos/model'
|
11
|
+
require 'rex/proto/kerberos/client'
|
12
|
+
require 'rex/proto/kerberos/credential_cache'
|
13
|
+
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
module Rex
|
4
|
+
module Proto
|
5
|
+
module Kerberos
|
6
|
+
# This class is a representation of a kerberos client.
|
7
|
+
class Client
|
8
|
+
# @!attribute host
|
9
|
+
# @return [String] The kerberos server host
|
10
|
+
attr_accessor :host
|
11
|
+
# @!attribute port
|
12
|
+
# @return [Fixnum] The kerberos server port
|
13
|
+
attr_accessor :port
|
14
|
+
# @!attribute timeout
|
15
|
+
# @return [Fixnum] The connect / read timeout
|
16
|
+
attr_accessor :timeout
|
17
|
+
# @todo Support UDP
|
18
|
+
# @!attribute protocol
|
19
|
+
# @return [String] The transport protocol used (tcp/udp)
|
20
|
+
attr_accessor :protocol
|
21
|
+
# @!attribute connection
|
22
|
+
# @return [IO] The connection established through Rex sockets
|
23
|
+
attr_accessor :connection
|
24
|
+
# @!attribute context
|
25
|
+
# @return [Hash] The Msf context where the connection belongs to
|
26
|
+
attr_accessor :context
|
27
|
+
|
28
|
+
def initialize(opts = {})
|
29
|
+
self.host = opts[:host]
|
30
|
+
self.port = (opts[:port] || 88).to_i
|
31
|
+
self.timeout = (opts[:timeout] || 10).to_i
|
32
|
+
self.protocol = opts[:protocol] || 'tcp'
|
33
|
+
self.context = opts[:context] || {}
|
34
|
+
end
|
35
|
+
|
36
|
+
# Creates a connection through a Rex socket
|
37
|
+
#
|
38
|
+
# @return [Rex::Socket::Tcp]
|
39
|
+
# @raise [RuntimeError] if the connection can not be created
|
40
|
+
def connect
|
41
|
+
return connection if connection
|
42
|
+
|
43
|
+
case protocol
|
44
|
+
when 'tcp'
|
45
|
+
self.connection = create_tcp_connection
|
46
|
+
when 'udp'
|
47
|
+
raise ::NotImplementedError, 'Kerberos Client: UDP not supported'
|
48
|
+
else
|
49
|
+
raise ::RuntimeError, 'Kerberos Client: unknown transport protocol'
|
50
|
+
end
|
51
|
+
|
52
|
+
connection
|
53
|
+
end
|
54
|
+
|
55
|
+
# Closes the connection
|
56
|
+
def close
|
57
|
+
if connection
|
58
|
+
connection.shutdown
|
59
|
+
connection.close unless connection.closed?
|
60
|
+
end
|
61
|
+
|
62
|
+
self.connection = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
# Sends a kerberos request through the connection
|
66
|
+
#
|
67
|
+
# @param req [Rex::Proto::Kerberos::Model::KdcRequest] the request to send
|
68
|
+
# @return [Fixnum] the number of bytes sent
|
69
|
+
# @raise [RuntimeError] if the transport protocol is unknown
|
70
|
+
# @raise [NotImplementedError] if the transport protocol isn't supported
|
71
|
+
def send_request(req)
|
72
|
+
connect
|
73
|
+
|
74
|
+
sent = 0
|
75
|
+
case protocol
|
76
|
+
when 'tcp'
|
77
|
+
sent = send_request_tcp(req)
|
78
|
+
when 'udp'
|
79
|
+
sent = send_request_udp(req)
|
80
|
+
else
|
81
|
+
raise ::RuntimeError, 'Kerberos Client: unknown transport protocol'
|
82
|
+
end
|
83
|
+
|
84
|
+
sent
|
85
|
+
end
|
86
|
+
|
87
|
+
# Receives a kerberos response through the connection
|
88
|
+
#
|
89
|
+
# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] the kerberos
|
90
|
+
# response message
|
91
|
+
# @raise [RuntimeError] if the connection isn't established, the transport protocol is unknown, not supported
|
92
|
+
# or the response can't be parsed
|
93
|
+
# @raise [NotImplementedError] if the transport protocol isn't supported
|
94
|
+
def recv_response
|
95
|
+
if connection.nil?
|
96
|
+
raise ::RuntimeError, 'Kerberos Client: connection not established'
|
97
|
+
end
|
98
|
+
|
99
|
+
res = nil
|
100
|
+
case protocol
|
101
|
+
when 'tcp'
|
102
|
+
res = recv_response_tcp
|
103
|
+
when 'udp'
|
104
|
+
res = recv_response_udp
|
105
|
+
else
|
106
|
+
raise ::RuntimeError, 'Kerberos Client: unknown transport protocol'
|
107
|
+
end
|
108
|
+
|
109
|
+
res
|
110
|
+
end
|
111
|
+
|
112
|
+
# Sends a kerberos request, and reads the response through the connection
|
113
|
+
#
|
114
|
+
# @param req [Rex::Proto::Kerberos::Model::KdcRequest] the request to send
|
115
|
+
# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] The kerberos message
|
116
|
+
# @raise [RuntimeError] if the transport protocol is unknown or the response can't be parsed.
|
117
|
+
# @raise [NotImplementedError] if the transport protocol isn't supported
|
118
|
+
def send_recv(req)
|
119
|
+
send_request(req)
|
120
|
+
res = recv_response
|
121
|
+
|
122
|
+
res
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
# Creates a TCP connection using Rex::Socket::Tcp
|
128
|
+
#
|
129
|
+
# @return [Rex::Socket::Tcp]
|
130
|
+
def create_tcp_connection
|
131
|
+
self.connection = Rex::Socket::Tcp.create(
|
132
|
+
'PeerHost' => host,
|
133
|
+
'PeerPort' => port.to_i,
|
134
|
+
'Context' => context,
|
135
|
+
'Timeout' => timeout
|
136
|
+
)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Sends a Kerberos Request over a tcp connection
|
140
|
+
#
|
141
|
+
# @param req [Rex::Proto::Kerberos::Model::KdcRequest] the request to send
|
142
|
+
# @return [Fixnum] the number of bytes sent
|
143
|
+
# @raise [RuntimeError] if the request can't be encoded
|
144
|
+
def send_request_tcp(req)
|
145
|
+
data = req.encode
|
146
|
+
length = [data.length].pack('N')
|
147
|
+
connection.put(length + data)
|
148
|
+
end
|
149
|
+
|
150
|
+
# UDP isn't supported
|
151
|
+
#
|
152
|
+
# @raise [NotImplementedError]
|
153
|
+
def send_request_udp(req)
|
154
|
+
raise ::NotImplementedError, 'Kerberos Client: UDP unsupported'
|
155
|
+
end
|
156
|
+
|
157
|
+
# Receives a Kerberos Response over a tcp connection
|
158
|
+
#
|
159
|
+
# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] the kerberos message response
|
160
|
+
# @raise [RuntimeError] if the response can't be processed
|
161
|
+
# @raise [EOFError] if expected data can't be read
|
162
|
+
def recv_response_tcp
|
163
|
+
length_raw = connection.get_once(4, timeout)
|
164
|
+
unless length_raw && length_raw.length == 4
|
165
|
+
raise ::RuntimeError, 'Kerberos Client: failed to read response'
|
166
|
+
end
|
167
|
+
length = length_raw.unpack('N')[0]
|
168
|
+
|
169
|
+
data = connection.get_once(length, timeout)
|
170
|
+
unless data && data.length == length
|
171
|
+
raise ::RuntimeError, 'Kerberos Client: failed to read response'
|
172
|
+
end
|
173
|
+
|
174
|
+
res = decode_kerb_response(data)
|
175
|
+
|
176
|
+
res
|
177
|
+
end
|
178
|
+
|
179
|
+
# UDP isn't supported
|
180
|
+
#
|
181
|
+
# @raise [NotImplementedError]
|
182
|
+
def recv_response_udp
|
183
|
+
raise ::NotImplementedError, 'Kerberos Client: UDP unsupported'
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
# Decodes a Kerberos response
|
189
|
+
#
|
190
|
+
# @param input [String] the raw response message
|
191
|
+
# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] the kerberos message response
|
192
|
+
# @raise [RuntimeError] if the response can't be processed
|
193
|
+
def decode_kerb_response(data)
|
194
|
+
asn1 = OpenSSL::ASN1.decode(data)
|
195
|
+
msg_type = asn1.value[0].value[1].value[0].value
|
196
|
+
|
197
|
+
case msg_type
|
198
|
+
when Rex::Proto::Kerberos::Model::KRB_ERROR
|
199
|
+
res = Rex::Proto::Kerberos::Model::KrbError.decode(asn1)
|
200
|
+
when Rex::Proto::Kerberos::Model::AS_REP
|
201
|
+
res = Rex::Proto::Kerberos::Model::KdcResponse.decode(asn1)
|
202
|
+
when Rex::Proto::Kerberos::Model::TGS_REP
|
203
|
+
res = Rex::Proto::Kerberos::Model::KdcResponse.decode(asn1)
|
204
|
+
else
|
205
|
+
raise ::RuntimeError, 'Kerberos Client: Unknown response'
|
206
|
+
end
|
207
|
+
|
208
|
+
res
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|