rex 2.0.5 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
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