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_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"")