Skip to content

Commit ac40b10

Browse files
authored
Merge pull request #284 from zeroSteiner/feat/dcerpc/gkdi/1
Add MS-GKDI Structures
2 parents 984a58b + 2071a83 commit ac40b10

File tree

9 files changed

+202
-0
lines changed

9 files changed

+202
-0
lines changed

lib/ruby_smb/dcerpc.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ module Dcerpc
5050
require 'ruby_smb/dcerpc/icpr'
5151
require 'ruby_smb/dcerpc/efsrpc'
5252
require 'ruby_smb/dcerpc/lsarpc'
53+
require 'ruby_smb/dcerpc/gkdi'
5354
require 'ruby_smb/dcerpc/request'
5455
require 'ruby_smb/dcerpc/response'
5556
require 'ruby_smb/dcerpc/rpc_auth3'

lib/ruby_smb/dcerpc/error.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ def initialize(msg, status_code: nil)
7070
super(msg)
7171
end
7272
end
73+
74+
class GkdiError < DcerpcError
75+
include RubySMB::Error::UnexpectedStatusCode::Mixin
76+
77+
def initialize(msg, status_code: nil)
78+
self.status_code = status_code unless status_code.nil?
79+
80+
super(msg)
81+
end
82+
end
7383
end
7484
end
7585
end

