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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rex/exploitation/egghunter.rb +4 -6
  3. data/lib/rex/exploitation/powershell/psh_methods.rb +9 -0
  4. data/lib/rex/java/serialization.rb +2 -1
  5. data/lib/rex/java/serialization/builder.rb +94 -0
  6. data/lib/rex/java/serialization/model.rb +29 -18
  7. data/lib/rex/java/serialization/model/annotation.rb +2 -2
  8. data/lib/rex/java/serialization/model/field.rb +2 -2
  9. data/lib/rex/java/serialization/model/new_array.rb +8 -3
  10. data/lib/rex/java/serialization/model/new_class_desc.rb +3 -3
  11. data/lib/rex/java/serialization/model/new_enum.rb +4 -4
  12. data/lib/rex/java/serialization/model/new_object.rb +17 -10
  13. data/lib/rex/ole/direntry.rb +1 -1
  14. data/lib/rex/ole/samples/create_ole.rb +0 -0
  15. data/lib/rex/ole/samples/dir.rb +0 -0
  16. data/lib/rex/ole/samples/dump_stream.rb +0 -0
  17. data/lib/rex/ole/samples/ole_info.rb +0 -0
  18. data/lib/rex/parser/foundstone_nokogiri.rb +1 -1
  19. data/lib/rex/parser/fs/ntfs.rb +252 -0
  20. data/lib/rex/parser/openvas_nokogiri.rb +2 -0
  21. data/lib/rex/payloads/win32/kernel.rb +3 -3
  22. data/lib/rex/post/meterpreter/client_core.rb +172 -64
  23. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +3 -2
  24. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +12 -10
  25. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +64 -37
  26. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +8 -2
  27. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +15 -3
  28. data/lib/rex/post/meterpreter/packet.rb +41 -38
  29. data/lib/rex/post/meterpreter/packet_dispatcher.rb +7 -1
  30. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +17 -4
  31. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +11 -4
  32. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +1 -1
  33. data/lib/rex/proto.rb +2 -0
  34. data/lib/rex/proto/acpp.rb +17 -0
  35. data/lib/rex/proto/acpp/client.rb +29 -0
  36. data/lib/rex/proto/acpp/message.rb +183 -0
  37. data/lib/rex/proto/http/client.rb +1 -2
  38. data/lib/rex/proto/iax2/call.rb +22 -3
  39. data/lib/rex/proto/iax2/client.rb +1 -0
  40. data/lib/rex/proto/kerberos.rb +13 -0
  41. data/lib/rex/proto/kerberos/client.rb +213 -0
  42. data/lib/rex/proto/kerberos/credential_cache.rb +19 -0
  43. data/lib/rex/proto/kerberos/credential_cache/cache.rb +81 -0
  44. data/lib/rex/proto/kerberos/credential_cache/credential.rb +151 -0
  45. data/lib/rex/proto/kerberos/credential_cache/element.rb +49 -0
  46. data/lib/rex/proto/kerberos/credential_cache/key_block.rb +62 -0
  47. data/lib/rex/proto/kerberos/credential_cache/principal.rb +70 -0
  48. data/lib/rex/proto/kerberos/credential_cache/time.rb +69 -0
  49. data/lib/rex/proto/kerberos/crypto.rb +21 -0
  50. data/lib/rex/proto/kerberos/crypto/rc4_hmac.rb +65 -0
  51. data/lib/rex/proto/kerberos/crypto/rsa_md5.rb +15 -0
  52. data/lib/rex/proto/kerberos/model.rb +133 -0
  53. data/lib/rex/proto/kerberos/model/ap_req.rb +98 -0
  54. data/lib/rex/proto/kerberos/model/authenticator.rb +143 -0
  55. data/lib/rex/proto/kerberos/model/authorization_data.rb +85 -0
  56. data/lib/rex/proto/kerberos/model/checksum.rb +59 -0
  57. data/lib/rex/proto/kerberos/model/element.rb +67 -0
  58. data/lib/rex/proto/kerberos/model/enc_kdc_response.rb +215 -0
  59. data/lib/rex/proto/kerberos/model/encrypted_data.rb +171 -0
  60. data/lib/rex/proto/kerberos/model/encryption_key.rb +106 -0
  61. data/lib/rex/proto/kerberos/model/kdc_request.rb +166 -0
  62. data/lib/rex/proto/kerberos/model/kdc_request_body.rb +315 -0
  63. data/lib/rex/proto/kerberos/model/kdc_response.rb +141 -0
  64. data/lib/rex/proto/kerberos/model/krb_error.rb +219 -0
  65. data/lib/rex/proto/kerberos/model/last_request.rb +82 -0
  66. data/lib/rex/proto/kerberos/model/pre_auth_data.rb +104 -0
  67. data/lib/rex/proto/kerberos/model/pre_auth_enc_time_stamp.rb +126 -0
  68. data/lib/rex/proto/kerberos/model/pre_auth_pac_request.rb +81 -0
  69. data/lib/rex/proto/kerberos/model/principal_name.rb +116 -0
  70. data/lib/rex/proto/kerberos/model/ticket.rb +151 -0
  71. data/lib/rex/proto/kerberos/pac.rb +36 -0
  72. data/lib/rex/proto/kerberos/pac/client_info.rb +53 -0
  73. data/lib/rex/proto/kerberos/pac/element.rb +52 -0
  74. data/lib/rex/proto/kerberos/pac/logon_info.rb +566 -0
  75. data/lib/rex/proto/kerberos/pac/priv_svr_checksum.rb +29 -0
  76. data/lib/rex/proto/kerberos/pac/server_checksum.rb +30 -0
  77. data/lib/rex/proto/kerberos/pac/type.rb +121 -0
  78. data/lib/rex/proto/rmi.rb +7 -0
  79. data/lib/rex/proto/rmi/model.rb +31 -0
  80. data/lib/rex/proto/rmi/model/call.rb +60 -0
  81. data/lib/rex/proto/rmi/model/continuation.rb +76 -0
  82. data/lib/rex/proto/rmi/model/dgc_ack.rb +62 -0
  83. data/lib/rex/proto/rmi/model/element.rb +143 -0
  84. data/lib/rex/proto/rmi/model/output_header.rb +86 -0
  85. data/lib/rex/proto/rmi/model/ping.rb +41 -0
  86. data/lib/rex/proto/rmi/model/ping_ack.rb +41 -0
  87. data/lib/rex/proto/rmi/model/protocol_ack.rb +100 -0
  88. data/lib/rex/proto/rmi/model/return_data.rb +60 -0
  89. data/lib/rex/socket.rb +9 -1
  90. data/lib/rex/socket/tcp_server.rb +3 -0
  91. data/lib/rex/ui/text/dispatcher_shell.rb +4 -4
  92. data/lib/rex/ui/text/output/tee.rb +2 -0
  93. data/lib/rex/zip/samples/comment.rb +0 -0
  94. data/lib/rex/zip/samples/mkwar.rb +0 -0
  95. data/lib/rex/zip/samples/mkzip.rb +0 -0
  96. data/lib/rex/zip/samples/recursive.rb +0 -0
  97. data/rex.gemspec +1 -1
  98. metadata +56 -2
