选择AD ntSecurityDescriptor属性作为非管理员

时间:2016-11-23 18:10:27

标签: php active-directory ldap

我正在使用针对Active Directory ACL / ACE的SDDL /安全描述符解析器。我几乎完成了,当我使用管理帐户连接到LDAP时,一切正常。

但是,当我尝试将ntSecurityDescriptor作为非管理帐户进行查询时,它不返回任何值。用户帐户本身具有读取属性的权限。当我开始研究这个时,我遇到了以下LDAP服务器控件:

https://msdn.microsoft.com/en-us/library/cc223323.aspx

  

LDAP_SERVER_SD_FLAGS_OID控件与LDAP搜索一起使用   请求控制Windows安全描述符的部分   检索。 DC仅返回安全性的指定部分   描述。它还与LDAP添加和修​​改请求一起使用   控制要修改的Windows安全描述符部分。 DC   仅修改安全描述符的指定部分。

     

将此控件发送到DC时,controlValue字段设置为   以下ASN.1结构的BER编码。

 SDFlagsRequestValue ::= SEQUENCE {
     Flags    INTEGER
 }
     

Flags值具有以big-endian字节显示的以下格式   订购。 X表示客户端应该将未使用的位设置为0   必须被服务器忽略。

     

指定没有设置位或不使用LDAP_SERVER_SD_FLAGS_OID控件的标志等同于将标志设置为(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)。将此控件发送到DC不会导致服务器在其响应中包含任何控件。

文档中该语句的最后一部分似乎不正确,至少在非管理用户的上下文中是这样。

我的问题:我应该如何使用标准的PHP LDAP库函数将此控件发送到LDAP?我知道我必须设置服务器控件,但我不确定如何编码该值。我把它缩小到最简单的例子:

$user = 'user@example.local';
$pass = 'secret';
$server = 'dc1.example.local';

$ldap = ldap_connect($server);
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);

ldap_bind($ldap, $user, $pass);
$ctrl1 = array(
    "oid" => "1.2.840.113556.1.4.801",
    "iscritical" => true,
    // How should this value be set???
    "value" => sprintf("%c%c%c%c%c", 48, 3, 2, 1, 15)
);
if (!ldap_set_option($ldap, LDAP_OPT_SERVER_CONTROLS, array($ctrl1))) {
    echo "Failed to set server controls";
}

$searchUser = "user";
$dn = "dc=example,dc=local";
$filter="(sAMAccountName=$searchUser)";
$attr = array("ntsecuritydescriptor");

$sr = ldap_search($ldap, $dn, $filter, $attr);
$info = ldap_get_entries($ldap, $sr);

// Should contain ntSecurityDescriptor...but it does not.
var_dump($info);

我知道控件的值需要进行BER编码,但我不确定如何为文档中定义的值实现该值。我能够找到以下Java示例:

https://github.com/Tirasa/ADSDDL/blob/master/src/main/java/net/tirasa/adsddl/ntsd/controls/SDFlagsControl.java

但是我无法将那里发生的事情翻译成PHP。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

问题似乎是非特权AD用户帐户无权访问安全描述符的SACL。要解决此问题并仍然检索ntSecurityDescriptor(减去SACL),请使用设置的所有其他标志的值发送控件(值为7):

// OWNER_SECURITY_INFORMATION + GROUP_SECURITY_INFORMATION + DACL_SECURITY_INFORMATION
$sdFlags = 7;

$ctrl1 = array(
    "oid" => "1.2.840.113556.1.4.801",
    "iscritical" => true,
    "value" => sprintf("%c%c%c%c%c", 48, 3, 2, 1, $sdFlags)
);
if (!ldap_set_option($ldap, LDAP_OPT_SERVER_CONTROLS, array($ctrl1))) {
    echo "Failed to set server controls";
}

我的猜测是MS文档没有错,LDAP_SERVER_SD_FLAGS_OID的默认值是所有标志设置(包括SACL)。由于大多数普通帐户无权访问该SACL,因此AD可能决定不返回安全描述符的任何部分,因此即使您选择了查询,也不会从查询中返回ntSecurityDescriptor值。

另一个重要的注意事项,如果您使用LDAP分页,它似乎会干扰此控件。您不能同时使用分页和此控件。我不确定这是否是此控件的副作用,或者是如何在PHP的LDAP模块中完成服务器控件的问题。