Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/proto/kerberos/client.rb
Views: 11704
# -*- coding: binary -*-12require 'rex/stopwatch'34module Rex5module Proto6module Kerberos7# This class is a representation of a kerberos client.8class Client9# @!attribute host10# @return [String] The kerberos server host11attr_accessor :host12# @!attribute port13# @return [Integer] The kerberos server port14attr_accessor :port15# @!attribute proxies16# @return [String,nil] The proxy directive to use for the socket17attr_accessor :proxies18# @!attribute timeout19# @return [Integer] The connect / read timeout20attr_accessor :timeout21# @todo Support UDP22# @!attribute protocol23# @return [String] The transport protocol used (tcp/udp)24attr_accessor :protocol25# @!attribute connection26# @return [IO] The connection established through Rex sockets27attr_accessor :connection28# @!attribute context29# @return [Hash] The Msf context where the connection belongs to30attr_accessor :context3132def initialize(opts = {})33self.host = opts[:host]34self.port = (opts[:port] || 88).to_i35self.proxies = opts[:proxies]36self.timeout = (opts[:timeout] || 10).to_i37self.protocol = opts[:protocol] || 'tcp'38self.context = opts[:context] || {}39end4041# Creates a connection through a Rex socket42#43# @return [Rex::Socket::Tcp]44# @raise [RuntimeError] if the connection can not be created45def connect46return connection if connection47raise ArgumentError, 'Missing remote address' unless self.host && self.port48case protocol49when 'tcp'50self.connection = create_tcp_connection51when 'udp'52raise ::NotImplementedError, 'Kerberos Client: UDP not supported'53else54raise ::RuntimeError, 'Kerberos Client: unknown transport protocol'55end5657connection58end5960# Closes the connection61def close62if connection63connection.shutdown64connection.close unless connection.closed?65end6667self.connection = nil68end6970# Sends a kerberos request through the connection71#72# @param req [Rex::Proto::Kerberos::Model::KdcRequest] the request to send73# @return [Integer] the number of bytes sent74# @raise [RuntimeError] if the transport protocol is unknown75# @raise [NotImplementedError] if the transport protocol isn't supported76def send_request(req)77connect7879sent = 080case protocol81when 'tcp'82sent = send_request_tcp(req)83when 'udp'84sent = send_request_udp(req)85else86raise ::RuntimeError, 'Kerberos Client: unknown transport protocol'87end8889sent90end9192# Receives a kerberos response through the connection93#94# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] the kerberos95# response message96# @raise [RuntimeError] if the connection isn't established, the transport protocol is unknown, not supported97# or the response can't be parsed98# @raise [NotImplementedError] if the transport protocol isn't supported99def recv_response100if connection.nil?101raise ::RuntimeError, 'Kerberos Client: connection not established'102end103104res = nil105case protocol106when 'tcp'107res = recv_response_tcp108when 'udp'109res = recv_response_udp110else111raise ::RuntimeError, 'Kerberos Client: unknown transport protocol'112end113114res115end116117# Sends a kerberos request, and reads the response through the connection118#119# @param req [Rex::Proto::Kerberos::Model::KdcRequest] the request to send120# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] The kerberos message121# @raise [RuntimeError] if the transport protocol is unknown or the response can't be parsed.122# @raise [NotImplementedError] if the transport protocol isn't supported123def send_recv(req)124send_request(req)125res = recv_response126127res128end129130private131132# Creates a TCP connection using Rex::Socket::Tcp133#134# @return [Rex::Socket::Tcp]135def create_tcp_connection136self.connection = Rex::Socket::Tcp.create(137'PeerHost' => host,138'PeerPort' => port.to_i,139'Proxies' => proxies,140'Context' => context,141'Timeout' => timeout142)143end144145# Sends a Kerberos Request over a tcp connection146#147# @param req [Rex::Proto::Kerberos::Model::KdcRequest] the request to send148# @return [Integer] the number of bytes sent149# @raise [RuntimeError] if the request can't be encoded150def send_request_tcp(req)151data = req.encode152length = [data.length].pack('N')153connection.put(length + data)154end155156# UDP isn't supported157#158# @raise [NotImplementedError]159def send_request_udp(req)160raise ::NotImplementedError, 'Kerberos Client: UDP unsupported'161end162163# Receives a Kerberos Response over a tcp connection164#165# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse>] the kerberos message response166# @raise [Rex::Proto::Kerberos::Model::Error::KerberosDecodingError] if the response can't be processed167# @raise [EOFError] if expected data can't be read168def recv_response_tcp169remaining = timeout170length_raw, elapsed_time = Rex::Stopwatch.elapsed_time do171connection.get_once(4, remaining)172end173remaining -= elapsed_time174unless length_raw && length_raw.length == 4175if remaining <= 0176raise Rex::TimeoutError, 'Kerberos Client: failed to read response length due to timeout'177end178179raise ::EOFError, 'Kerberos Client: failed to read response length'180end181length = length_raw.unpack('N')[0]182183data = ''184while data.length < length && remaining > 0185chunk, elapsed_time = Rex::Stopwatch.elapsed_time do186connection.get_once(length - data.length, remaining)187end188189remaining -= elapsed_time190break if chunk.nil?191192data << chunk193end194195unless data.length == length196if remaining <= 0197raise Rex::TimeoutError, 'Kerberos Client: failed to read response due to timeout'198end199200raise ::EOFError, 'Kerberos Client: failed to read response'201end202203decode_kerb_response(data)204end205206# UDP isn't supported207#208# @raise [NotImplementedError]209def recv_response_udp210raise ::NotImplementedError, 'Kerberos Client: UDP unsupported'211end212213private214215# Decodes a Kerberos response216#217# @param data [String] the raw response message218# @return [<Rex::Proto::Kerberos::Model::KrbError, Rex::Proto::Kerberos::Model::KdcResponse, Rex::Proto::Kerberos::Model::KrbError>] the kerberos message response219# @raise [Rex::Proto::Kerberos::Model::Error::KerberosDecodingError] if the response can't be processed220def decode_kerb_response(data)221asn1 = OpenSSL::ASN1.decode(data)222msg_type = asn1.value[0].value[1].value[0].value223224case msg_type225when Rex::Proto::Kerberos::Model::KRB_ERROR226res = Rex::Proto::Kerberos::Model::KrbError.decode(asn1)227when Rex::Proto::Kerberos::Model::AS_REP, Rex::Proto::Kerberos::Model::TGS_REP228res = Rex::Proto::Kerberos::Model::KdcResponse.decode(asn1)229when Rex::Proto::Kerberos::Model::AP_REP230res = Rex::Proto::Kerberos::Model::ApRep.decode(asn1)231else232raise ::Rex::Proto::Kerberos::Model::Error::KerberosDecodingError, 'Kerberos Client: Unknown response'233end234235res236end237end238end239end240end241242243