Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-rdp_ear.c
blobde903bd6e154773aaa7cf90d279d11c2df8b69d2
1 /* Packet-rdp_ear.c
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
13 * See: "[MS-RDPEAR] "
16 #include "config.h"
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;
61 typedef enum {
62 RCG_PACKAGE_KERBEROS,
63 RCG_PACKAGE_NTLM,
64 RCG_PACKAGE_UNKNOWN = 1,
65 } RcgPackageType;
67 typedef struct {
68 RcgPackageType lastPackage;
69 } RcgContext;
71 static int
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);
74 return offset;
77 static int
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;
85 if (packageName) {
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;
95 return offset;
99 static int
100 dissect_rdpear_packagePayload(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, RcgPackageType package)
102 int offset = 0;
103 gboolean isServerTarget = rdp_isServerAddressTarget(pinfo);
105 proto_tree_add_item(tree, hf_rdpear_package_reservedHeader, tvb, offset, 16, ENC_NA);
106 offset += 16;
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);
116 switch (package) {
117 case RCG_PACKAGE_KERBEROS:
118 // NDR headers
119 offset += 24;
120 if (isServerTarget)
121 offset = rcg_dissect_struct_KerbCredIsoRemoteOutput(tvb, offset, pinfo, tree, &di, drep, hf_rdpear_package_command, 0);
122 else
123 offset = rcg_dissect_struct_KerbCredIsoRemoteInput(tvb, offset, pinfo, tree, &di, drep, hf_rdpear_package_command, 0);
125 break;
126 case RCG_PACKAGE_NTLM:
127 // NDR headers
128 offset += 20;
130 if (isServerTarget)
131 offset = rcg_dissect_struct_NtlmCredIsoRemoteOutput(tvb, offset, pinfo, tree, &di, drep, hf_rdpear_package_command, 0);
132 else
133 offset = rcg_dissect_struct_NtlmCredIsoRemoteInput(tvb, offset, pinfo, tree, &di, drep, hf_rdpear_package_command, 0);
134 break;
135 default:
136 break;
139 return offset;
143 static int
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);
148 if (packageData)
149 dissect_rdpear_packagePayload(tree, actx->pinfo, packageData, rcg->lastPackage);
150 return offset;
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 };
165 asn1_ctx_t asn1_ctx;
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);
172 return offset;
175 static int
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;
181 proto_item *item;
182 int nextOffset, offset = 0;
183 uint32_t pduLength;
184 proto_tree *tree;
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);
197 offset += 4;
199 proto_tree_add_item(tree, hf_rdpear_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
200 offset += 4;
202 proto_tree_add_item(tree, hf_rdpear_version, tvb, offset, 4, ENC_LITTLE_ENDIAN);
203 offset += 4;
205 proto_tree_add_item(tree, hf_rdpear_reserved, tvb, offset, 4, ENC_LITTLE_ENDIAN);
206 offset += 4;
208 proto_tree_add_item(tree, hf_rdpear_tspkgcontext, tvb, offset, 8, ENC_LITTLE_ENDIAN);
209 offset += 8;
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);
223 offset = nextOffset;
224 return offset;
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,
233 NULL, HFILL }},
234 { &hf_rdpear_length,
235 { "Length", "rdp_ear.length",
236 FT_UINT32, BASE_DEC, NULL, 0x0,
237 NULL, HFILL }},
238 { &hf_rdpear_version,
239 { "Version", "rdp_ear.version",
240 FT_UINT32, BASE_HEX, NULL, 0x0,
241 NULL, HFILL }},
242 { &hf_rdpear_reserved,
243 { "Reserved", "rdp_ear.reserved",
244 FT_UINT32, BASE_HEX, NULL, 0x0,
245 NULL, HFILL }},
246 { &hf_rdpear_tspkgcontext,
247 { "TsPkgContext", "rdp_ear.tspkgcontext",
248 FT_UINT64, BASE_HEX, NULL, 0x0,
249 NULL, HFILL }},
250 { &hf_rdpear_payload,
251 { "Payload", "rdp_ear.payload",
252 FT_NONE, BASE_NONE, NULL, 0,
253 NULL, HFILL }},
254 { &hf_rdpear_packet_version,
255 { "Version", "rdp_ear.payload.version",
256 FT_INT32, BASE_DEC, NULL, 0,
257 NULL, HFILL }},
258 { &hf_rdpear_packet_packageName,
259 { "Package", "rdp_ear.payload.package",
260 FT_STRING, BASE_NONE, NULL, 0,
261 NULL, HFILL }},
262 { &hf_rdpear_packet_buffer,
263 { "Buffer", "rdp_ear.payload.buffer",
264 FT_BYTES, BASE_NONE, NULL, 0,
265 NULL, HFILL }},
266 { &hf_rdpear_package_reservedHeader,
267 { "Reserved", "rdp_ear.package.reservedheader",
268 FT_BYTES, BASE_NONE, NULL, 0,
269 NULL, HFILL }},
270 { &hf_rdpear_package_command,
271 { "Command", "rdp_ear.package.command",
272 FT_BYTES, BASE_NONE, NULL, 0,
273 NULL, HFILL }},
277 static int *ett[] = {
278 &ett_rdp_ear,
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);