Files
hakril-PythonForWindows/tests/test_security.py
2024-06-05 22:45:46 +02:00

229 lines
8.5 KiB
Python

# -*- coding: utf-8 -*-
import windows.security
from windows.security import SecurityDescriptor
from .pfwtest import *
import ctypes
# CC -> Create-Child -> 1
# GR -> Generic read -> 0x80000000L
# AN -> Anonymous -> S-1-5-7
TEST_SDDL = [
"O:ANG:AND:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)(D;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)",
"O:ANG:AND:(A;;GR;;;S-1-0-0)",
"O:ANG:AND:(OA;;CC;;00000042-0043-0044-0045-000000000000;S-1-0-0)",
"O:ANG:AND:(OA;;CCGR;00004242-0043-0044-0045-000000000000;00000042-0043-0044-0045-000000000000;S-1-0-0)",
]
@pytest.mark.parametrize("sddl", TEST_SDDL)
def test_security_descriptor_from_string(sddl):
sd = SecurityDescriptor.from_string(sddl)
TEST_BIN_SDDL = [
# TapiSrv security descriptor
b'\x01\x00\x14\x80\x8c\x00\x00\x00\x98\x00\x00\x00\x14\x00\x00\x000\x00\x00\x00\x02\x00\x1c\x00\x01\x00\x00\x00\x02\x80\x14\x00\xff\x01\x0f\x00\x01\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x02\x00\\\x00\x04\x00\x00\x00\x00\x00\x14\x00\xfd\x01\x02\x00\x01\x01\x00\x00\x00\x00\x00\x05\x12\x00\x00\x00\x00\x00\x18\x00\xff\x01\x0f\x00\x01\x02\x00\x00\x00\x00\x00\x05 \x00\x00\x00 \x02\x00\x00\x00\x00\x14\x00\x9d\x01\x02\x00\x01\x01\x00\x00\x00\x00\x00\x05\x04\x00\x00\x00\x00\x00\x14\x00\x9d\x01\x02\x00\x01\x01\x00\x00\x00\x00\x00\x05\x06\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x05\x12\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x05\x12\x00\x00\x00',
]
@pytest.mark.parametrize("binsd", TEST_BIN_SDDL)
def test_security_descriptor_from_binary(binsd):
sd = SecurityDescriptor.from_binary(binsd)
def test_security_descriptor_from_unicode_file(tmpdir):
TARGET_FILENAME = u"내 한국은 최고의 한국.txt"
TARGET_PATH = os.path.join(str(tmpdir), TARGET_FILENAME)
with open(TARGET_PATH, "w") as f:
f.write("Hello Test")
assert SecurityDescriptor.from_filename(TARGET_PATH)
def test_empty_security_descriptor():
esd = SecurityDescriptor.from_string("")
assert esd.owner is None # Should NOT be NULL PSID but None
assert esd.group is None # Should NOT be NULL PSID but None
assert esd.dacl is None
assert esd.sacl is None
def test_security_descriptor__str__():
sddl = "D:(A;;FA;;;WD)"
sd = SecurityDescriptor.from_string(sddl)
assert str(sd) == sddl
def test_pacl_object():
SDDL = "O:ANG:S-1-2-3D:(A;;;;;S-1-42-42)(A;;;;;S-1-42-43)(A;;;;;S-1-42-44)"
dacl = SecurityDescriptor.from_string(SDDL).dacl
assert dacl is not None
assert len(dacl) == 3 # __len__
assert len(list(dacl)) == 3 # __iter__
assert len(dacl.aces) == 3
assert ctypes.addressof(dacl[0]) == ctypes.addressof(dacl[0]) # __getitem__
assert len([ctypes.addressof(dacl[i])for i in range(3)]) == 3
with pytest.raises(IndexError):
x = dacl[3]
def test_sec_descrip_owner_group():
SDDL = "O:ANG:S-1-2-3"
sd = SecurityDescriptor.from_string(SDDL)
assert sd.owner.to_string() == "S-1-5-7"
assert sd.group.to_string() == "S-1-2-3"
assert sd.dacl is None
assert sd.sacl is None
def test_mask_sid_ace():
SDDL = "D:(A;CIOI;CCGR;;;S-1-42-42)"
# OBJECT_INHERIT_ACE(0x1L) | CONTAINER_INHERIT_ACE(0x2L)
# Create-Child | GENERIC_READ(0x80000000L)
sd = SecurityDescriptor.from_string(SDDL)
dacl = sd.dacl
assert dacl is not None
ace = dacl[0]
# Test the ACE
assert ace.Header.AceType == gdef.ACCESS_ALLOWED_ACE_TYPE
# flags + flags split
assert ace.Header.AceFlags == gdef.OBJECT_INHERIT_ACE | gdef.CONTAINER_INHERIT_ACE
assert set(ace.Header.flags) == {gdef.OBJECT_INHERIT_ACE, gdef.CONTAINER_INHERIT_ACE}
# mask + mask split
assert ace.Mask == 1 | gdef.GENERIC_READ
assert set(ace.mask) == {1, gdef.GENERIC_READ}
# SID
assert ace.sid.to_string() == "S-1-42-42"
SGUID = gdef.GUID.from_string
COMPLEXE_SDDL_GUID = [
("D:(OA;;;00000042-0043-0044-0045-000000000001;;S-1-0-0)",
SGUID("00000042-0043-0044-0045-000000000001"),
None),
("D:(OA;;;;00000042-0043-0044-0045-000000000000;S-1-0-0)",
None,
SGUID("00000042-0043-0044-0045-000000000000")),
("D:(OA;;;00000042-0043-0044-0045-000000000002;00000042-0043-0044-0045-000000000003;S-1-0-0)",
SGUID("00000042-0043-0044-0045-000000000002"),
SGUID("00000042-0043-0044-0045-000000000003")),
("D:(OA;;;;;S-1-0-0)",
None,
None),
]
@pytest.mark.parametrize("sddl, obj_guid, inherited_object_guid", COMPLEXE_SDDL_GUID)
def test_complex_ace_guid_sid(sddl, obj_guid, inherited_object_guid):
sd = SecurityDescriptor.from_string(sddl)
assert sd.dacl is not None
ace = sd.dacl[0]
assert ace.sid.to_string() == "S-1-0-0"
if obj_guid is None and inherited_object_guid is None:
# No GUID -> transformed in ACCESS_ALLOWED_ACE_TYPE
assert ace.Header.AceType == gdef.ACCESS_ALLOWED_ACE_TYPE
return
assert ace.object_type == obj_guid
assert ace.inherited_object_type == inherited_object_guid
ALL_DACL_ACE_TYPES = [
("D:(A;;;;;S-1-2-3)", gdef.ACCESS_ALLOWED_ACE_TYPE),
("D:(D;;;;;S-1-2-3)", gdef.ACCESS_DENIED_ACE_TYPE),
("D:(OA;;;;00000042-0043-0044-0045-000000000000;S-1-0-0)",
gdef.ACCESS_ALLOWED_OBJECT_ACE_TYPE),
("D:(OD;;;;00000042-0043-0044-0045-000000000001;S-1-0-0)",
gdef.ACCESS_DENIED_OBJECT_ACE_TYPE),
("D:AI(XA;;GR;;;WD;(YOLO))", gdef.ACCESS_ALLOWED_CALLBACK_ACE_TYPE),
("D:AI(XD;;GR;;;WD;(YOLO))", gdef.ACCESS_DENIED_CALLBACK_ACE_TYPE),
("D:AI(ZA;;GR;;00000042-0043-0044-0045-000000000001;WD;(YOLO))", gdef.ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE),
# NO SDDL DEFINE FOR : gdef.ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE)
]
@pytest.mark.parametrize("sddl, ace_type", ALL_DACL_ACE_TYPES)
def test_ace_dacl_subclass(sddl, ace_type):
sd = SecurityDescriptor.from_string(sddl)
dacl = sd.dacl
assert len(dacl) == 1
ace = dacl[0] # Will raise if AceHeader is not handled
assert ace.Header.AceType == ace_type
# SACL STUFF
ALL_SACL_ACE_TYPES = [
("S:(AU;;;;;AN)", gdef.SYSTEM_AUDIT_ACE_TYPE),
("S:(ML;;;;;S-1-16-4000)", gdef.SYSTEM_MANDATORY_LABEL_ACE_TYPE),
# S-1-19-512-4096 what retrieved in a ACE from a directory in C:\Program Files\WindowsApps\
("S:(TL;;;;;S-1-19-512-4096)", gdef.SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE),
("S:(SP;;;;;S-1-17-1)", gdef.SYSTEM_SCOPED_POLICY_ID_ACE_TYPE),
("S:(OU;;;;00000042-0043-0044-0045-000000000000;AN)", gdef.SYSTEM_AUDIT_OBJECT_ACE_TYPE),
("S:(XU;;;;;S-1-2-3;(YOLO))", gdef.SYSTEM_AUDIT_CALLBACK_ACE_TYPE),
## Reserved for futur use (RFS): not handled by ADVAPI.dll
# ("S:(AL;;;;;S-1-2-3)", gdef.SYSTEM_ALARM_OBJECT_ACE_TYPE),
#("S:(OL;;;;00000042-0043-0044-0045-000000000000;AN)", gdef.SYSTEM_ALARM_OBJECT_ACE_TYPE),
## NO SDDL FOR:
# SYSTEM_ALARM_CALLBACK_ACE_TYPE
# SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE
# SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
]
@pytest.mark.parametrize("sddl, ace_type", ALL_SACL_ACE_TYPES)
def test_ace_sacl_subclass(sddl, ace_type):
sd = SecurityDescriptor.from_string(sddl)
sacl = sd.sacl
assert len(sacl) == 1
ace = sacl[0] # Will raise if AceHeader is not handled
assert ace.Header.AceType == ace_type
RESOURCE_ATTRIBUTES_SDDLS = [
("""S:(RA;;;;;WD; ("TestName",TI,0,-2, -1, 0, 1, 2))""",
(-2, -1, 0, 1, 2 )),
("""S:(RA;;;;;WD; ("TestName",TU,0,3,4,42))""",
(3, 4, 42)),
("""S:(RA;;;;;WD; ("TestName",TS,0,"Windows","SQL", ""))""",
("Windows", "SQL", "")),
("""S:(RA;;;;;WD; ("TestName",TD,0, AN, S-1-2-3-4-5-6-7-8-9))""",
(gdef.PSID.from_string("S-1-5-7"),
gdef.PSID.from_string("S-1-2-3-4-5-6-7-8-9"))),
("""S:(RA;;;;;WD; ("TestName",TX,0, 42000042, 0123456789abcdef))""",
(b"B\x00\x00B", b"\x01\x23\x45\x67\x89\xab\xcd\xef")),
("""S:(RA;;;;;WD; ("TestName",TB,0, 0, 1, 0, 0, 1))""",
(False, True, False, False, True)),
]
@pytest.mark.parametrize("sddl, expected_values", RESOURCE_ATTRIBUTES_SDDLS)
def test_ace_resource_attribute(sddl, expected_values):
sd = SecurityDescriptor.from_string(sddl)
ra = sd.sacl[0]
assert ra.Header.AceType == gdef.SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE
attr = ra.attribute
assert attr.name == "TestName"
assert attr.values == expected_values
CONDITIONAL_SDDLS = [
("D:AI(XA;;GR;;;WD;(ATTR1))", b"ATTR1"),
("D:AI(XD;;GR;;;WD;(ATTR2))", b"ATTR2"),
("S:AI(XU;;GR;;;WD;(ATTR3))", b"ATTR3")
]
@pytest.mark.parametrize("sddl, expected_value", CONDITIONAL_SDDLS)
def test_conditional_ace_applicationdata(sddl, expected_value):
sd = SecurityDescriptor.from_string(sddl)
acl = sd.dacl
if acl is None:
acl = sd.sacl
ace = acl[0]
appdata = ace.application_data
# https://msdn.microsoft.com/en-us/library/hh877860.aspx
assert appdata.startswith(b"artx")
assert expected_value in appdata.replace(b"\x00", b"")