Skip to content

Commit

Permalink
Merge 013c9ed into 93bed5e
Browse files Browse the repository at this point in the history
  • Loading branch information
zeroSteiner committed Sep 21, 2020
2 parents 93bed5e + 013c9ed commit 45fd718
Show file tree
Hide file tree
Showing 18 changed files with 680 additions and 7 deletions.
4 changes: 3 additions & 1 deletion lib/ruby_smb/dcerpc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ module Dcerpc
require 'ruby_smb/dcerpc/rpc_security_attributes'
require 'ruby_smb/dcerpc/pdu_header'
require 'ruby_smb/dcerpc/srvsvc'
require 'ruby_smb/dcerpc/winreg'
require 'ruby_smb/dcerpc/svcctl'
require 'ruby_smb/dcerpc/winreg'
require 'ruby_smb/dcerpc/netlogon'
require 'ruby_smb/dcerpc/request'
require 'ruby_smb/dcerpc/response'
require 'ruby_smb/dcerpc/bind'
require 'ruby_smb/dcerpc/bind_ack'



# Bind to the remote server interface endpoint.
#
# @param options [Hash] the options to pass to the Bind request packet. At least, :endpoint must but provided with an existing Dcerpc class
Expand Down
97 changes: 97 additions & 0 deletions lib/ruby_smb/dcerpc/ndr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ module Ndr
VER_MAJOR = 2
VER_MINOR = 0

# An NDR Enum type as defined in
# [Transfer Syntax NDR - Enumerated Types](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_02_05_01)
class NdrEnum < BinData::Int16le; end

# An NDR Conformant and Varying String representation as defined in
# [Transfer Syntax NDR - Conformant and Varying Strings](http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_04_02)
Expand Down Expand Up @@ -92,6 +95,100 @@ def set(v)
end
end

# An NDR Uni-dimensional Fixed Array of bytes representation as defined in:
# [Transfer Syntax NDR - NDR Constructed Types](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_03_01)
class NdrFixedByteArray < BinData::BasePrimitive
optional_parameters :read_length, :length, :pad_byte, :pad_front
default_parameters pad_byte: 0
mutually_exclusive_parameters :length, :value

def initialize_shared_instance
if (has_parameter?(:value) || has_parameter?(:asserted_value)) && !has_parameter?(:read_length)
extend WarnNoReadLengthPlugin
end
super
end

def assign(val)
super(fixed_byte_array(val))
end

def snapshot
clamp_to_length(super)
end

class << self
def arg_processor
NdrFixedByteArrayArgProcessor.new
end
end

private

def clamp_to_length(val)
val = fixed_byte_array(val)
len = eval_parameter(:length) || val.length
if val.length > len
val = val.first(len)
elsif val.length < len
pad = eval_parameter(:pad_byte)
if get_parameter(:pad_front)
val = val.insert(0, *Array.new(len - val.length, pad))
else
val = val.fill(pad, val.length...len)
end
end

val
end

def fixed_byte_array(val)
val = val.bytes if val.is_a? String
val.to_ary
end

def read_and_return_value(io)
len = eval_parameter(:read_length) || eval_parameter(:length) || 0
io.readbytes(len)
end

def sensible_default
[ ]
end

def value_to_binary_string(val)
clamp_to_length(val).pack('C*')
end

class NdrFixedByteArrayArgProcessor < BinData::BaseArgProcessor
def sanitize_parameters!(obj_class, obj_params)
obj_params.must_be_integer(:length, :pad_byte)
obj_params.sanitize(:pad_byte) { |byte| sanitized_pad_byte(byte) }
end

private

def sanitized_pad_byte(byte)
if byte.is_a?(String)
raise ArgumentError, ':pad_byte must not contain more than 1 byte' if byte.bytesize > 1

byte = byte.ord
end
raise ArgumentError, ':pad_byte must be within the range of 0 - 255' unless ((byte >= 0) && (byte <= 255))

byte
end
end

# Warns when reading if :value && no :read_length
module WarnNoReadLengthPlugin
def read_and_return_value(io)
warn "#{debug_name} does not have a :read_length parameter - returning empty array"
""
end
end
end