lib/ruby_smb/dcerpc/gkdi.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
module RubySMB
2+
module Dcerpc
3+
module Gkdi
4+
5+
# [2.1 Transport](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/2ca63ad2-2464-4a41-ba84-2e0270e95e86)
6+
UUID = 'b9785960-524f-11df-8b6d-83dcded72085'
7+
VER_MAJOR = 1
8+
VER_MINOR = 0
9+
10+
# Operation numbers
11+
GKDI_GET_KEY = 0x0000
12+
13+
require 'ruby_smb/dcerpc/gkdi/gkdi_get_key_request'
14+
require 'ruby_smb/dcerpc/gkdi/gkdi_get_key_response'
15+
require 'ruby_smb/dcerpc/gkdi/gkdi_ffc_dh_key'
16+
require 'ruby_smb/dcerpc/gkdi/gkdi_ffc_dh_parameters'
17+
require 'ruby_smb/dcerpc/gkdi/gkdi_group_key_envelope'
18+
19+
def gkdi_get_key(target_sd, root_key_id, l0_key_id, l1_key_id, l2_key_id)
20+
target_sd = target_sd.to_binary_s if target_sd.respond_to?(:to_binary_s)
21+
22+
gkdi_get_key_request = GkdiGetKeyRequest.new(
23+
cb_target_sd: target_sd.length,
24+
pb_target_sd: target_sd.unpack('C*'),
25+
p_root_key_id: root_key_id,
26+
l0_key_id: l0_key_id,
27+
l1_key_id: l1_key_id,
28+
l2_key_id: l2_key_id
29+
)
30+
31+
response = dcerpc_request(
32+
gkdi_get_key_request,
33+
auth_level: @auth_level,
34+
auth_type: @auth_type
35+
)
36+
begin
37+
gkdi_get_key_response = GkdiGetKeyResponse.read(response)
38+
rescue IOError
39+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading CertServerRequestResponse'
40+
end
41+
unless gkdi_get_key_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
42+
status_code = WindowsError::Win32.find_by_retval(gkdi_get_key_response.error_status.value).first
43+
raise RubySMB::Dcerpc::Error::GkdiError.new(
44+
"Error returned with gkdi_get_key: #{status_code}",
45+
status_code: status_code
46+
)
47+
end
48+
49+
GkdiGroupKeyEnvelope.read(gkdi_get_key_response.pbb_out.snapshot.pack('C*'))
50+
end
51+
52+
end
53+
end
54+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module RubySMB
2+
module Dcerpc
3+
module Gkdi
4+
5+
# [2.2.3.1 FFC DH Key](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/f8770f01-036d-4bf6-a4cf-1bd0e3913404)
6+
class GkdiFfcDhKey < BinData::Record
7+
endian :little
8+
9+
uint8_array :magic, initial_length: 4, initial_value: [ 0x44, 0x48, 0x50, 0x42 ]
10+
uint32 :key_length
11+
uint8_array :field_order, initial_length: :key_length
12+
uint8_array :generator, initial_length: :key_length
13+
uint8_array :public_key, initial_length: :key_length
14+
end
15+
end
16+
end
17+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module RubySMB
2+
module Dcerpc
3+
module Gkdi
4+
5+
# [2.2.2 FFC DH Parameters](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/e15ae269-ee21-446a-a480-de3ea243db5f)
6+
class GkdiFfcDhParameters < BinData::Record
7+
endian :little
8+
9+
uint32 :parameters_length, initial_value: -> { (key_length * 2) + offset_of(generator) }
10+
uint8_array :magic, initial_length: 4, initial_value: [ 0x44, 0x48, 0x50, 0x4d ]
11+
uint32 :key_length
12+
uint8_array :field_order, initial_length: :key_length
13+
uint8_array :generator, initial_length: :key_length
14+
end
15+
end
16+
end
17+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module RubySMB
2+
module Dcerpc
3+
module Gkdi
4+
5+
# [3.1.4.1 GetKey (Opnum 0)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/4cac87a3-521e-4918-a272-240f8fabed39)
6+
class GkdiGetKeyRequest < BinData::Record
7+
attr_reader :opnum
8+
9+
endian :little
10+
11+
ndr_uint32 :cb_target_sd
12+
ndr_conf_array :pb_target_sd, type: :ndr_uint8
13+
uuid_ptr :p_root_key_id
14+
ndr_int32 :l0_key_id
15+
ndr_int32 :l1_key_id
16+
ndr_int32 :l2_key_id
17+
18+
def initialize_instance
19+
super
20+
@opnum = GKDI_GET_KEY
21+
end
22+
end
23+
24+
end
25+
end
26+
end
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module RubySMB
2+
module Dcerpc
3+
module Gkdi
4+
5+
# [3.1.4.1 GetKey (Opnum 0)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/4cac87a3-521e-4918-a272-240f8fabed39)
6+
class GkdiGetKeyResponse < BinData::Record
7+
attr_reader :opnum
8+
9+
endian :little
10+
11+
ndr_uint32 :pcb_out
12+
ndr_byte_conf_array_ptr :pbb_out
13+
ndr_uint32 :error_status
14+
15+
def initialize_instance
16+
super
17+
@opnum = GKDI_GET_KEY
18+
end
19+
end
20+
21+
end
22+
end
23+
end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
module RubySMB
2+
module Dcerpc
3+
module Gkdi
4+
5+
# [2.2.4 Group Key Envelope](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/192c061c-e740-4aa0-ab1d-6954fb3e58f7)
6+
class GkdiGroupKeyEnvelope < BinData::Record
7+
endian :little
8+
9+
uint32 :version
10+
uint8_array :magic, initial_length: 4, initial_value: [ 0x4b, 0x44, 0x53, 0x5b ]
11+
uint32 :dw_flags
12+
uint32 :l0_index
13+
uint32 :l1_index
14+
uint32 :l2_index
15+
uuid :root_key_identifier
16+
uint32 :cb_kdf_algorithm
17+
uint32 :cb_kdf_parameters, initial_value: -> { kdf_parameters.length }
18+
uint32 :cb_secret_agreement_algorithm
19+
uint32 :cb_secret_agreement_parameters
20+
uint32 :private_key_length
21+
uint32 :public_key_length
22+
uint32 :cb_l1_key
23+
uint32 :cb_l2_key
24+
uint32 :cb_domain_name
25+
uint32 :cb_forest_name
26+
stringz16 :kdf_algorithm
27+
struct :kdf_parameters, only_if: -> { cb_kdf_parameters > 0 } do
28+
uint8_array :block0, initial_length: 8, initial_value: [ 0, 0, 0, 0, 1, 0, 0, 0 ]
29+
uint32 :length_of_hash_name, initial_value: -> { hash_algorithm_name.length }
30+
uint8_array :block1, initial_length: 4, initial_value: [ 0, 0, 0, 0 ]
31+
stringz16 :hash_algorithm_name
32+
end
33+
stringz16 :secret_agreement_algorithm
34+
uint8_array :secret_agreement_parameters, initial_length: :cb_secret_agreement_parameters
35+
stringz16 :domain_name
36+
stringz16 :forest_name
37+
uint8_array :l1_key, initial_length: 64, only_if: -> { cb_l1_key != 0 }
38+
uint8_array :l2_key, initial_length: :l2_key_length, only_if: -> { cb_l2_key != 0 }
39+
40+
private
41+
42+
def l2_key_length
43+
return 0 if cb_l2_key == 0
44+
return 64 if (dw_flags & (1 << 31)) == 0
45+
46+
public_key_length
47+
end
48+
end
49+
end
50+
end
51+
end

lib/ruby_smb/dcerpc/request.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ class Request < BinData::Record
124124
lsar_close_handle_request Lsarpc::LSAR_CLOSE_HANDLE
125125
lsar_lookup_sids_request Lsarpc::LSAR_LOOKUP_SIDS
126126
end
127+
choice 'Gkdi', selection: -> { opnum } do
128+
gkdi_get_key_request Gkdi::GKDI_GET_KEY
129+
end
127130
string :default
128131
end
129132

0 commit comments

Comments
 (0)