2

I try to read the nTSecurityDescriptor from a linux machine with ldapsearch (or something else) as normal domain user.

Searching for other things works, but I can not find the nTSecurityDescriptor.

This KB is probably related, but running as domain admin is not an option for a service.

So how can I read this info? I know that I can read the DACL, but the question is HOW.

Johannes Kuhn
  • 14,778
  • 4
  • 49
  • 73

3 Answers3

5

I created a new Java (JNDI) library (Apache2 license) for Windows ntSecurityDescriptor management. Start reading from http://blog.tirasa.net/ntsecuritydescripto-management.html for intro.

Take a look at the library (https://github.com/Tirasa/ADSDDL) integration tests for any help. Following an example to add 'user cannot change password' ACE into DACL.

final SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
controls.setReturningAttributes(new String[] { "nTSecurityDescriptor" });

ctx.setRequestControls(new Control[] { new SDFlagsControl(0x00000004) });

NamingEnumeration<SearchResult> results = 
    ctx.search(baseContext, searchFilter, controls);

SearchResult res = results.next();
final String dn = res.getNameInNamespace();

byte[] orig = (byte[]) res.getAttributes().get("nTSecurityDescriptor").get();

SDDL sddl = new SDDL(orig);
results.close();

final List<ACE> toBeChanged = new ArrayList<>();

for (ACE ace : sddl.getDacl().getAces()) {
    if ((ace.getType() == AceType.ACCESS_ALLOWED_OBJECT_ACE_TYPE
       || ace.getType() == AceType.ACCESS_DENIED_OBJECT_ACE_TYPE)
       && ace.getObjectFlags().getFlags().contains(
                 AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT)) {
        if (GUID.getGuidAsString(ace.getObjectType()).equals(
                     UCP_OBJECT_GUID)) {

            final SID sid = ace.getSid();
            if (sid.getSubAuthorities().size() == 1
                && ((Arrays.equals(sid.getIdentifierAuthority(), 
                   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })
                && Arrays.equals(sid.getSubAuthorities().get(0), 
                   new byte[] { 0x00, 0x00, 0x00, 0x00 }))
                || (Arrays.equals(sid.getIdentifierAuthority(), 
                   new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 })
                 && Arrays.equals(sid.getSubAuthorities().get(0), 
                   new byte[] { 0x00, 0x00, 0x00, 0x0a })))) {
                toBeChanged.add(ace);
            }
        }
    }
}

if (toBeChanged.isEmpty()) {
    // prepare aces
    ACE self = ACE.newInstance(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
    self.setObjectFlags(new AceObjectFlags(
                AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT));
    self.setObjectType(GUID.getGuidAsByteArray(UCP_OBJECT_GUID));
    self.setRights(new AceRights().addOjectRight(AceRights.ObjectRight.CR));
    SID sd = SID.newInstance(NumberFacility.getBytes(0x000000000001));
    sd.addSubAuthority(NumberFacility.getBytes(0));
    self.setSid(sd);

    ACE all = ACE.newInstance(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
    all.setObjectFlags(new AceObjectFlags(
                AceObjectFlags.Flag.ACE_OBJECT_TYPE_PRESENT));
    all.setObjectType(GUID.getGuidAsByteArray(UCP_OBJECT_GUID));
    all.setRights(new AceRights().addOjectRight(AceRights.ObjectRight.CR));
    sd = SID.newInstance(NumberFacility.getBytes(0x000000000005));
    sd.addSubAuthority(NumberFacility.getBytes(0x0A));
    all.setSid(sd);

    sddl.getDacl().getAces().add(self);
    sddl.getDacl().getAces().add(all);
} else {
    for (ACE ace : toBeChanged) {
        ace.setType(AceType.ACCESS_DENIED_OBJECT_ACE_TYPE);
    }
}

final Attribute ntSecurityDescriptor = new BasicAttribute(
      "ntSecurityDescriptor", sddl.toByteArray());

final ModificationItem[] mods = new ModificationItem[1];
mods[0] = new ModificationItem(
      DirContext.REPLACE_ATTRIBUTE, ntSecurityDescriptor);

ctx.modifyAttributes(dn, mods);
// .....
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Jave Jan 16 '15 at 09:57
  • 1
    I've just included the essential parts of the answer. – Fabio Martelli Jan 16 '15 at 12:13
3

To select the ntSecurityDescriptor as a non-privileged account you need to use the LDAP_SERVER_SD_FLAGS_OID server control with a value of 7. That indicates you want all portions of the security descriptor minus the SACL. The default value (which includes the SACL) seems to be what causes the attribute not to be returned, as most non-privileged accounts will not have access to the SACL, and because of this AD seems to just return nothing.

More details in this question/answer:

Selecting the AD ntSecurityDescriptor Attribute as a Non-Admin

Community
  • 1
  • 1
ChadSikorra
  • 2,829
  • 2
  • 21
  • 27
2

As it looks, it is not possible.

Unfortunately the underlying API that the Microsoft products use (COM API etc.) is not open source, so I don't even know how it can be done.

But I can get the security descriptor with the windows API call GetSecurityInfo on windows.

Johannes Kuhn
  • 14,778
  • 4
  • 49
  • 73
  • 1
    The format of the `ntSecurityDescriptor` is described in large detail as part of the MS-DTYP open specifications document under the Security Descriptor section 2.4, and its subsections. The challenge is translating that into code that can actually decode the structure, as it is not something Microsoft provides libraries for in the open source world. The library that Fabio Martelli created, and referenced in his answer, is a great reference for those attempting their own implementations. – ChadSikorra Nov 15 '16 at 16:03
  • The problem is how I get that binary chunk of data. What do I have to send to the LDAP server? – Johannes Kuhn Nov 16 '16 at 04:49
  • 1
    It seems like to retrieve the value as a non-administrator, you need to set the `LDAP_SERVER_SD_FLAGS_OID` server control. See this for some info on the control: https://msdn.microsoft.com/en-us/library/cc223323.aspx . It appears that control is assumed when running under an administrative user, but not under a normal account. However, I have not yet tested this. – ChadSikorra Nov 16 '16 at 15:08
  • @ChadSikorra Thanks, that was exactly what I was looking for. – Johannes Kuhn Nov 17 '16 at 03:48
  • 1
    In case you're interested, I have more details in [this answer](http://stackoverflow.com/a/40773088/2242593). It appears the reason that the `ntSecurityDescriptor` does not get returned for a normal user is that they do not have access to the SACL of a security descriptor. – ChadSikorra Nov 23 '16 at 19:58
  • @ChadSikorra Right, figured that much. And I'm not interested in the SACL, only in the DACL. Should have provided more information. If you answer this question, I'll accept it. – Johannes Kuhn Nov 23 '16 at 20:37