rex 2.0.5 → 2.0.7
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/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
|