Johannes Kuhn
Johannes Kuhn

Reputation: 15172

How can I access the nTSecurityDescriptor with a normal ldap client?

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.

Upvotes: 2

Views: 11363

Answers (3)

ChadSikorra
ChadSikorra

Reputation: 2869

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

Upvotes: 4

Fabio Martelli
Fabio Martelli

Reputation: 51

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);
// .....

Upvotes: 5

Johannes Kuhn
Johannes Kuhn

Reputation: 15172

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.

Upvotes: 2

Related Questions