目录
LDAP 查找中的objectCategory和objectClass
查询Active Directory
通过查询目录,可以直接收集到要求的数据。查询目录需要指定两个要素
- BaseDN
- 过滤规则
BaseDN
BaseDN指定了这棵树的根。比如指定BaseDN为DC=xie,DC=com
就是以DC=xie.DC=com
为根往下搜索
BaseDN为CN=Users,DC=xie.DC=com
就是以CN=Users,DC=xie.DC=com
为根往下搜索
过滤规则
LDAP 过滤规则相对简单,很方便入手
LDAP 搜索过滤器语法有以下子集:
- 用与号 (&) 表示的 AND 运算符。
- 用竖线 (|) 表示的 OR 运算符。
- 用感叹号 (!) 表示的 NOT 运算符。
- 用名称和值表达式的等号 (=) 表示的相等比较。
- 用名称和值表达式中值的开头或结尾处的星号 (*) 表示的通配符。
下面举几个例子:
- (uid=testuser):匹配 uid 属性为testuser的所有对象
- (uid=test*):匹配 uid 属性以test开头的所有对象
- (!(uid=test*)):匹配 uid 属性不以test开头的所有对象
- (&(department=1234)(city=Paris)):匹配 department 属性为1234且city属性为Paris的所有对象
- (|(department=1234)(department=56*)):匹配 department 属性的值为1234或者以56开头的所有对象。
一个需要注意的点就是运算符是放在前面的,跟我们之前常规思维的放在中间不一样。
关于查询目录还有一些高级点的用法,比如 LDAP 控件,位掩码等。
LDAP高级搜索语法
LDAP 查找中的位操作
在LDAP 里面,有些字段是位字段,这里以userAccountControl举例,关于这个字段的详细意义,后面会详细介绍,这里先把他当做一个普通的位字段,不去考虑他的具体含义,这里先看下他的内容。
他的属性类位于架构分区的 CN=User-Account-Control,CN=Schema,CN=Configuration,DC=xie,DC=com
attributeSyntax
是2.5.5.9,
oMSyntax
是2
。
查表可知是32位的Integer类型。
之所以我们说他是位字段,是因为他是由一个个位构成。
比如说一个账户,他只有LOCKOUT和NOT_DELEGATED有值,其他位都没有。那这个用户的属性userAccountControl
的值就为0x0010+0x100000。是个32 位 int 类型。
现在如果我要搜索域内userAccountControl属性的值为NOT_DELEGATED的所有对象。那么用之前简单的LDAP语法就显得力不从心。简单的LDAP搜索语法只能对某个属性进行过滤,还不能对属性里面的某个具体位进行过滤。所以这也是我们这一节要讲的内容。LDAP的语法支持按位搜索。
执行过滤器以搜索位字段,必须遵循以下语法:
<属性名称>:<BitFilterRule-ID>:= <十进制比较值>
其中的<BitFilterRule-ID>
,内容如下。
我们最常的是LDAP_MATCHING_RULE_BIT_AND ,也就是1.2.840.113556.1.4.803
我们举几个例子。
我们想查询哪些对象设置了 TRUSTED_FOR_DELEGATION
TRUSTED_FOR_DELEGATION
对应的十进制比较值为524288
根据语法,我们就可以构造以下过滤规则
(userAccountControl:1.2.840.113556.1.4.803:=524288)
adfind的查询命令如下
adfind.exe -b dc=xie,dc=com -f "(userAccountControl:1.2.840.113556.1.4.803:=524288)" -bit -dn
但是使用这种语法我们还得去记BitFilterRule,于是adfind提供了一个更为快捷的方式。
adfind.exe -b dc=xie,dc=com -f "(userAccountControl:AND:=524288)" -bit -dn
LDAP 查找中的objectCategory和objectClass
(1) objectClass
在前面一节里面说过,在对象的objectClass
属性里面,可以看到这个对象是哪个类的实例,以及这个类的所有父类,比如说CN=test,CN=Users,DC=xie,DC=com
的objectClass
是top,person,organizationalPerson,user
。那我们通过过滤语句(objectClass=user)
,(objectClass=organizationalPerson)
都能找到这个对象。
所有的类都是top
类的子类。因此当我们过滤(objectClass=top)
可以找到域内的所有对象。
adfind.exe -b dc=xie,dc=com -s subtree -bit -f "(objectclass=*)" -c
adfind.exe -b dc=xie,dc=com -s subtree -bit -f "(objectclass=top)" -c
(2) objectCategory
在Windows Server 2008之前默认不对objectClass属性进行索引。最初认为对多值属性(如objectClass)进行索引会导致性能下降。如此一来,Windows 2000 附带了未索引的objectClass 属性和另一个已建立索引的单值属性,称为objectCategory。
接下来介绍下objectCategory
这个属性。对象类的每个实例还具有一个objectCategory属性,该属性是一个单值属性。并且建立了索引。其中包含对象是其实例的类或其父类之一的专有名称。
比如说CN=hack,CN=Users,DC=xie,DC=com
他的objectCategory
是 CN=Person,CN=Schema,CN=Configuration,DC=xie,DC=com
创建对象时,系统会将其objectCategory属性设置为由其对象类的defaultObjectCategory
属性指定的值,无法更改对象的objectCategory属性。
如果我们想过滤所有objectCategory的属性为CN=Person,CN=Schema,CN=Configuration,DC=xie,DC=com
的对象,这个很简单。
(objectCategory="CN=Person,CN=Schema,CN=Configuration,DC=test,DC=local")
adfind查询语法如下
adfind.exe -b dc=xie,dc=com -s subtree -bit -f "(objectCategory="CN=Person,CN=Schema,CN=Configuration,DC=xie,DC=com")" -dn
但是这样,又有点不方便,需要记住记住类的DN,所以LDAP在实现上实现了个小技巧。对象类有个属性lDAPDisplayName
,指定他的显示名。事实上,我们看objectClass
属性里面的类以及父类(比如top.person),他的名字都是这个类的lDAPDisplayName。
CN=Person,CN=Schema,CN=Configuration,DC=xie,DC=com
的lDAPDisplayName
是 person。
所以LDAP在实现上,支持用类的lDAPDisplayName
作为搜索条件。所以如果我们想找所有CN=Person,CN=Schema,CN=Configuration,DC=xie,DC=com
的实例,可以简化为以下过滤规则。
(objectCategory=person)
adfind搜索语法为
adfind.exe -b dc=xie,dc=com -s subtree -bit -f "(objectCategory=person)" -dn
(3) objectClass 与objectCategory的结合使用
如果想确保查询在所有版本的Active Directory上都能正常运行,建议使用 objectClass 和 objectCategory 结合。如果在目录中已经索引了ObjectClass ,或者所有域控制器都在运行Windows Server 2008或更高版本,则可以随意使用 objectClass,而不必担心会对性能产生影响。
这里我们介绍下objectClass 和 objectCategory 的结合使用。前面我们分别介绍了objectClass 以及objectCategory,但是没讲怎么把他们结合在一起使用。
我们这里再来理一理思路。
CN=hack,CN=Users,DC=xie,DC=com
这个对象。他的objectClass
是top,person,organizationalPerson,user
。他的objectCategory
是person
。
- 一个对象的
objectClass
是一个类的对象类,以及这个对象类的所有父类。 - 一个对象的
objectCategory
是一个类的对象类或者这个对象类的所有父类。
所以说一个对象的objectCategory
必定是objectClass
中的其中一个。
user,person,organizationalPerson类将其defaultObjectCategory设置为person。这允许像(objectCategory= person)这样的搜索过滤器通过单个查询定位所有这些类的实例。
比如说,我们要定位所有的user 类的实例。(CN=test,CN=Users,DC=xie,DC=com
就是user类的一个对象)
user 类的继承关系如下。
top => person => organizationalPerson => user
那person
,organizationalPerson
,user
都将其defaultObjectCategory设置为person。因此我们可以先过滤。
(objectCategory=person)
但是这样的结果并不精准。我们使用objectClass进一步在过滤后的结果进行过滤
(&(objectCategory=person)(objectClass=user))
这样就能精准匹配到了。其实说通俗点就是,objectCategory建立索引,所以查询时间比较快。我们通过objectCategory划分一个大的范围,然后通过objectClass进行精准匹配。
当然如果在目录中已经索引了ObjectClass ,或者所有域控制器都在运行Windows Server 2008或更高版本,我们直接使用 objectClass((objectClass=user)
) 也能很精准地匹配并且不用考虑效率问题。
参考文章:https://daiker.gitbook.io/windows-protocol/ldap-pian/8#0x06-sou-suo-active-directory