2 * Routines for the redirected authentication RDP channel
3 * Copyright 2023, David Fort <contact@hardening-consulting.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include <epan/packet.h>
19 #include <epan/prefs.h>
20 #include <epan/conversation.h>
21 #include <epan/expert.h>
22 #include <epan/value_string.h>
23 #include <epan/asn1.h>
25 #include "packet-rdpudp.h"
26 #include "packet-gssapi.h"
27 #include "packet-ber.h"
28 #include "packet-dcerpc.h"
29 #include "packet-dcerpc-rcg.h"
32 #define PNAME "RDP authentication redirection virtual channel Protocol"
33 #define PSNAME "rdpear"
34 #define PFNAME "rdp_ear"
36 void proto_register_rdp_ear(void);
37 void proto_reg_handoff_rdp_ear(void);
40 static int proto_rdp_ear
;
42 static int hf_rdpear_protocolMagic
;
43 static int hf_rdpear_length
;
44 static int hf_rdpear_version
;
45 static int hf_rdpear_reserved
;
46 static int hf_rdpear_tspkgcontext
;
48 static int hf_rdpear_payload
;
49 static int hf_rdpear_packet_version
;
50 static int hf_rdpear_packet_packageName
;
51 static int hf_rdpear_packet_buffer
;
53 static int hf_rdpear_package_reservedHeader
;
54 static int hf_rdpear_package_command
;
56 static int ett_rdp_ear
;
57 static int ett_rdp_ear_innerPacket
;
59 static dissector_handle_t gssapi_wrap_handle
;
64 RCG_PACKAGE_UNKNOWN
= 1,
68 RcgPackageType lastPackage
;
72 dissect_rdpear_ber_VERSION(bool implicit_tag
, tvbuff_t
*tvb
, int offset
, asn1_ctx_t
*actx
, proto_tree
*tree
, int hf_index
) {
73 offset
= dissect_ber_integer(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
, NULL
);
78 dissect_rdpear_ber_packageName(bool implicit_tag
, tvbuff_t
*tvb
, int offset
, asn1_ctx_t
*actx
, proto_tree
*tree
, int hf_index
) {
79 RcgContext
*rcg
= (RcgContext
*)actx
->private_data
;
81 tvbuff_t
*packageName
= NULL
;
82 offset
= dissect_ber_octet_string_with_encoding(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
, &packageName
, ENC_UTF_16
|ENC_LITTLE_ENDIAN
);
84 rcg
->lastPackage
= RCG_PACKAGE_UNKNOWN
;
86 char kerb
[] = {'K', 0, 'e', 0, 'r', 0, 'b', 0, 'e', 0, 'r', 0, 'o', 0, 's', 0 };
87 char ntlm
[] = {'N', 0, 'T', 0, 'L', 0, 'M', 0 };
89 if (tvb_memeql(packageName
, 0, kerb
, sizeof(kerb
)) == 0)
90 rcg
->lastPackage
= RCG_PACKAGE_KERBEROS
;
91 else if (tvb_memeql(packageName
, 0, ntlm
, sizeof(ntlm
)) == 0)
92 rcg
->lastPackage
= RCG_PACKAGE_NTLM
;
100 dissect_rdpear_packagePayload(proto_tree
*tree
, packet_info
*pinfo
, tvbuff_t
*tvb
, RcgPackageType package
)
103 gboolean isServerTarget
= rdp_isServerAddressTarget(pinfo
);
105 proto_tree_add_item(tree
, hf_rdpear_package_reservedHeader
, tvb
, offset
, 16, ENC_NA
);
108 dcerpc_info di
= { 0 };
109 guint8 drep
[4] = { 0x10, 0x00, 0x00, 0x00};
111 dcerpc_call_value call_data
= { 0 };
112 di
.conformant_run
= 0;
113 di
.call_data
= &call_data
;
114 init_ndr_pointer_list(&di
);
117 case RCG_PACKAGE_KERBEROS
:
121 offset
= rcg_dissect_struct_KerbCredIsoRemoteOutput(tvb
, offset
, pinfo
, tree
, &di
, drep
, hf_rdpear_package_command
, 0);
123 offset
= rcg_dissect_struct_KerbCredIsoRemoteInput(tvb
, offset
, pinfo
, tree
, &di
, drep
, hf_rdpear_package_command
, 0);
126 case RCG_PACKAGE_NTLM
:
131 offset
= rcg_dissect_struct_NtlmCredIsoRemoteOutput(tvb
, offset
, pinfo
, tree
, &di
, drep
, hf_rdpear_package_command
, 0);
133 offset
= rcg_dissect_struct_NtlmCredIsoRemoteInput(tvb
, offset
, pinfo
, tree
, &di
, drep
, hf_rdpear_package_command
, 0);
144 dissect_rdpear_ber_packetBuffer(bool implicit_tag
, tvbuff_t
*tvb
, int offset
, asn1_ctx_t
*actx
, proto_tree
*tree
, int hf_index
) {
145 RcgContext
*rcg
= (RcgContext
*)actx
->private_data
;
146 tvbuff_t
*packageData
= NULL
;
147 offset
= dissect_ber_octet_string(implicit_tag
, actx
, tree
, tvb
, offset
, hf_index
, &packageData
);
149 dissect_rdpear_packagePayload(tree
, actx
->pinfo
, packageData
, rcg
->lastPackage
);
154 static const ber_sequence_t TSRemoteGuardInnerPacket_sequence
[] = {
155 { &hf_rdpear_packet_version
, BER_CLASS_CON
, 0, BER_FLAGS_OPTIONAL
, dissect_rdpear_ber_VERSION
},
156 { &hf_rdpear_packet_packageName
, BER_CLASS_CON
, 1, 0, dissect_rdpear_ber_packageName
},
157 { &hf_rdpear_packet_buffer
, BER_CLASS_CON
, 2, 0, dissect_rdpear_ber_packetBuffer
},
158 { NULL
, 0, 0, 0, NULL
}
162 static int dissect_rcg_payload(packet_info
*pinfo
, proto_tree
*tree
, tvbuff_t
*tvb
, int offset
)
164 RcgContext rcg
= { RCG_PACKAGE_UNKNOWN
};
166 asn1_ctx_init(&asn1_ctx
, ASN1_ENC_BER
, true, pinfo
);
167 asn1_ctx
.private_data
= &rcg
;
169 offset
= dissect_ber_sequence(false, &asn1_ctx
, tree
, tvb
, offset
,
170 TSRemoteGuardInnerPacket_sequence
, hf_rdpear_payload
, ett_rdp_ear_innerPacket
);
176 dissect_rdp_ear(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void *data _U_
)
178 tvbuff_t
*payload_tvb
= NULL
;
179 tvbuff_t
*decr_tvb
= NULL
;
180 gssapi_encrypt_info_t gssapi_encrypt
;
182 int nextOffset
, offset
= 0;
186 parent_tree
= proto_tree_get_root(parent_tree
);
187 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RDPEAR");
188 col_clear(pinfo
->cinfo
, COL_INFO
);
190 pduLength
= tvb_get_uint32(tvb
, offset
+ 4, ENC_LITTLE_ENDIAN
) + 24;
191 nextOffset
= offset
+ pduLength
;
193 item
= proto_tree_add_item(parent_tree
, proto_rdp_ear
, tvb
, offset
, pduLength
, ENC_NA
);
194 tree
= proto_item_add_subtree(item
, ett_rdp_ear
);
196 proto_tree_add_item(tree
, hf_rdpear_protocolMagic
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
199 proto_tree_add_item(tree
, hf_rdpear_length
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
202 proto_tree_add_item(tree
, hf_rdpear_version
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
205 proto_tree_add_item(tree
, hf_rdpear_reserved
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
208 proto_tree_add_item(tree
, hf_rdpear_tspkgcontext
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
211 /* ================== */
212 payload_tvb
= tvb_new_subset_length(tvb
, offset
, pduLength
- 24);
213 memset(&gssapi_encrypt
, 0, sizeof(gssapi_encrypt
));
214 gssapi_encrypt
.decrypt_gssapi_tvb
= DECRYPT_GSSAPI_NORMAL
;
215 call_dissector_with_data(gssapi_wrap_handle
, payload_tvb
, pinfo
, tree
, &gssapi_encrypt
);
217 decr_tvb
= gssapi_encrypt
.gssapi_decrypted_tvb
;
219 if (decr_tvb
!= NULL
) {
220 dissect_rcg_payload(pinfo
, tree
, decr_tvb
, 0);
228 void proto_register_rdp_ear(void) {
229 static hf_register_info hf
[] = {
230 { &hf_rdpear_protocolMagic
,
231 { "Protocol magic", "rdp_ear.magic",
232 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
235 { "Length", "rdp_ear.length",
236 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
238 { &hf_rdpear_version
,
239 { "Version", "rdp_ear.version",
240 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
242 { &hf_rdpear_reserved
,
243 { "Reserved", "rdp_ear.reserved",
244 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
246 { &hf_rdpear_tspkgcontext
,
247 { "TsPkgContext", "rdp_ear.tspkgcontext",
248 FT_UINT64
, BASE_HEX
, NULL
, 0x0,
250 { &hf_rdpear_payload
,
251 { "Payload", "rdp_ear.payload",
252 FT_NONE
, BASE_NONE
, NULL
, 0,
254 { &hf_rdpear_packet_version
,
255 { "Version", "rdp_ear.payload.version",
256 FT_INT32
, BASE_DEC
, NULL
, 0,
258 { &hf_rdpear_packet_packageName
,
259 { "Package", "rdp_ear.payload.package",
260 FT_STRING
, BASE_NONE
, NULL
, 0,
262 { &hf_rdpear_packet_buffer
,
263 { "Buffer", "rdp_ear.payload.buffer",
264 FT_BYTES
, BASE_NONE
, NULL
, 0,
266 { &hf_rdpear_package_reservedHeader
,
267 { "Reserved", "rdp_ear.package.reservedheader",
268 FT_BYTES
, BASE_NONE
, NULL
, 0,
270 { &hf_rdpear_package_command
,
271 { "Command", "rdp_ear.package.command",
272 FT_BYTES
, BASE_NONE
, NULL
, 0,
277 static int *ett
[] = {
279 &ett_rdp_ear_innerPacket
,
282 proto_rdp_ear
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
284 /* Register fields and subtrees */
285 proto_register_field_array(proto_rdp_ear
, hf
, array_length(hf
));
286 proto_register_subtree_array(ett
, array_length(ett
));
288 register_dissector("rdp_ear", dissect_rdp_ear
, proto_rdp_ear
);
291 void proto_reg_handoff_rdp_ear(void) {
292 gssapi_wrap_handle
= find_dissector_add_dependency("gssapi_verf", proto_rdp_ear
);