@@ -355,7 +355,13 @@ module PacketDispatcher
355
355
 
356
356
  begin
357
357
  if ! dispatch_inbound_packet(pkt)
358
- # Only requeue packets newer than the timeout
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
- print_line "Usage: migrate <pid>"
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, only -h or a pid
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.core.migrate(pid)
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.upload(dest, src) { |step, src, dst|
507
- print_status("#{step.ljust(11)}: #{src} -> #{dst}")
508
- client.framework.events.on_session_upload(client, src, dest) if msf_loaded?
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
 
@@ -150,7 +150,7 @@ class Console::CommandDispatcher::Stdapi::Ui
150
150
  when "-p"
151
151
  path = val
152
152
  when "-v"
153
- view = false if ( val =~ /^(f|n|0)/i )
153
+ view = true if ( val =~ /^(t|y|1)/i )
154
154
  end
155
155
  }
156
156
 
@@ -5,6 +5,8 @@ require 'rex/proto/ntlm'
5
5
  require 'rex/proto/dcerpc'
6
6
  require 'rex/proto/drda'
7
7
  require 'rex/proto/iax2'
8
+ require 'rex/proto/kerberos'
9
+ require 'rex/proto/rmi'
8
10
 
9
11
  module Rex
10
12
  module Proto
@@ -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(typ.class.to_s == 'Array')
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
-
@@ -72,7 +72,14 @@ class Call
72
72
  end
73
73
 
74
74
  chall = nil
75
- if res[2][14] == "\x00\x03" and res[2][IAX_IE_CHALLENGE_DATA]
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
- if res[2][14] == "\x00\x03" and res[1][15]
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][15]
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)
@@ -34,6 +34,7 @@ class Client
34
34
  self.server_port = opts[:server_port]
35
35
  self.username = opts[:username]
36
36
  self.password = opts[:password]
37
+ self.debugging = opts[:debugging]
37
38
 
38
39
  self.sock = Rex::Socket::Udp.create(
39
40
  'PeerHost' => self.server_host,
@@ -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