1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Gabriel Potter
5
6"""
7Python objects for Microsoft Windows security structures.
8"""
9
10import re
11import struct
12
13from scapy.config import conf
14from scapy.packet import Packet, bind_layers
15from scapy.fields import (
16 ByteEnumField,
17 ByteField,
18 ConditionalField,
19 FieldLenField,
20 FieldListField,
21 FlagsField,
22 FlagValue,
23 LEIntField,
24 LELongField,
25 LenField,
26 LEShortEnumField,
27 LEShortField,
28 MultipleTypeField,
29 PacketField,
30 PacketListField,
31 ShortField,
32 StrFieldUtf16,
33 StrFixedLenField,
34 StrLenField,
35 StrLenFieldUtf16,
36 UUIDField,
37)
38
39from scapy.layers.ntlm import (
40 _NTLM_ENUM,
41 _NTLM_post_build,
42 _NTLMPayloadField,
43 _NTLMPayloadPacket,
44)
45
46# [MS-DTYP] sect 2.4.1
47
48
49class WINNT_SID_IDENTIFIER_AUTHORITY(Packet):
50
51 fields_desc = [
52 StrFixedLenField("Value", b"\x00\x00\x00\x00\x00\x01", length=6),
53 ]
54
55 def default_payload_class(self, payload: bytes) -> Packet:
56 return conf.padding_layer
57
58
59# [MS-DTYP] sect 2.4.2
60
61
62class WINNT_SID(Packet):
63 fields_desc = [
64 ByteField("Revision", 1),
65 FieldLenField("SubAuthorityCount", None, count_of="SubAuthority", fmt="B"),
66 PacketField(
67 "IdentifierAuthority",
68 WINNT_SID_IDENTIFIER_AUTHORITY(),
69 WINNT_SID_IDENTIFIER_AUTHORITY,
70 ),
71 FieldListField(
72 "SubAuthority",
73 [0],
74 LEIntField("", 0),
75 count_from=lambda pkt: pkt.SubAuthorityCount,
76 ),
77 ]
78
79 def default_payload_class(self, payload: bytes) -> Packet:
80 return conf.padding_layer
81
82 _SID_REG = re.compile(r"^S-(\d)-(\d+)((?:-\d+)*)$")
83
84 @staticmethod
85 def fromstr(x: str):
86 """
87 Helper to create a SID from its string representation.
88
89 :param x: string representation of the SID like "S-1-5-18"
90 :type x: str
91
92 Example:
93
94 >>> from scapy.layers.windows.security import WINNT_SID
95 >>> WINNT_SID.fromstr("S-1-5-18")
96 <WINNT_SID Revision=1 IdentifierAuthority=<WINNT_SID_IDENTIFIER_AUTHORITY
97 Value=b'\x00\x00\x00\x00\x00\x05' |> SubAuthority=[18] |>
98 >>> _.summary()
99 >>> 'S-1-5-18'
100 """
101
102 m = WINNT_SID._SID_REG.match(x)
103 if not m:
104 raise ValueError("Invalid SID format !")
105 rev, authority, subauthority = m.groups()
106 return WINNT_SID(
107 Revision=int(rev),
108 IdentifierAuthority=WINNT_SID_IDENTIFIER_AUTHORITY(
109 Value=struct.pack(">Q", int(authority))[2:]
110 ),
111 SubAuthority=[int(x) for x in subauthority[1:].split("-")],
112 )
113
114 def summary(self) -> str:
115 """
116 Return the string representation of the SID.
117 """
118 return "S-%s-%s%s" % (
119 self.Revision,
120 struct.unpack(">Q", b"\x00\x00" + self.IdentifierAuthority.Value)[0],
121 (
122 ("-%s" % "-".join(str(x) for x in self.SubAuthority))
123 if self.SubAuthority
124 else ""
125 ),
126 )
127
128
129# https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers
130
131WELL_KNOWN_SIDS = {
132 # Universal well-known SID
133 "S-1-0-0": "Null SID",
134 "S-1-1-0": "Everyone",
135 "S-1-2-0": "Local",
136 "S-1-2-1": "Console Logon",
137 "S-1-3-0": "Creator Owner ID",
138 "S-1-3-1": "Creator Group ID",
139 "S-1-3-2": "Owner Server",
140 "S-1-3-3": "Group Server",
141 "S-1-3-4": "Owner Rights",
142 "S-1-4": "Non-unique Authority",
143 "S-1-5": "NT Authority",
144 "S-1-5-80-0": "All Services",
145 # NT well-known SIDs
146 "S-1-5-1": "Dialup",
147 "S-1-5-113": "Local account",
148 "S-1-5-114": "Local account and member of Administrators group",
149 "S-1-5-2": "Network",
150 "S-1-5-3": "Batch",
151 "S-1-5-4": "Interactive",
152 "S-1-5-6": "Service",
153 "S-1-5-7": "Anonymous Logon",
154 "S-1-5-8": "Proxy",
155 "S-1-5-9": "Enterprise Domain Controllers",
156 "S-1-5-10": "Self",
157 "S-1-5-11": "Authenticated Users",
158 "S-1-5-12": "Restricted Code",
159 "S-1-5-13": "Terminal Server User",
160 "S-1-5-14": "Remote Interactive Logon",
161 "S-1-5-15": "This Organization",
162 "S-1-5-17": "IUSR",
163 "S-1-5-18": "System (or LocalSystem)",
164 "S-1-5-19": "NT Authority (LocalService)",
165 "S-1-5-20": "Network Service",
166 "S-1-5-32-544": "Administrators",
167 "S-1-5-32-545": "Users",
168 "S-1-5-32-546": "Guests",
169 "S-1-5-32-547": "Power Users",
170 "S-1-5-32-548": "Account Operators",
171 "S-1-5-32-549": "Server Operators",
172 "S-1-5-32-550": "Print Operators",
173 "S-1-5-32-551": "Backup Operators",
174 "S-1-5-32-552": "Replicators",
175 "S-1-5-32-554": r"Builtin\Pre-Windows 2000 Compatible Access",
176 "S-1-5-32-555": r"Builtin\Remote Desktop Users",
177 "S-1-5-32-556": r"Builtin\Network Configuration Operators",
178 "S-1-5-32-557": r"Builtin\Incoming Forest Trust Builders",
179 "S-1-5-32-558": r"Builtin\Performance Monitor Users",
180 "S-1-5-32-559": r"Builtin\Performance Log Users",
181 "S-1-5-32-560": r"Builtin\Windows Authorization Access Group",
182 "S-1-5-32-561": r"Builtin\Terminal Server License Servers",
183 "S-1-5-32-562": r"Builtin\Distributed COM Users",
184 "S-1-5-32-568": r"Builtin\IIS_IUSRS",
185 "S-1-5-32-569": r"Builtin\Cryptographic Operators",
186 "S-1-5-32-573": r"Builtin\Event Log Readers",
187 "S-1-5-32-574": r"Builtin\Certificate Service DCOM Access",
188 "S-1-5-32-575": r"Builtin\RDS Remote Access Servers",
189 "S-1-5-32-576": r"Builtin\RDS Endpoint Servers",
190 "S-1-5-32-577": r"Builtin\RDS Management Servers",
191 "S-1-5-32-578": r"Builtin\Hyper-V Administrators",
192 "S-1-5-32-579": r"Builtin\Access Control Assistance Operators",
193 "S-1-5-32-580": r"Builtin\Remote Management Users",
194 "S-1-5-32-581": r"Builtin\Default Account",
195 "S-1-5-32-582": r"Builtin\Storage Replica Admins",
196 "S-1-5-32-583": r"Builtin\Device Owners",
197 "S-1-5-64-10": "NTLM Authentication",
198 "S-1-5-64-14": "SChannel Authentication",
199 "S-1-5-64-21": "Digest Authentication",
200 "S-1-5-80": "NT Service",
201 "S-1-5-80-0": "All Services",
202 "S-1-5-83-0": r"NT VIRTUAL MACHINE\Virtual Machines",
203}
204
205
206# [MS-DTYP] sect 2.4.3
207
208_WINNT_ACCESS_MASK = {
209 0x80000000: "GENERIC_READ",
210 0x40000000: "GENERIC_WRITE",
211 0x20000000: "GENERIC_EXECUTE",
212 0x10000000: "GENERIC_ALL",
213 0x02000000: "MAXIMUM_ALLOWED",
214 0x01000000: "ACCESS_SYSTEM_SECURITY",
215 0x00100000: "SYNCHRONIZE",
216 0x00080000: "WRITE_OWNER",
217 0x00040000: "WRITE_DACL",
218 0x00020000: "READ_CONTROL",
219 0x00010000: "DELETE",
220}
221
222
223# [MS-DTYP] sect 2.4.4.1
224
225
226WINNT_ACE_FLAGS = {
227 0x01: "OBJECT_INHERIT",
228 0x02: "CONTAINER_INHERIT",
229 0x04: "NO_PROPAGATE_INHERIT",
230 0x08: "INHERIT_ONLY",
231 0x10: "INHERITED_ACE",
232 0x40: "SUCCESSFUL_ACCESS",
233 0x80: "FAILED_ACCESS",
234}
235
236
237class WINNT_ACE_HEADER(Packet):
238 """
239 Access Control Entry (ACE) Header
240 It is composed of 3 fields, followed by ACE-specific data:
241
242 - AceType (1 byte): see below for standard values
243 - AceFlags (1 byte): see WINNT_ACE_FLAGS
244 - AceSize (2 bytes): total size of the ACE, including the header
245 and the ACE-specific data.
246 """
247
248 fields_desc = [
249 ByteEnumField(
250 "AceType",
251 0,
252 {
253 0x00: "ACCESS_ALLOWED",
254 0x01: "ACCESS_DENIED",
255 0x02: "SYSTEM_AUDIT",
256 0x03: "SYSTEM_ALARM",
257 0x04: "ACCESS_ALLOWED_COMPOUND",
258 0x05: "ACCESS_ALLOWED_OBJECT",
259 0x06: "ACCESS_DENIED_OBJECT",
260 0x07: "SYSTEM_AUDIT_OBJECT",
261 0x08: "SYSTEM_ALARM_OBJECT",
262 0x09: "ACCESS_ALLOWED_CALLBACK",
263 0x0A: "ACCESS_DENIED_CALLBACK",
264 0x0B: "ACCESS_ALLOWED_CALLBACK_OBJECT",
265 0x0C: "ACCESS_DENIED_CALLBACK_OBJECT",
266 0x0D: "SYSTEM_AUDIT_CALLBACK",
267 0x0E: "SYSTEM_ALARM_CALLBACK",
268 0x0F: "SYSTEM_AUDIT_CALLBACK_OBJECT",
269 0x10: "SYSTEM_ALARM_CALLBACK_OBJECT",
270 0x11: "SYSTEM_MANDATORY_LABEL",
271 0x12: "SYSTEM_RESOURCE_ATTRIBUTE",
272 0x13: "SYSTEM_SCOPED_POLICY_ID",
273 },
274 ),
275 FlagsField(
276 "AceFlags",
277 0,
278 8,
279 WINNT_ACE_FLAGS,
280 ),
281 LenField("AceSize", None, fmt="<H", adjust=lambda x: x + 4),
282 ]
283
284 def extract_padding(self, p):
285 return p[: self.AceSize - 4], p[self.AceSize - 4 :]
286
287 # fmt: off
288 def extractData(self, accessMask=None):
289 """
290 Return the ACE data as usable data.
291
292 :param accessMask: context-specific flags for the ACE Mask.
293 """
294 sid_string = self.payload.Sid.summary()
295 mask = self.payload.Mask
296 if accessMask is not None:
297 mask = FlagValue(mask, FlagsField("", 0, 32, accessMask).names)
298 ace_flag_string = str(
299 FlagValue(self.AceFlags, ["OI", "CI", "NP", "IO", "ID", "SA", "FA"])
300 )
301 object_guid = getattr(self.payload, "ObjectType", "")
302 inherit_object_guid = getattr(self.payload, "InheritedObjectType", "")
303 # ApplicationData -> conditional expression
304 cond_expr = None
305 if hasattr(self.payload, "ApplicationData"):
306 # Parse tokens
307 res = []
308 for ct in self.payload.ApplicationData.Tokens:
309 if ct.TokenType in [
310 # binary operators
311 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x88, 0x8e, 0x8f,
312 0xa0, 0xa1
313 ]:
314 t1 = res.pop(-1)
315 t0 = res.pop(-1)
316 tt = ct.sprintf("%TokenType%")
317 if ct.TokenType in [0xa0, 0xa1]: # && and ||
318 res.append(f"({t0}) {tt} ({t1})")
319 else:
320 res.append(f"{t0} {tt} {t1}")
321 elif ct.TokenType in [
322 # unary operators
323 0x87, 0x8d, 0xa2, 0x89, 0x8a, 0x8b, 0x8c, 0x91, 0x92, 0x93
324 ]:
325 t0 = res.pop(-1)
326 tt = ct.sprintf("%TokenType%")
327 res.append(f"{tt}{t0}")
328 elif ct.TokenType in [
329 # values
330 0x01, 0x02, 0x03, 0x04, 0x10, 0x18, 0x50, 0x51, 0xf8, 0xf9,
331 0xfa, 0xfb
332 ]:
333 def lit(ct):
334 if ct.TokenType in [0x10, 0x18]: # literal strings
335 return '"%s"' % ct.value
336 elif ct.TokenType == 0x50: # composite
337 return "({%s})" % ",".join(lit(x) for x in ct.value)
338 else:
339 return str(ct.value)
340 res.append(lit(ct))
341 elif ct.TokenType == 0x00: # padding
342 pass
343 else:
344 raise ValueError("Unhandled token type %s" % ct.TokenType)
345 if len(res) != 1:
346 raise ValueError("Incomplete SDDL !")
347 cond_expr = "(%s)" % res[0]
348 return {
349 "ace-flags-string": ace_flag_string,
350 "sid-string": sid_string,
351 "mask": mask,
352 "object-guid": object_guid,
353 "inherited-object-guid": inherit_object_guid,
354 "cond-expr": cond_expr,
355 }
356 # fmt: on
357
358 def toSDDL(self, accessMask=None):
359 """
360 Return SDDL
361 """
362 data = self.extractData(accessMask=accessMask)
363 ace_rights = "" # TODO
364 if self.AceType in [0x9, 0xA, 0xB, 0xD]: # Conditional ACE
365 conditional_ace_type = {
366 0x09: "XA",
367 0x0A: "XD",
368 0x0B: "XU",
369 0x0D: "ZA",
370 }[self.AceType]
371 return "D:(%s)" % (
372 ";".join(
373 x
374 for x in [
375 conditional_ace_type,
376 data["ace-flags-string"],
377 ace_rights,
378 str(data["object-guid"]),
379 str(data["inherited-object-guid"]),
380 data["sid-string"],
381 data["cond-expr"],
382 ]
383 if x is not None
384 )
385 )
386 else:
387 ace_type = {
388 0x00: "A",
389 0x01: "D",
390 0x02: "AU",
391 0x05: "OA",
392 0x06: "OD",
393 0x07: "OU",
394 0x11: "ML",
395 0x13: "SP",
396 }[self.AceType]
397 return "(%s)" % (
398 ";".join(
399 x
400 for x in [
401 ace_type,
402 data["ace-flags-string"],
403 ace_rights,
404 str(data["object-guid"]),
405 str(data["inherited-object-guid"]),
406 data["sid-string"],
407 data["cond-expr"],
408 ]
409 if x is not None
410 )
411 )
412
413
414# [MS-DTYP] sect 2.4.4.2
415
416
417class WINNT_ACCESS_ALLOWED_ACE(Packet):
418 fields_desc = [
419 FlagsField("Mask", 0, -32, _WINNT_ACCESS_MASK),
420 PacketField("Sid", WINNT_SID(), WINNT_SID),
421 ]
422
423
424bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_ACE, AceType=0x00)
425
426
427# [MS-DTYP] sect 2.4.4.3
428
429
430class WINNT_ACCESS_ALLOWED_OBJECT_ACE(Packet):
431 fields_desc = [
432 FlagsField("Mask", 0, -32, _WINNT_ACCESS_MASK),
433 FlagsField(
434 "Flags",
435 0,
436 -32,
437 {
438 0x00000001: "OBJECT_TYPE_PRESENT",
439 0x00000002: "INHERITED_OBJECT_TYPE_PRESENT",
440 },
441 ),
442 ConditionalField(
443 UUIDField("ObjectType", None, uuid_fmt=UUIDField.FORMAT_LE),
444 lambda pkt: pkt.Flags.OBJECT_TYPE_PRESENT,
445 ),
446 ConditionalField(
447 UUIDField("InheritedObjectType", None, uuid_fmt=UUIDField.FORMAT_LE),
448 lambda pkt: pkt.Flags.INHERITED_OBJECT_TYPE_PRESENT,
449 ),
450 PacketField("Sid", WINNT_SID(), WINNT_SID),
451 ]
452
453
454bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_OBJECT_ACE, AceType=0x05)
455
456
457# [MS-DTYP] sect 2.4.4.4
458
459
460class WINNT_ACCESS_DENIED_ACE(Packet):
461 fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc
462
463
464bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_ACE, AceType=0x01)
465
466
467# [MS-DTYP] sect 2.4.4.5
468
469
470class WINNT_ACCESS_DENIED_OBJECT_ACE(Packet):
471 fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc
472
473
474bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_OBJECT_ACE, AceType=0x06)
475
476
477# [MS-DTYP] sect 2.4.4.17.4+
478
479
480class WINNT_APPLICATION_DATA_LITERAL_TOKEN(Packet):
481 def default_payload_class(self, payload):
482 return conf.padding_layer
483
484
485# fmt: off
486WINNT_APPLICATION_DATA_LITERAL_TOKEN.fields_desc = [
487 ByteEnumField(
488 "TokenType",
489 0,
490 {
491 # [MS-DTYP] sect 2.4.4.17.5
492 0x00: "Padding token",
493 0x01: "Signed int8",
494 0x02: "Signed int16",
495 0x03: "Signed int32",
496 0x04: "Signed int64",
497 0x10: "Unicode",
498 0x18: "Octet String",
499 0x50: "Composite",
500 0x51: "SID",
501 # [MS-DTYP] sect 2.4.4.17.6
502 0x80: "==",
503 0x81: "!=",
504 0x82: "<",
505 0x83: "<=",
506 0x84: ">",
507 0x85: ">=",
508 0x86: "Contains",
509 0x88: "Any_of",
510 0x8e: "Not_Contains",
511 0x8f: "Not_Any_of",
512 0x89: "Member_of",
513 0x8a: "Device_Member_of",
514 0x8b: "Member_of_Any",
515 0x8c: "Device_Member_of_Any",
516 0x90: "Not_Member_of",
517 0x91: "Not_Device_Member_of",
518 0x92: "Not_Member_of_Any",
519 0x93: "Not_Device_Member_of_Any",
520 # [MS-DTYP] sect 2.4.4.17.7
521 0x87: "Exists",
522 0x8d: "Not_Exists",
523 0xa0: "&&",
524 0xa1: "||",
525 0xa2: "!",
526 # [MS-DTYP] sect 2.4.4.17.8
527 0xf8: "Local attribute",
528 0xf9: "User Attribute",
529 0xfa: "Resource Attribute",
530 0xfb: "Device Attribute",
531 }
532 ),
533 ConditionalField(
534 # Strings
535 LEIntField("length", 0),
536 lambda pkt: pkt.TokenType in [
537 0x10, # Unicode string
538 0x18, # Octet string
539 0xf8, 0xf9, 0xfa, 0xfb, # Attribute tokens
540 0x50, # Composite
541 ]
542 ),
543 ConditionalField(
544 MultipleTypeField(
545 [
546 (
547 LELongField("value", 0),
548 lambda pkt: pkt.TokenType in [
549 0x01, # signed int8
550 0x02, # signed int16
551 0x03, # signed int32
552 0x04, # signed int64
553 ]
554 ),
555 (
556 StrLenFieldUtf16("value", b"", length_from=lambda pkt: pkt.length),
557 lambda pkt: pkt.TokenType in [
558 0x10, # Unicode string
559 0xf8, 0xf9, 0xfa, 0xfb, # Attribute tokens
560 ]
561 ),
562 (
563 StrLenField("value", b"", length_from=lambda pkt: pkt.length),
564 lambda pkt: pkt.TokenType == 0x18, # Octet string
565 ),
566 (
567 PacketListField("value", [], WINNT_APPLICATION_DATA_LITERAL_TOKEN,
568 length_from=lambda pkt: pkt.length),
569 lambda pkt: pkt.TokenType == 0x50, # Composite
570 ),
571
572 ],
573 StrFixedLenField("value", b"", length=0),
574 ),
575 lambda pkt: pkt.TokenType in [
576 0x01, 0x02, 0x03, 0x04, 0x10, 0x18, 0xf8, 0xf9, 0xfa, 0xfb, 0x50
577 ]
578 ),
579 ConditionalField(
580 # Literal
581 ByteEnumField("sign", 0, {
582 0x01: "+",
583 0x02: "-",
584 0x03: "None",
585 }),
586 lambda pkt: pkt.TokenType in [
587 0x01, # signed int8
588 0x02, # signed int16
589 0x03, # signed int32
590 0x04, # signed int64
591 ]
592 ),
593 ConditionalField(
594 # Literal
595 ByteEnumField("base", 0, {
596 0x01: "Octal",
597 0x02: "Decimal",
598 0x03: "Hexadecimal",
599 }),
600 lambda pkt: pkt.TokenType in [
601 0x01, # signed int8
602 0x02, # signed int16
603 0x03, # signed int32
604 0x04, # signed int64
605 ]
606 ),
607]
608# fmt: on
609
610
611class WINNT_APPLICATION_DATA(Packet):
612 fields_desc = [
613 StrFixedLenField("Magic", b"\x61\x72\x74\x78", length=4),
614 PacketListField(
615 "Tokens",
616 [],
617 WINNT_APPLICATION_DATA_LITERAL_TOKEN,
618 ),
619 ]
620
621 def default_payload_class(self, payload):
622 return conf.padding_layer
623
624
625# [MS-DTYP] sect 2.4.4.6
626
627
628class WINNT_ACCESS_ALLOWED_CALLBACK_ACE(Packet):
629 fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + [
630 PacketField(
631 "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA
632 ),
633 ]
634
635
636bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_CALLBACK_ACE, AceType=0x09)
637
638
639# [MS-DTYP] sect 2.4.4.7
640
641
642class WINNT_ACCESS_DENIED_CALLBACK_ACE(Packet):
643 fields_desc = WINNT_ACCESS_ALLOWED_CALLBACK_ACE.fields_desc
644
645
646bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_CALLBACK_ACE, AceType=0x0A)
647
648
649# [MS-DTYP] sect 2.4.4.8
650
651
652class WINNT_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE(Packet):
653 fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc + [
654 PacketField(
655 "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA
656 ),
657 ]
658
659
660bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE, AceType=0x0B)
661
662
663# [MS-DTYP] sect 2.4.4.9
664
665
666class WINNT_ACCESS_DENIED_CALLBACK_OBJECT_ACE(Packet):
667 fields_desc = WINNT_ACCESS_DENIED_OBJECT_ACE.fields_desc + [
668 PacketField(
669 "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA
670 ),
671 ]
672
673
674bind_layers(WINNT_ACE_HEADER, WINNT_ACCESS_DENIED_CALLBACK_OBJECT_ACE, AceType=0x0C)
675
676
677# [MS-DTYP] sect 2.4.4.10
678
679
680class WINNT_SYSTEM_AUDIT_ACE(Packet):
681 fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc
682
683
684bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_ACE, AceType=0x02)
685
686
687# [MS-DTYP] sect 2.4.4.11
688
689
690class WINNT_SYSTEM_AUDIT_OBJECT_ACE(Packet):
691 # doc is wrong.
692 fields_desc = WINNT_ACCESS_ALLOWED_OBJECT_ACE.fields_desc
693
694
695bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_OBJECT_ACE, AceType=0x07)
696
697
698# [MS-DTYP] sect 2.4.4.12
699
700
701class WINNT_SYSTEM_AUDIT_CALLBACK_ACE(Packet):
702 fields_desc = WINNT_SYSTEM_AUDIT_ACE.fields_desc + [
703 PacketField(
704 "ApplicationData", WINNT_APPLICATION_DATA(), WINNT_APPLICATION_DATA
705 ),
706 ]
707
708
709bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_CALLBACK_ACE, AceType=0x0D)
710
711
712# [MS-DTYP] sect 2.4.4.13
713
714
715class WINNT_SYSTEM_MANDATORY_LABEL_ACE(Packet):
716 fields_desc = WINNT_SYSTEM_AUDIT_ACE.fields_desc
717
718
719bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_MANDATORY_LABEL_ACE, AceType=0x11)
720
721
722# [MS-DTYP] sect 2.4.4.14
723
724
725class WINNT_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE(Packet):
726 fields_desc = WINNT_SYSTEM_AUDIT_OBJECT_ACE.fields_desc
727
728
729bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE, AceType=0x0F)
730
731# [MS-DTYP] sect 2.4.10.1
732
733
734class CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1(_NTLMPayloadPacket):
735 _NTLM_PAYLOAD_FIELD_NAME = "Data"
736 fields_desc = [
737 LEIntField("NameOffset", 0),
738 LEShortEnumField(
739 "ValueType",
740 0,
741 {
742 0x0001: "CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64",
743 0x0002: "CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64",
744 0x0003: "CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING",
745 0x0005: "CLAIM_SECURITY_ATTRIBUTE_TYPE_SID",
746 0x0006: "CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN",
747 0x0010: "CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING",
748 },
749 ),
750 LEShortField("Reserved", 0),
751 FlagsField(
752 "Flags",
753 0,
754 -32,
755 {
756 0x0001: "CLAIM_SECURITY_ATTRIBUTE_NON_INHERITABLE",
757 0x0002: "CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE",
758 0x0004: "CLAIM_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY",
759 0x0008: "CLAIM_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT",
760 0x0010: "CLAIM_SECURITY_ATTRIBUTE_DISABLED",
761 0x0020: "CLAIM_SECURITY_ATTRIBUTE_MANDATORY",
762 },
763 ),
764 LEIntField("ValueCount", 0),
765 FieldListField(
766 "ValueOffsets", [], LEIntField("", 0), count_from=lambda pkt: pkt.ValueCount
767 ),
768 _NTLMPayloadField(
769 "Data",
770 lambda pkt: 16 + pkt.ValueCount * 4,
771 [
772 ConditionalField(
773 StrFieldUtf16("Name", b""),
774 lambda pkt: pkt.NameOffset,
775 ),
776 # TODO: Values
777 ],
778 offset_name="Offset",
779 ),
780 ]
781
782
783# [MS-DTYP] sect 2.4.4.15
784
785
786class WINNT_SYSTEM_RESOURCE_ATTRIBUTE_ACE(Packet):
787 fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc + [
788 PacketField(
789 "AttributeData",
790 CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1(),
791 CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
792 )
793 ]
794
795
796bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_RESOURCE_ATTRIBUTE_ACE, AceType=0x12)
797
798# [MS-DTYP] sect 2.4.4.16
799
800
801class WINNT_SYSTEM_SCOPED_POLICY_ID_ACE(Packet):
802 fields_desc = WINNT_ACCESS_ALLOWED_ACE.fields_desc
803
804
805bind_layers(WINNT_ACE_HEADER, WINNT_SYSTEM_SCOPED_POLICY_ID_ACE, AceType=0x13)
806
807# [MS-DTYP] sect 2.4.5
808
809
810class WINNT_ACL(Packet):
811 fields_desc = [
812 ByteField("AclRevision", 2),
813 ByteField("Sbz1", 0x00),
814 # Total size including header:
815 # AclRevision(1) + Sbz1(1) + AclSize(2) + AceCount(2) + Sbz2(2)
816 FieldLenField(
817 "AclSize",
818 None,
819 length_of="Aces",
820 adjust=lambda _, x: x + 8,
821 fmt="<H",
822 ),
823 FieldLenField("AceCount", None, count_of="Aces", fmt="<H"),
824 ShortField("Sbz2", 0),
825 PacketListField(
826 "Aces",
827 [],
828 WINNT_ACE_HEADER,
829 count_from=lambda pkt: pkt.AceCount,
830 ),
831 ]
832
833 def toSDDL(self):
834 return [x.toSDDL() for x in self.Aces]
835
836
837# [MS-DTYP] 2.4.6 SECURITY_DESCRIPTOR
838
839
840class SECURITY_DESCRIPTOR(_NTLMPayloadPacket):
841 OFFSET = 20
842 _NTLM_PAYLOAD_FIELD_NAME = "Data"
843 fields_desc = [
844 ByteField("Revision", 0x01),
845 ByteField("Sbz1", 0x00),
846 FlagsField(
847 "Control",
848 0x00,
849 -16,
850 [
851 "OWNER_DEFAULTED",
852 "GROUP_DEFAULTED",
853 "DACL_PRESENT",
854 "DACL_DEFAULTED",
855 "SACL_PRESENT",
856 "SACL_DEFAULTED",
857 "DACL_TRUSTED",
858 "SERVER_SECURITY",
859 "DACL_COMPUTED",
860 "SACL_COMPUTED",
861 "DACL_AUTO_INHERITED",
862 "SACL_AUTO_INHERITED",
863 "DACL_PROTECTED",
864 "SACL_PROTECTED",
865 "RM_CONTROL_VALID",
866 "SELF_RELATIVE",
867 ],
868 ),
869 LEIntField("OwnerSidOffset", None),
870 LEIntField("GroupSidOffset", None),
871 LEIntField("SACLOffset", None),
872 LEIntField("DACLOffset", None),
873 _NTLMPayloadField(
874 "Data",
875 OFFSET,
876 [
877 ConditionalField(
878 PacketField("OwnerSid", WINNT_SID(), WINNT_SID),
879 lambda pkt: pkt.OwnerSidOffset != 0,
880 ),
881 ConditionalField(
882 PacketField("GroupSid", WINNT_SID(), WINNT_SID),
883 lambda pkt: pkt.GroupSidOffset != 0,
884 ),
885 ConditionalField(
886 PacketField("SACL", WINNT_ACL(), WINNT_ACL),
887 lambda pkt: pkt.Control.SACL_PRESENT,
888 ),
889 ConditionalField(
890 PacketField("DACL", WINNT_ACL(), WINNT_ACL),
891 lambda pkt: pkt.Control.DACL_PRESENT,
892 ),
893 ],
894 offset_name="Offset",
895 ),
896 ]
897
898 def post_build(self, pkt, pay):
899 # type: (bytes, bytes) -> bytes
900 return (
901 _NTLM_post_build(
902 self,
903 pkt,
904 self.OFFSET,
905 {
906 "OwnerSid": 4,
907 "GroupSid": 8,
908 "SACL": 12,
909 "DACL": 16,
910 },
911 config=[
912 ("Offset", _NTLM_ENUM.OFFSET),
913 ],
914 )
915 + pay
916 )
917
918 def show_print(self):
919 """
920 Print the SECURITY_DESCRIPTOR in a human format
921 """
922 print("Owner:", self.OwnerSid.summary())
923 print("Group:", self.GroupSid.summary())
924 if getattr(self, "DACL", None):
925 print("DACL:")
926 for ace in self.DACL.Aces:
927 print(" - ", ace.toSDDL())
928 if getattr(self, "SACL", None):
929 print("SACL:")
930 for ace in self.SACL.Aces:
931 print(" - ", ace.toSDDL())