# An NDR Context Handle representation as defined in
# [IDL Data Type Declarations - Basic Type Declarations](http://pubs.opengroup.org/onlinepubs/9629399/apdxn.htm#tagcjh_34_01)
class NdrContextHandle < BinData::Primitive
Expand Down
101 changes: 101 additions & 0 deletions lib/ruby_smb/dcerpc/netlogon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
module RubySMB
module Dcerpc
module Netlogon

# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/592edbc8-f6f1-40c0-9ab3-fe6725ac6d7e
UUID = '12345678-1234-abcd-ef00-01234567cffb'
VER_MAJOR = 1
VER_MINOR = 0

# Operation numbers
NETR_SERVER_REQ_CHALLENGE = 4
NETR_SERVER_AUTHENTICATE3 = 26
NETR_SERVER_PASSWORD_SET2 = 30

# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/3b224201-b531-43e2-8c79-b61f6dea8640
class LogonsrvHandle < Ndr::NdrLpStr; end

# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/d55e2632-7163-4f6c-b662-4b870e8cc1cd
class NetlogonCredential < Ndr::NdrFixedByteArray
default_parameters length: 8
end

# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/76c93227-942a-4687-ab9d-9d972ffabdab
class NetlogonAuthenticator < BinData::Record
endian :little

netlogon_credential :credential
uint32 :timestamp
end

# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/4d1235e3-2c96-4e9f-a147-3cb338a0d09f
class NetlogonSecureChannelType < Ndr::NdrEnum
# enum example from dmendel/bindata#38 https://github.com/dmendel/bindata/issues/38#issuecomment-46397163
ALL = {
0 => :NullSecureChannel,
1 => :MsvApSecureChannel,
2 => :WorkstationSecureChannel,
3 => :TrustedDnsDomainSecureChannel,
4 => :TrustedDomainSecureChannel,
5 => :UasServerSecureChannel,
6 => :ServerSecureChannel,
7 => :CdcServerSecureChannel
}
ALL.each_pair { |val,sym| const_set(sym.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').upcase, val) }
default_parameter assert: -> { ALL.keys.include? value }

def as_enum
ALL[value]
end

def assign(val)
if val.is_a? Symbol
val = ALL.key(val)
raise ArgumentError, 'invalid value name' if val.nil?
end

super
end
end

require 'ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request'
require 'ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response'
require 'ruby_smb/dcerpc/netlogon/netr_server_password_set2_request'
require 'ruby_smb/dcerpc/netlogon/netr_server_password_set2_response'
require 'ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request'
require 'ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response'

# Calculate the netlogon session key from the provided shared secret and
# challenges. The shared secret is an NTLM hash.
#
# @param shared_secret [String] the share secret between the client and the server
# @param client_challenge [String] the client challenge portion of the negotiation
# @param server_challenge [String] the server challenge portion of the negotiation
# @return [String] the session key for encryption
def self.calculate_session_key(shared_secret, client_challenge, server_challenge)
client_challenge = client_challenge.to_binary_s if client_challenge.is_a? NetlogonCredential
server_challenge = server_challenge.to_binary_s if server_challenge.is_a? NetlogonCredential

hmac = OpenSSL::HMAC.new(shared_secret, OpenSSL::Digest::SHA256.new)
hmac << client_challenge
hmac << server_challenge
hmac.digest.first(16)
end

# Encrypt the input data using the specified session key. This is used for
# certain Netlogon service operations including the authentication
# process. Per the specification, this uses AES-128-CFB8 with an all zero
# initialization vector.
#
# @param session_key [String] the session key to use for encryption (must be 16 bytes long)
# @param input_data [String] the data to encrypt
# @return [String] the encrypted data
def self.encrypt_credential(session_key, input_data)
cipher = OpenSSL::Cipher.new('AES-128-CFB8').encrypt
cipher.iv = "\x00" * 16
cipher.key = session_key
cipher.update(input_data) + cipher.final
end
end
end
end
28 changes: 28 additions & 0 deletions lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'ruby_smb/dcerpc/ndr'

module RubySMB
module Dcerpc
module Netlogon

# [3.5.4.4.2 NetrServerAuthenticate3 (Opnum 26)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/3a9ed16f-8014-45ae-80af-c0ecb06e2db9)
class NetrServerAuthenticate3Request < BinData::Record
attr_reader :opnum

endian :little

logonsrv_handle :primary_name
ndr_string :account_name
netlogon_secure_channel_type :secure_channel_type
ndr_string :computer_name
netlogon_credential :client_credential
uint32 :flags

def initialize_instance
super
@opnum = NETR_SERVER_AUTHENTICATE3
end

end
end
end
end
26 changes: 26 additions & 0 deletions lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require 'ruby_smb/dcerpc/ndr'

module RubySMB
module Dcerpc
module Netlogon

# [3.5.4.4.2 NetrServerAuthenticate3 (Opnum 26)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/3a9ed16f-8014-45ae-80af-c0ecb06e2db9)
class NetrServerAuthenticate3Response < BinData::Record
attr_reader :opnum

endian :little

netlogon_credential :server_credential
uint32 :negotiate_flags
uint32 :account_rid
uint32 :error_status

def initialize_instance
super
@opnum = NETR_SERVER_AUTHENTICATE3
end

end
end
end
end
27 changes: 27 additions & 0 deletions lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require 'ruby_smb/dcerpc/ndr'

module RubySMB
module Dcerpc
module Netlogon

# [3.5.4.4.5 NetrServerPasswordSet2 (Opnum 30)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/14b020a8-0bcf-4af5-ab72-cc92bc6b1d81)
class NetrServerPasswordSet2Request < BinData::Record
attr_reader :opnum

endian :little

logonsrv_handle :primary_name
ndr_string :account_name
netlogon_secure_channel_type :secure_channel_type
ndr_string :computer_name
netlogon_authenticator :authenticator
ndr_fixed_byte_array :clear_new_password, length: 516 # this is an encrypted NL_TRUST_PASSWORD

def initialize_instance
super
@opnum = Netlogon::NETR_SERVER_PASSWORD_SET2
end
end
end
end
end
23 changes: 23 additions & 0 deletions lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'ruby_smb/dcerpc/ndr'

module RubySMB
module Dcerpc
module Netlogon

# [3.5.4.4.5 NetrServerPasswordSet2 (Opnum 30)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/14b020a8-0bcf-4af5-ab72-cc92bc6b1d81)
class NetrServerPasswordSet2Response < BinData::Record
attr_reader :opnum

endian :little

netlogon_authenticator :return_authenticator
uint32 :error_status

def initialize_instance
super
@opnum = Netlogon::NETR_SERVER_PASSWORD_SET2
end
end
end
end
end
25 changes: 25 additions & 0 deletions lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'ruby_smb/dcerpc/ndr'

module RubySMB
module Dcerpc
module Netlogon

# [3.5.4.4.1 NetrServerReqChallenge (Opnum 4)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/5ad9db9f-7441-4ce5-8c7b-7b771e243d32)
class NetrServerReqChallengeRequest < BinData::Record
attr_reader :opnum

endian :little

logonsrv_handle :primary_name
ndr_string :computer_name
netlogon_credential :client_challenge

def initialize_instance
super
@opnum = NETR_SERVER_REQ_CHALLENGE
end

end
end
end
end
24 changes: 24 additions & 0 deletions lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require 'ruby_smb/dcerpc/ndr'

module RubySMB
module Dcerpc
module Netlogon

# [3.5.4.4.1 NetrServerReqChallenge (Opnum 4)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/5ad9db9f-7441-4ce5-8c7b-7b771e243d32)
class NetrServerReqChallengeResponse < BinData::Record
attr_reader :opnum

endian :little

netlogon_credential :server_challenge
uint32 :error_status

def initialize_instance
super
@opnum = NETR_SERVER_REQ_CHALLENGE
end

end
end
end
end

0 comments on commit 45fd718

Please sign in to comment.