前言

LDAP是一种目录访问协议,它规定了以树状结构的方式来存储和访问数据。

然而协议是抽象的,要产生具体的功效,必须在应用中实现,比如AD域服务就实现了LDAP协议。

LDAP最明显的优势就是读取速度快,拥有极高的搜索效率。

可以用一个例子来体会这种速度:当我们进入一个迷宫,需要寻找出口。

普通数据库:一条路一条路地尝试,直到尝试出能走出去的路线,再将这条路线返回给我们。

LDAP:相当于拿了一张解密地图,上面清清楚楚写着哪条路能直接到达出口。

很明显,普通数据库也许要尝试十多次才能找到正确的路线,但是LDAP只要一次就能找到,搜索性能上孰优孰劣一目了然。

除此之外,LDAP允许灵活地添加数据,并且采取【客户端-服务端】的方式提供服务,即在服务端存储数据,在客户端操作数据,但相比于关系型数据库,它不支持事务、回滚等操作。

LDAP之所以拥有这些特点,主要基于它的数据存储方式——树形目录,即在系统中构建一棵树,在树叶上存储数据。接下来我们通过在系统中搭建一棵树的流程,详细介绍LDAP原理。

# LDAP原理 #

构建一棵树,首先我们需要确定这棵树长在哪里,也就是树根是什么。

LDAP中将域名拆分开,形成树根,系统中的树根叫做DC,比如在test20.local域下,树根为DC=test20,DC=local。

1633921602_6163aa429feac0cdb4d39.png!small?1633921574750

相比于直接用test20.local做树根,这样的组织方式让整体结构更清晰,同时便于扩充域。假如有另一个叫test20.local2的域要加入这棵树,那么我们就可以直接将DC=local2放到DC=test20下面,而不必重新构建一棵叫test20.local2的树,如下图所示。

1633921608_6163aa48ef59eb7685b7e.png!small?1633921581144

树根有了,下一步,我们开始构建树枝。

LDAP中,树的枝干通常是由组织单位(OU)来充当,主要是区分数据所属范围。比如有一个叫张三的用户在local下的信息部,那么张三所属枝干就是OU=信息部。

1633921654_6163aa769d174e480e817.png!small?1633921626715

在这里,LDAP有一个明显优势,就是每一个树枝都可以被单独放在一个服务器中进行管理。这不仅有利于减轻服务器负担,也方便具有分公司的企业在不同地域部署服务器。

到最后,只要把所有的数据制作成树叶,挂到树枝上去就行了。

制作树叶有两个关键的地方,一个是树叶名字,另一个是树叶内容。

LDAP规定的名字结构由两部分组成,一部分是直接名称,即CN,一部分是相对名称,即RDN。

CN是唯一的,用来区分不同树叶。比如用户张三注册时,CN=张三。

而RDN是指从树根到树叶经过的所有枝干,用来标识树叶位置。如果Sam用户在市场运营部,他的RDN就是DC=test20,DC=local,OU=信息部。

RDN加CN就形成了数据名称,用DN来表示,张三的DN就是:DC=test20,DC=local,OU=信息部,CN=张三。

正是这样的名字结构提升了LDAP的读取效率,因为DN就是那张标识了出口路线的地图,只要我们顺着名称往下寻找,就能直接找到所需数据。

1633921670_6163aa86cfac67d3beda6.png!small?1633921642895

树叶内容主要是描述这片树叶的颜色、形状、气味等独特的信息,对应到系统中,就是资源的属性,比如用户的属性有性别,身份证号,电话等,计算机的属性有操作系统类型、账号密码等。

1633921680_6163aa90b01280ca01fbe.png!small?1633921652869

一片树叶名称加上它的属性就形成完整的数据信息,在系统中被称为条目。

每片树叶有它单独的条目,如果要增加新的信息,只需要在条目中添加一个属性,不会影响其它的条目。而在关系型数据库中,增加信息需要改变表结构,相比来说,困难很多。

为了提高效率,LDAP还提供了一种比较方便的做法,就是给具有相同属性类型的资源制定模板,在注册时直接往模板中填充信息就能创建一片树叶,这就是对象类。

比如说系统中有一个对象类叫用户,它的属性包括姓名、电话、邮箱。那么我创建用户时,必须填写这三项才能创建成功。

1633921726_6163aabe964df8087df90.png!small?1633921698717

系统中的树还有一个不一样的地方,就是各种不同品种的树叶可以长在一棵树上,这个不同品种的树叶是由系统中多种多样的资源对象来充当的,所以我们可以想象一棵长满了用户、计算机和打印机的树。

除此之外,它还可以允许杂交树叶的存在。这是因为系统中的某个资源对象可能同时具有多个对象类的属性,比如系统管理员,它就同时具有用户和管理员的属性。

到此,在LDAP协议的“指导”下,我们就成功在系统中构建好一棵完整的树了。

# 结语 #

LDAP常用来构建统一的账号管理、身份验证平台,实现sso单点登录机制。此外,它还有访问控制和数据复制的功能,能够帮助增强系统安全性和容灾性。

但同时,LDAP协议也存在一些安全问题,比如LDAP注入造成的恶意LDAP查询。在工作生产中,同样需要我们多加防范。

以上就是LDAP协议的全部内容,下一篇文章中,我们将继续为大家介绍RPC协议。

前言

LDAP是一种目录访问协议,它规定了以树状结构的方式来存储和访问数据。

然而协议是抽象的,要产生具体的功效,必须在应用中实现,比如AD域服务就实现了LDAP协议。

LDAP最明显的优势就是读取速度快,拥有极高的搜索效率。

可以用一个例子来体会这种速度:当我们进入一个迷宫,需要寻找出口。

普通数据库:一条路一条路地尝试,直到尝试出能走出去的路线,再将这条路线返回给我们。

LDAP:相当于拿了一张解密地图,上面清清楚楚写着哪条路能直接到达出口。

很明显,普通数据库也许要尝试十多次才能找到正确的路线,但是LDAP只要一次就能找到,搜索性能上孰优孰劣一目了然。

除此之外,LDAP允许灵活地添加数据,并且采取【客户端-服务端】的方式提供服务,即在服务端存储数据,在客户端操作数据,但相比于关系型数据库,它不支持事务、回滚等操作。

LDAP之所以拥有这些特点,主要基于它的数据存储方式——树形目录,即在系统中构建一棵树,在树叶上存储数据。接下来我们通过在系统中搭建一棵树的流程,详细介绍LDAP原理。

# LDAP原理 #

构建一棵树,首先我们需要确定这棵树长在哪里,也就是树根是什么。

LDAP中将域名拆分开,形成树根,系统中的树根叫做DC,比如在test20.local域下,树根为DC=test20,DC=local。

1633921602_6163aa429feac0cdb4d39.png!small?1633921574750

相比于直接用test20.local做树根,这样的组织方式让整体结构更清晰,同时便于扩充域。假如有另一个叫test20.local2的域要加入这棵树,那么我们就可以直接将DC=local2放到DC=test20下面,而不必重新构建一棵叫test20.local2的树,如下图所示。

1633921608_6163aa48ef59eb7685b7e.png!small?1633921581144

树根有了,下一步,我们开始构建树枝。

LDAP中,树的枝干通常是由组织单位(OU)来充当,主要是区分数据所属范围。比如有一个叫张三的用户在local下的信息部,那么张三所属枝干就是OU=信息部。

1633921654_6163aa769d174e480e817.png!small?1633921626715

在这里,LDAP有一个明显优势,就是每一个树枝都可以被单独放在一个服务器中进行管理。这不仅有利于减轻服务器负担,也方便具有分公司的企业在不同地域部署服务器。

到最后,只要把所有的数据制作成树叶,挂到树枝上去就行了。

制作树叶有两个关键的地方,一个是树叶名字,另一个是树叶内容。

LDAP规定的名字结构由两部分组成,一部分是直接名称,即CN,一部分是相对名称,即RDN。

CN是唯一的,用来区分不同树叶。比如用户张三注册时,CN=张三。

而RDN是指从树根到树叶经过的所有枝干,用来标识树叶位置。如果Sam用户在市场运营部,他的RDN就是DC=test20,DC=local,OU=信息部。

RDN加CN就形成了数据名称,用DN来表示,张三的DN就是:DC=test20,DC=local,OU=信息部,CN=张三。

正是这样的名字结构提升了LDAP的读取效率,因为DN就是那张标识了出口路线的地图,只要我们顺着名称往下寻找,就能直接找到所需数据。

1633921670_6163aa86cfac67d3beda6.png!small?1633921642895

树叶内容主要是描述这片树叶的颜色、形状、气味等独特的信息,对应到系统中,就是资源的属性,比如用户的属性有性别,身份证号,电话等,计算机的属性有操作系统类型、账号密码等。

1633921680_6163aa90b01280ca01fbe.png!small?1633921652869

一片树叶名称加上它的属性就形成完整的数据信息,在系统中被称为条目。

每片树叶有它单独的条目,如果要增加新的信息,只需要在条目中添加一个属性,不会影响其它的条目。而在关系型数据库中,增加信息需要改变表结构,相比来说,困难很多。

为了提高效率,LDAP还提供了一种比较方便的做法,就是给具有相同属性类型的资源制定模板,在注册时直接往模板中填充信息就能创建一片树叶,这就是对象类。

比如说系统中有一个对象类叫用户,它的属性包括姓名、电话、邮箱。那么我创建用户时,必须填写这三项才能创建成功。

1633921726_6163aabe964df8087df90.png!small?1633921698717

系统中的树还有一个不一样的地方,就是各种不同品种的树叶可以长在一棵树上,这个不同品种的树叶是由系统中多种多样的资源对象来充当的,所以我们可以想象一棵长满了用户、计算机和打印机的树。

除此之外,它还可以允许杂交树叶的存在。这是因为系统中的某个资源对象可能同时具有多个对象类的属性,比如系统管理员,它就同时具有用户和管理员的属性。

到此,在LDAP协议的“指导”下,我们就成功在系统中构建好一棵完整的树了。

# 结语 #

LDAP常用来构建统一的账号管理、身份验证平台,实现sso单点登录机制。此外,它还有访问控制和数据复制的功能,能够帮助增强系统安全性和容灾性。

但同时,LDAP协议也存在一些安全问题,比如LDAP注入造成的恶意LDAP查询。在工作生产中,同样需要我们多加防范。

以上就是LDAP协议的全部内容,下一篇文章中,我们将继续为大家介绍RPC协议。

在网络空间中,用户进行通信时,要将自己的信息转换成数据,在网络上传输给对方。最初是不加密直接传输的,但是对话信息容易被他人查看,所以就出现了加密模式。这种方式,一定程度上保护了通信安全,但一些“聪明”的黑客,仍能通过第三方攻击的手段偷换密码,以达到窃取信息的目的。

1632363039_614be21f3720c740f8ce6.png!small?1632363011643

在企业中,大多信息都能产生价值。黑客为了获得利益,不惜耗费巨大的精力研究密码,窃取信息。企业急需一种能够在更高程度上保护信息安全的通信方式。

Kerberos,作为一种网络认证协议,凭借其更高的便利性和安全性,成为了各大企业规范内网通信的首选方案。

本篇文章,我们将为大家详细介绍Kerberos协议的原理。

#Kerberos概述#

Kerberos作为第三方认证机构,在客户端需要与服务端通信时,通过对通信双方的认证,来保证通信安全。

如果用“一手交钱一手交货“来比喻通信过程。我们可以这样理解:客户端把自己的钱(我是谁)交给另一方,另一方验证真假后,把货物交给客户端(返回数据)。

但是在网络世界中,交易双方无法面对面交易,交易的“物品”也不是实物,如何确认交易对象的身份,保证信息没有被篡改,是件困难的事。

Kerberos要做的就是解决这个问题:在发生交易前,确认交易双方可信,并且制定交易规则。

1632363061_614be235a3b47d68db8b3.png!small?1632363034410

确认身份过程,由交易双方提供证件,即ID等信息,Kerberos根据数据库记录,检查信息是否与记录一致,以防止他人伪冒客户端申请服务,或假冒服务端发送虚假信息。

交易规则主要包括交易期限、交易时间、交易密码等,由Kerberos制定,并发送给通信双方知晓。

其中,最重要的是交易密码,也就是我们常说的通信密钥,用来加密通信双方的数据,可以理解为货物上的“锁”。通信密钥与私钥不同,通信密钥加密的信息可以由通信双方查看,而私玥加密的信息只能由该密钥拥有者查看。

保证通信密钥能准确无误地分发给客户端和服务端,并且不被其他人盗取,是Kerberos中至关重要的一步。

1632363076_614be244bc6f64e32a2d9.png!small?1632363049165

用户在Kerberos环境下请求服务,共有三次通信,每次通信分别进行“用户身份验证“、“授权用户访问服务“和“请求响应服务”。

前两次通信主要通过KDC(密钥分发中心)来实现。KDC通常安装在域控上,由AS和TGS两部分组成。AS负责“用户身份验证”,TGS负责“授权用户访问服务”。

1632363087_614be24ff34a1658227ec.png!small?1632363060385

它们间的关系就像个连环扣,每一步都依赖于上一步的成功完成。第一步确定第二步的通信规则,第二步确定第三步的通信规则。接下来我们详细说说这个环环相扣的过程。

【验证用户身份】

通信安全,首先要保证通信双方都是可信的,所以进行身份验证是必不可少的环节。

交钱:客户端将自己的身份信息装进Authenticator(用户私钥加密)发给AS,同时附上请求信息。

交货:AS生成TGS Session Key(客户端私钥加密),用于客户端与TGS通信时加密数据。AS将第二阶段的通信内容装进TGT(TGS私钥加密),将它和TGS Session Key(客户端私钥加密)一起返回给客户端。

1632363113_614be269b6ff8967603e7.png!small?1632363085771

交易规则:

AS接收到客户端信息后,并不是立即接受交易,而是先在AD数据库中查找是否有该用户记录。如果存在,则用该用户的密码HASH解密Authenticator,解密成功则允许交易。

也就是说AS只接受特定用户的交易,如果请求用户不在它的信任名单内,就会拒绝交易。这也是Kerberos维护域内安全的一种方式。

1632363126_614be27681dd2803fbefa.png!small?1632363098518

客户端收到“货物“后,发现两件货物都被”上了锁“,TGS Session Key上的”锁“可以用客户端的密钥解开。但是TGT上的锁只能由TGS解开,客户端无法打开也看不到里面的内容,只能直接转交给TGS。

1632363133_614be27d68cd14190ee6f.png!small?1632363105446

 

【授权客户端访问服务】

在拿到TGT后,客户端就可以用它跟TGS做交易了。

交钱:客户端同样将包含自身信息的Authenticator(TGS Session Key加密)发给TGS,同时附上TGT。

交货:TGS生成Service Session Key,用于客户端与服务端通信时加密数据。再将第三阶段的通信内容封装进Ticket for Service(Service Secret Key加密),将它和Service Session Key(TGS Session Key加密)一起发送给客户端。

1632363154_614be2927bd58180c47a2.png!small?1632363126129

交易规则

TGS收到货物后,发现这两件货物中,只有TGT上的锁可以解开。但是解开后,在里面找到了一把钥匙——TGS Session Key,这把钥匙正好可以解开 Authenticator的锁,于是它就得到了全部货物中的信息。

进行身份验证时,通过对比TGT和Authenticator中用户信息就能判断“发件人”是否可信。

TGS在对比完用户信息后,还会检查货物中的其它信息来保证安全性,比如检查时间戳判断这批货物是否过期,检查TGS缓存查看是否客户端已经申请过该服务……

1632363166_614be29e4ec2559e0c72c.png!small?1632363138007

同样,客户端收到TGS发来的货物后,能够用TGS Session Key解开Service Session Key,但无法打开Ticket for Service上的锁,于是把Ticket for Service转发给服务端。

【请求响应服务】

交钱:客户端将Authenticator(Service Session Key加密)发送给服务端,同时附上Ticket For Service。

交货:用Service Session Key加密数据,开始通信。

1632363190_614be2b6479d86c12ea15.png!small?1632363161902

同TGS一样,服务端收到Authenticator和Ticket后,用私钥解密Ticket,获得TGS封装给它的信息。再用其中的Service Session Key解密Authentictor,获得客户端封装给它的信息。

通过对比客户端信息判断用户身份是否可信,再检查时间戳、生命周期等保证会话安全性。

之后,客户端和服务端就能愉快地进行通信啦!

1632363202_614be2c253ba45c461c2f.png!small?1632363175244

由此可见,为了把通信密钥安全地送到客户端和服务端手里,Kerberos废了多大的力,下面这张图总结了kerberos协议在整个交易过程中所用到的密钥。

1632363209_614be2c98c46f0203d5de.png!small?1632363181253

#结语#

尽管Kerberos的认证模式已经能满足大多数企业的安全需求了,但这样就足够了吗?不是的,其中还存在很多威胁。AD域的攻击行为,很多都与Kerberos相关,比如哈希传递、黄金票据、Kerberoast攻击等。了解Kerberos协议的作用原理后,我们就可以针对各个阶段特有的威胁采取针对性的防护措施,帮助我们选择智能运营方案。

以上就是我们给大家介绍的Kerberos协议的全部内容,下一篇文章中,我们将继续为大家介绍ntlm协议。

在网络空间中,用户进行通信时,要将自己的信息转换成数据,在网络上传输给对方。最初是不加密直接传输的,但是对话信息容易被他人查看,所以就出现了加密模式。这种方式,一定程度上保护了通信安全,但一些“聪明”的黑客,仍能通过第三方攻击的手段偷换密码,以达到窃取信息的目的。

1632363039_614be21f3720c740f8ce6.png!small?1632363011643

在企业中,大多信息都能产生价值。黑客为了获得利益,不惜耗费巨大的精力研究密码,窃取信息。企业急需一种能够在更高程度上保护信息安全的通信方式。

Kerberos,作为一种网络认证协议,凭借其更高的便利性和安全性,成为了各大企业规范内网通信的首选方案。

本篇文章,我们将为大家详细介绍Kerberos协议的原理。

#Kerberos概述#

Kerberos作为第三方认证机构,在客户端需要与服务端通信时,通过对通信双方的认证,来保证通信安全。

如果用“一手交钱一手交货“来比喻通信过程。我们可以这样理解:客户端把自己的钱(我是谁)交给另一方,另一方验证真假后,把货物交给客户端(返回数据)。

但是在网络世界中,交易双方无法面对面交易,交易的“物品”也不是实物,如何确认交易对象的身份,保证信息没有被篡改,是件困难的事。

Kerberos要做的就是解决这个问题:在发生交易前,确认交易双方可信,并且制定交易规则。

1632363061_614be235a3b47d68db8b3.png!small?1632363034410

确认身份过程,由交易双方提供证件,即ID等信息,Kerberos根据数据库记录,检查信息是否与记录一致,以防止他人伪冒客户端申请服务,或假冒服务端发送虚假信息。

交易规则主要包括交易期限、交易时间、交易密码等,由Kerberos制定,并发送给通信双方知晓。

其中,最重要的是交易密码,也就是我们常说的通信密钥,用来加密通信双方的数据,可以理解为货物上的“锁”。通信密钥与私钥不同,通信密钥加密的信息可以由通信双方查看,而私玥加密的信息只能由该密钥拥有者查看。

保证通信密钥能准确无误地分发给客户端和服务端,并且不被其他人盗取,是Kerberos中至关重要的一步。

1632363076_614be244bc6f64e32a2d9.png!small?1632363049165

用户在Kerberos环境下请求服务,共有三次通信,每次通信分别进行“用户身份验证“、“授权用户访问服务“和“请求响应服务”。

前两次通信主要通过KDC(密钥分发中心)来实现。KDC通常安装在域控上,由AS和TGS两部分组成。AS负责“用户身份验证”,TGS负责“授权用户访问服务”。

1632363087_614be24ff34a1658227ec.png!small?1632363060385

它们间的关系就像个连环扣,每一步都依赖于上一步的成功完成。第一步确定第二步的通信规则,第二步确定第三步的通信规则。接下来我们详细说说这个环环相扣的过程。

【验证用户身份】

通信安全,首先要保证通信双方都是可信的,所以进行身份验证是必不可少的环节。

交钱:客户端将自己的身份信息装进Authenticator(用户私钥加密)发给AS,同时附上请求信息。

交货:AS生成TGS Session Key(客户端私钥加密),用于客户端与TGS通信时加密数据。AS将第二阶段的通信内容装进TGT(TGS私钥加密),将它和TGS Session Key(客户端私钥加密)一起返回给客户端。

1632363113_614be269b6ff8967603e7.png!small?1632363085771

交易规则:

AS接收到客户端信息后,并不是立即接受交易,而是先在AD数据库中查找是否有该用户记录。如果存在,则用该用户的密码HASH解密Authenticator,解密成功则允许交易。

也就是说AS只接受特定用户的交易,如果请求用户不在它的信任名单内,就会拒绝交易。这也是Kerberos维护域内安全的一种方式。

1632363126_614be27681dd2803fbefa.png!small?1632363098518

客户端收到“货物“后,发现两件货物都被”上了锁“,TGS Session Key上的”锁“可以用客户端的密钥解开。但是TGT上的锁只能由TGS解开,客户端无法打开也看不到里面的内容,只能直接转交给TGS。

1632363133_614be27d68cd14190ee6f.png!small?1632363105446

 

【授权客户端访问服务】

在拿到TGT后,客户端就可以用它跟TGS做交易了。

交钱:客户端同样将包含自身信息的Authenticator(TGS Session Key加密)发给TGS,同时附上TGT。

交货:TGS生成Service Session Key,用于客户端与服务端通信时加密数据。再将第三阶段的通信内容封装进Ticket for Service(Service Secret Key加密),将它和Service Session Key(TGS Session Key加密)一起发送给客户端。

1632363154_614be2927bd58180c47a2.png!small?1632363126129

交易规则

TGS收到货物后,发现这两件货物中,只有TGT上的锁可以解开。但是解开后,在里面找到了一把钥匙——TGS Session Key,这把钥匙正好可以解开 Authenticator的锁,于是它就得到了全部货物中的信息。

进行身份验证时,通过对比TGT和Authenticator中用户信息就能判断“发件人”是否可信。

TGS在对比完用户信息后,还会检查货物中的其它信息来保证安全性,比如检查时间戳判断这批货物是否过期,检查TGS缓存查看是否客户端已经申请过该服务……

1632363166_614be29e4ec2559e0c72c.png!small?1632363138007

同样,客户端收到TGS发来的货物后,能够用TGS Session Key解开Service Session Key,但无法打开Ticket for Service上的锁,于是把Ticket for Service转发给服务端。

【请求响应服务】

交钱:客户端将Authenticator(Service Session Key加密)发送给服务端,同时附上Ticket For Service。

交货:用Service Session Key加密数据,开始通信。

1632363190_614be2b6479d86c12ea15.png!small?1632363161902

同TGS一样,服务端收到Authenticator和Ticket后,用私钥解密Ticket,获得TGS封装给它的信息。再用其中的Service Session Key解密Authentictor,获得客户端封装给它的信息。

通过对比客户端信息判断用户身份是否可信,再检查时间戳、生命周期等保证会话安全性。

之后,客户端和服务端就能愉快地进行通信啦!

1632363202_614be2c253ba45c461c2f.png!small?1632363175244

由此可见,为了把通信密钥安全地送到客户端和服务端手里,Kerberos废了多大的力,下面这张图总结了kerberos协议在整个交易过程中所用到的密钥。

1632363209_614be2c98c46f0203d5de.png!small?1632363181253

#结语#

尽管Kerberos的认证模式已经能满足大多数企业的安全需求了,但这样就足够了吗?不是的,其中还存在很多威胁。AD域的攻击行为,很多都与Kerberos相关,比如哈希传递、黄金票据、Kerberoast攻击等。了解Kerberos协议的作用原理后,我们就可以针对各个阶段特有的威胁采取针对性的防护措施,帮助我们选择智能运营方案。

以上就是我们给大家介绍的Kerberos协议的全部内容,下一篇文章中,我们将继续为大家介绍ntlm协议。

在Kerberos出现之前,NTLM被广泛应用于工作组和域环境,是更早的用于对用户进行身份验证的协议。

相比于Kerberos,NTLM的认证原理比较简单,主要通过对比客户端和服务端加密后的数据,判断其是否一致,以确定用户身份。

如果用做菜来比喻,那么被加密的数据就是“原材料”,加密密钥就是“秘方”,原理就是“用不同的秘方做出来的菜味道不一样”。当秘方只有客户端和服务端知道,服务端确定用户身份时,只需要用该秘方和客户端做同一盘菜,对比两盘菜的味道,如果一样,那就是真实的客户端。

1632709688_61512c38966aecde17552.png!small?1632709662939

目前NTLM有两个版本,分别是NTLMv1和NTLMv2,他们间最主要的区别体现在被加密数据的长度上,也就是“原材料”的种类。在v1版本中数据长度是8位,而v2版本中增加到16位。

v2版本相较于v1安全性更高,在网络中应用较多。因此,本篇文章中,我们将基于NTLMv2的认证原理,详细介绍“客户端登录”、“访问服务器资源”和“域环境下申请服务”这三种情况的认证过程。

客户端登录

回忆我们平常登录电脑的过程,输好密码后就直接跳转到了桌面,整个过程不过一两秒钟。但其实在这短暂的两秒中,电脑内部发生了多重“反应”,从而实现对我们身份的验证。

首先,我们输入的密码会被交给Lsass进程,这个进程对明文密码进行加工,生成唯一的密码哈希。

然后,Lsass进程将从本地内存中,找到该用户账户对应的密码哈希。

最后再比较两者,如果相同,证明该用户的身份是真实的,则允许登录。

1632709749_61512c7580c3085f870bf.png!small?1632709723815

这之中有个关键点:原本存在于本地内存中的密码哈希,是从何而来的呢?

原理是这样的,这个值早在用户注册时,就由Lsass存储在系统中了。这样做的目的,就是为了在系统重启时,快速帮助验证用户身份,保障用户数据安全。

访问服务器资源

在开放网络环境下,用户要访问服务器资源,就需要向服务器提交申请。在NTLM认证过程中,服务器接到申请后,除了验证用户身份,还要判断该用户是否有使用资源的权限、自己是否有能力提供服务等。

接下来我们说说这个过程。

同本地账户类似,用户在访问服务器之前,也需要先在服务器中存有自己的账号,以便在身份验证时进行信息对比。

首先用户注册一个账号,该账号密码以哈希形式存储在服务器中,形成只有用户和服务器知道的“秘方”。

用户请求访问服务时,先将自己的用户名提供给服务器,并且附上想要访问的服务内容。

1632709766_61512c869e0b4246c9138.png!small?1632709740939

服务端接收到请求后,先检查该用户是不是有资格访问服务,也就是查找该用户是否存在于数据库中;如果存在,再进一步确认自己是否能满足请求。

如果该用户确实存在,服务器就会发送一个随机数给客户端,叫用户做“一道菜”来证明自己不是伪冒的,这个随机数就是“原材料“。这时候,伴随着“原材料”一起发送给客户端的,还有它能提供的服务列表。

1632709773_61512c8d156e4d28e13b9.png!small?1632709747401

客户端收到数据后,将随机数取出,用自己的密钥哈希加工,得到色香味唯一的菜肴。然后将“做好的菜”和原料以及自己的用户名放在一起,组成身份验证包,再次发给服务端。

1632709779_61512c93d880e3081f3e9.png!small?1632709754162

服务端从自己的数据库中找到该用户的“秘方”,使用同样的“原材料”——随机数做菜。然后比较两道菜,如果相同,则认为用户身份真实,就可以响应其请求了。

1632709811_61512cb30b8a5f2747adc.png!small?1632709785303

域环境下申请服务

域环境下申请服务时,NTLM的认证过程和第二种情况基本一样,只是在最后验证用户身份时,并不是由服务器来进行,而是域控。

这是为什么呢?

在AD域安全管理系列科普文章中,我们提到,AD域内所有账户信息都存储在域控上。这说明,域环境下的服务器上并没有用户“秘方”,“秘方”只存在于域控上。

所以服务器接收到身份验证包后,会将它转发给域控,由域控来进行验证。

域控在数据库中找到该用户对应的密码哈希,同样加工该随机数,得到加密后的值。将这个值与客户端加密的值进行比较,最后把结果返回给服务器。

1632709858_61512ce2384d68376d68f.png!small?1632709832484

# 结语 #

由上可见,无论哪种情况下,NTLM在认证过程中,都没有在网络上单独传递密码,这减少了密码泄露的可能,提高了系统安全性。

但NTLM的认证方式也不是绝对安全的,基于密码哈希的认证方式,让攻击者在不需要获取明文密码的情况下,也能直接传递密码哈希通过认证。有的攻击者甚至将客户端发送给服务器的验证信息截获,用来进行明文爆破或NTLM中继攻击。

为了防范这样的威胁,我们需要选择安全性更高的认证协议或采取专门的安全运营方案。

以上就是我们给大家介绍的NTLM协议的全部内容,下一篇文章中,我们将继续为大家介绍LDAP协议。

在Kerberos出现之前,NTLM被广泛应用于工作组和域环境,是更早的用于对用户进行身份验证的协议。

相比于Kerberos,NTLM的认证原理比较简单,主要通过对比客户端和服务端加密后的数据,判断其是否一致,以确定用户身份。

如果用做菜来比喻,那么被加密的数据就是“原材料”,加密密钥就是“秘方”,原理就是“用不同的秘方做出来的菜味道不一样”。当秘方只有客户端和服务端知道,服务端确定用户身份时,只需要用该秘方和客户端做同一盘菜,对比两盘菜的味道,如果一样,那就是真实的客户端。

1632709688_61512c38966aecde17552.png!small?1632709662939

目前NTLM有两个版本,分别是NTLMv1和NTLMv2,他们间最主要的区别体现在被加密数据的长度上,也就是“原材料”的种类。在v1版本中数据长度是8位,而v2版本中增加到16位。

v2版本相较于v1安全性更高,在网络中应用较多。因此,本篇文章中,我们将基于NTLMv2的认证原理,详细介绍“客户端登录”、“访问服务器资源”和“域环境下申请服务”这三种情况的认证过程。

客户端登录

回忆我们平常登录电脑的过程,输好密码后就直接跳转到了桌面,整个过程不过一两秒钟。但其实在这短暂的两秒中,电脑内部发生了多重“反应”,从而实现对我们身份的验证。

首先,我们输入的密码会被交给Lsass进程,这个进程对明文密码进行加工,生成唯一的密码哈希。

然后,Lsass进程将从本地内存中,找到该用户账户对应的密码哈希。

最后再比较两者,如果相同,证明该用户的身份是真实的,则允许登录。

1632709749_61512c7580c3085f870bf.png!small?1632709723815

这之中有个关键点:原本存在于本地内存中的密码哈希,是从何而来的呢?

原理是这样的,这个值早在用户注册时,就由Lsass存储在系统中了。这样做的目的,就是为了在系统重启时,快速帮助验证用户身份,保障用户数据安全。

访问服务器资源

在开放网络环境下,用户要访问服务器资源,就需要向服务器提交申请。在NTLM认证过程中,服务器接到申请后,除了验证用户身份,还要判断该用户是否有使用资源的权限、自己是否有能力提供服务等。

接下来我们说说这个过程。

同本地账户类似,用户在访问服务器之前,也需要先在服务器中存有自己的账号,以便在身份验证时进行信息对比。

首先用户注册一个账号,该账号密码以哈希形式存储在服务器中,形成只有用户和服务器知道的“秘方”。

用户请求访问服务时,先将自己的用户名提供给服务器,并且附上想要访问的服务内容。

1632709766_61512c869e0b4246c9138.png!small?1632709740939

服务端接收到请求后,先检查该用户是不是有资格访问服务,也就是查找该用户是否存在于数据库中;如果存在,再进一步确认自己是否能满足请求。

如果该用户确实存在,服务器就会发送一个随机数给客户端,叫用户做“一道菜”来证明自己不是伪冒的,这个随机数就是“原材料“。这时候,伴随着“原材料”一起发送给客户端的,还有它能提供的服务列表。

1632709773_61512c8d156e4d28e13b9.png!small?1632709747401

客户端收到数据后,将随机数取出,用自己的密钥哈希加工,得到色香味唯一的菜肴。然后将“做好的菜”和原料以及自己的用户名放在一起,组成身份验证包,再次发给服务端。

1632709779_61512c93d880e3081f3e9.png!small?1632709754162

服务端从自己的数据库中找到该用户的“秘方”,使用同样的“原材料”——随机数做菜。然后比较两道菜,如果相同,则认为用户身份真实,就可以响应其请求了。

1632709811_61512cb30b8a5f2747adc.png!small?1632709785303

域环境下申请服务

域环境下申请服务时,NTLM的认证过程和第二种情况基本一样,只是在最后验证用户身份时,并不是由服务器来进行,而是域控。

这是为什么呢?

在AD域安全管理系列科普文章中,我们提到,AD域内所有账户信息都存储在域控上。这说明,域环境下的服务器上并没有用户“秘方”,“秘方”只存在于域控上。

所以服务器接收到身份验证包后,会将它转发给域控,由域控来进行验证。

域控在数据库中找到该用户对应的密码哈希,同样加工该随机数,得到加密后的值。将这个值与客户端加密的值进行比较,最后把结果返回给服务器。

1632709858_61512ce2384d68376d68f.png!small?1632709832484

# 结语 #

由上可见,无论哪种情况下,NTLM在认证过程中,都没有在网络上单独传递密码,这减少了密码泄露的可能,提高了系统安全性。

但NTLM的认证方式也不是绝对安全的,基于密码哈希的认证方式,让攻击者在不需要获取明文密码的情况下,也能直接传递密码哈希通过认证。有的攻击者甚至将客户端发送给服务器的验证信息截获,用来进行明文爆破或NTLM中继攻击。

为了防范这样的威胁,我们需要选择安全性更高的认证协议或采取专门的安全运营方案。

以上就是我们给大家介绍的NTLM协议的全部内容,下一篇文章中,我们将继续为大家介绍LDAP协议。

上一篇文章,我们了解了AD域的架构和原理。本篇文章我们将引入AD域服务的重头戏——AD域的功能。

众所周知,AD域在企业内网中扮演了重要的角色,集身份验证和服务管理于一身。它是如何进行身份验证和资源管理的,在企业内网管理中有什么明显优势呢?

本篇文章从AD域服务对资源对象的管理方式开始,逐步讲述它的身份验证能力和策略配置特性。

【全局资源管理】

要将内网中的资源部署到AD域内,需要在域控上注册。域计算机和打印机、共享文件夹等一起组成域环境,企业员工要在这个域环境内办公,需要注册成为域用户。

所有资源注册成功后,由AD域来统一管理。下面,我们通过AD域管理域计算机和域用户的一些特点,来探查其一般模式。

本地计算机在域控上注册后就成为域计算机,拥有单独的域账户,该账户记录计算机的位置、操作系统类型和计算机名等信息。

这个计算机名并非原名,而是在加域后重新生成的。它采用DNS格式,在允许分配单独名称的基础上,还能清晰显示组织单位中的计算机结构。比如在zawx.com域下注册的计算机,名称可能为pc.zawx.com。

企业员工在域控上注册成为域用户后,也会生成单独的域账户,账户上保存了员工的电话、邮箱、身份证号等基本信息,还有权限、账号密码等信息。

不同用户拥有不同权限:

◼普通域用户:

普通域用户接受域管理员的指派,对资源的使用程度有限制。一般是根据员工岗位的实际情况赋予权限,比如允许使用打印机,拒绝修改共享文件夹等。

◼域管理员:

域管理员管理域内资源的使用关系,委派域用户间的适应关系,比如允许A用户更改其它用户的密码。

◼企业管理员:

企业管理员账户存在于企业的每一个域中,拥有对每一个域的登录权限。它是企业中权限级别最高的账户,能够指派或取消域管理员权限。

由上,我们可以看出AD域对资源的一般管理模式是:为注册资源创建一个单独账户,在这个账户上记录资源的一般信息(如位置、电话)和特殊的域内信息(如权限、域内名称)。

在数据库中,AD域将这些资源信息以树形目录的方式组织,在叶子节点存储数据。

这种形式下,管理员可以直接使用标识名(DN)和相对标识名(RDN)两种命名路径来访问资源,相比于挨个对比,极大地提升了资源搜索效率。

【统一身份验证】

域用户在内网中采用单点登录方式,即登录过程由域控统一验证,验证成功就可访问域内资源。

登录过程中,域计算机将用户信息发送给域控,域控会进行计算机和用户两个账号的验证。

域控对计算机进行验证的方式是通过对比本地和域控上保存的计算机账户密码。本地密码每30天更新一次,新旧密码同时保存。验证过程中,先发送新密码,再发送旧密码。两密码中的任何一个与域控上保存的密码相同,就能通过验证。

而对域用户的验证一般是用的Kerberos认证。Kerberos认证服务器KDC安装在域控上,由AS和TGS组成。用户信息先发送给AS,由AS在AD数据库中查询是否有该用户记录,如果存在且信息吻合,就返回一个TGT。之后用户使用TGT向TGS请求Ticket,然后就能使用该Ticket访问特定服务了。

正是因为登录验证过程是在域控上统一进行,域用户在任一域计算机上都能登录,并获得同样的该用户权限。这种方式让用户登录更具灵活性,也增强了抵抗主机故障的能力。

【集中策略配置】

AD域最大的管理优势是,只需一次操作,就能实现大量资源属性的配置。

要达到这种效果,有分组和组策略两种方式。

分组情况下,需要域管理员手动将符合条件的域用户加到一个组中,然后对该组对象进行配置,最终作用到组内每一个用户身上,一般有通信组和安全组两种类型。

在通信组中,对该通信组发送一次消息,就会分发给组内所有成员,比如邮件组。

安全组主要是用来设置权限,通常将企业内同一岗位的员工放到一个组中配置权限;对新加入的用户,可以将它添加到相应的组,直接继承该组权限。

组策略对象由容器和模板两部分组成。如果将容器用食物来比喻,模板就像调味料,决定食物是什么味道的。容器一般由组织单位、域、站点等来充当,而模板可以是首选项设置、软件安装等。

创建域时,通常会形成两个默认组策略对象,一个是默认域策略,一个是默认域控制器策略。这两个组策略配置了域的基本属性,一般不能被修改。

拿域组策略来说,组策略会对域中的每个计算机和用户产生影响。组策略的应用效果保存在注册表中,计算机通过读取注册表来表现组策略内容。

如果计算机所属的域和组织单位等都分别配置了组策略,它将根据优先级从小到大地应用。通常的优先级顺序是:本地组策略——站点组策略——域组策略——组织单位组策略,如果有冲突,则以最高优先级为准。

集中策略配置为管理员省去了不少麻烦,帮助企业提高了整体工作效率。

结语 

本文我们探讨了AD域的资源管理、身份验证和策略配置等功能属性,此基础上,更多特性等着我们在企业应用实践中一一探索。

同时,AD域在发展得越来越适应企业管理需求时,也面临着更多针对它的独特攻击手法。在大量应用AD域的基础上,我们也应当注重其安全防护建设。

在AD域的安全管理两篇科普文章中,我们分别为大家介绍了域的形成和架构、AD域服务的功能。不知道大家觉得如何呢?如果想了解其他AD域的拓展内容,请给我们留言,我们会持续不断地为大家提供更多的AD域知识与支持。

上一篇文章,我们了解了AD域的架构和原理。本篇文章我们将引入AD域服务的重头戏——AD域的功能。

众所周知,AD域在企业内网中扮演了重要的角色,集身份验证和服务管理于一身。它是如何进行身份验证和资源管理的,在企业内网管理中有什么明显优势呢?

本篇文章从AD域服务对资源对象的管理方式开始,逐步讲述它的身份验证能力和策略配置特性。

【全局资源管理】

要将内网中的资源部署到AD域内,需要在域控上注册。域计算机和打印机、共享文件夹等一起组成域环境,企业员工要在这个域环境内办公,需要注册成为域用户。

所有资源注册成功后,由AD域来统一管理。下面,我们通过AD域管理域计算机和域用户的一些特点,来探查其一般模式。

本地计算机在域控上注册后就成为域计算机,拥有单独的域账户,该账户记录计算机的位置、操作系统类型和计算机名等信息。

这个计算机名并非原名,而是在加域后重新生成的。它采用DNS格式,在允许分配单独名称的基础上,还能清晰显示组织单位中的计算机结构。比如在zawx.com域下注册的计算机,名称可能为pc.zawx.com。

企业员工在域控上注册成为域用户后,也会生成单独的域账户,账户上保存了员工的电话、邮箱、身份证号等基本信息,还有权限、账号密码等信息。

不同用户拥有不同权限:

◼普通域用户:

普通域用户接受域管理员的指派,对资源的使用程度有限制。一般是根据员工岗位的实际情况赋予权限,比如允许使用打印机,拒绝修改共享文件夹等。

◼域管理员:

域管理员管理域内资源的使用关系,委派域用户间的适应关系,比如允许A用户更改其它用户的密码。

◼企业管理员:

企业管理员账户存在于企业的每一个域中,拥有对每一个域的登录权限。它是企业中权限级别最高的账户,能够指派或取消域管理员权限。

由上,我们可以看出AD域对资源的一般管理模式是:为注册资源创建一个单独账户,在这个账户上记录资源的一般信息(如位置、电话)和特殊的域内信息(如权限、域内名称)。

在数据库中,AD域将这些资源信息以树形目录的方式组织,在叶子节点存储数据。

这种形式下,管理员可以直接使用标识名(DN)和相对标识名(RDN)两种命名路径来访问资源,相比于挨个对比,极大地提升了资源搜索效率。

【统一身份验证】

域用户在内网中采用单点登录方式,即登录过程由域控统一验证,验证成功就可访问域内资源。

登录过程中,域计算机将用户信息发送给域控,域控会进行计算机和用户两个账号的验证。

域控对计算机进行验证的方式是通过对比本地和域控上保存的计算机账户密码。本地密码每30天更新一次,新旧密码同时保存。验证过程中,先发送新密码,再发送旧密码。两密码中的任何一个与域控上保存的密码相同,就能通过验证。

而对域用户的验证一般是用的Kerberos认证。Kerberos认证服务器KDC安装在域控上,由AS和TGS组成。用户信息先发送给AS,由AS在AD数据库中查询是否有该用户记录,如果存在且信息吻合,就返回一个TGT。之后用户使用TGT向TGS请求Ticket,然后就能使用该Ticket访问特定服务了。

正是因为登录验证过程是在域控上统一进行,域用户在任一域计算机上都能登录,并获得同样的该用户权限。这种方式让用户登录更具灵活性,也增强了抵抗主机故障的能力。

【集中策略配置】

AD域最大的管理优势是,只需一次操作,就能实现大量资源属性的配置。

要达到这种效果,有分组和组策略两种方式。

分组情况下,需要域管理员手动将符合条件的域用户加到一个组中,然后对该组对象进行配置,最终作用到组内每一个用户身上,一般有通信组和安全组两种类型。

在通信组中,对该通信组发送一次消息,就会分发给组内所有成员,比如邮件组。

安全组主要是用来设置权限,通常将企业内同一岗位的员工放到一个组中配置权限;对新加入的用户,可以将它添加到相应的组,直接继承该组权限。

组策略对象由容器和模板两部分组成。如果将容器用食物来比喻,模板就像调味料,决定食物是什么味道的。容器一般由组织单位、域、站点等来充当,而模板可以是首选项设置、软件安装等。

创建域时,通常会形成两个默认组策略对象,一个是默认域策略,一个是默认域控制器策略。这两个组策略配置了域的基本属性,一般不能被修改。

拿域组策略来说,组策略会对域中的每个计算机和用户产生影响。组策略的应用效果保存在注册表中,计算机通过读取注册表来表现组策略内容。

如果计算机所属的域和组织单位等都分别配置了组策略,它将根据优先级从小到大地应用。通常的优先级顺序是:本地组策略——站点组策略——域组策略——组织单位组策略,如果有冲突,则以最高优先级为准。

集中策略配置为管理员省去了不少麻烦,帮助企业提高了整体工作效率。

结语 

本文我们探讨了AD域的资源管理、身份验证和策略配置等功能属性,此基础上,更多特性等着我们在企业应用实践中一一探索。

同时,AD域在发展得越来越适应企业管理需求时,也面临着更多针对它的独特攻击手法。在大量应用AD域的基础上,我们也应当注重其安全防护建设。

在AD域的安全管理两篇科普文章中,我们分别为大家介绍了域的形成和架构、AD域服务的功能。不知道大家觉得如何呢?如果想了解其他AD域的拓展内容,请给我们留言,我们会持续不断地为大家提供更多的AD域知识与支持。

作者:[email protected]Amulab

0x00 前言

在前一篇《利用MS-SAMR协议修改用户密码》中介绍了利用MS-SAMR修改用户密码并还原的技巧。在本篇文章中,我们继续介绍MS-SAMR协议的一些其它利用。

0x01 利用

1. 添加本地用户

在渗透测试过程中,我们经常会遇到在目标机器添加账户但被杀软拦截掉的情况。现在较为通用的绕过方法是通过调用NetUserAdd()等API来添加用户

我们同样也可以利用MS-SAMR协议中的SamrCreateUser2InDomain()来添加用户(其实调用MS-SAMR是NetUserAdd()等API的底层实现)

需要注意的有两点,一点是Windows操作系统(域控除外)中的“域”分为内置域(Builtin Domain)和账户域(Account Domain)

◼内置域(Builtin Domain):包含在安装操作系统时建立的默认本地组,例如管理员组和用户组

◼账户域(Account Domain):包含用户、组和本地组帐户。管理员帐户在此域中。在工作站或成员服务器的帐户域中定义的帐户仅限于访问位于该帐户所在物理计算机上的资源

因此我们需要在账户域中添加普通用户,然后在内置域中找到Administrators组,再将该用户添加到内置域中的Administrators中

第二个需要注意的是,利用SamrCreateUser2InDomain()添加的账户默认是禁用状态,因此我们需要调用SamrSetInformationUser()在用户的userAccountControl中清除禁用标志位:

// Clear the UF_ACCOUNTDISABLE to enable account
userAllInfo.UserAccountControl &= 0xFFFFFFFE;
userAllInfo.UserAccountControl |= USER_NORMAL_ACCOUNT;
userAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
RtlInitUnicodeString(&userAllInfo.NtOwfPassword, password.Buffer);

// Set password and userAccountControl
status = SamSetInformationUser(hUserHandle, UserAllInformation, &userAllInfo);

在实现时,如果直接调用MS-SAMR的话在设置用户密码时会非常复杂,涉及到加密算法并且可能需要SMB Session Key(用impacket很好实现,但impacket不支持当前用户身份执行)

但我们可以调用samlib.dll的导出函数,在上一篇文章中提到过这些导出函数其实是封装了协议的调用,实现会更简单一些,代码Demo:https://github.com/loong716/CPPPractice/tree/master/AddUserBypass_SAMR

2. 解决密码过期限制

假设在渗透测试过程中,我们收集到一台服务器的用户账户,但当想要访问目标SMB资源时,发现该账户密码已过期。此处以psexec横向为例,目标显示STATUS_PASSWORD_MUST_CHANGE错误:

此时我们可以利用samba中的smbpasswd来修改该用户的密码

修改之后使用新密码就可以正常访问目标的SMB资源了:

实际上smbpasswd调用的是MS-SAMR的SamrUnicodeChangePasswordUser2(),该方法不需要上下文句柄,并且支持SMB空会话(Null Session)调用

https://github.com/samba-team/samba/blob/e742661bd2507d39dfa47e40531dc1dca636cbbe/source3/libsmb/passchange.c#L192

另外impacket之前也更新了该方法的example,并且该脚本支持hash传递:

https://github.com/SecureAuthCorp/impacket/blob/master/examples/smbpasswd.py

3. 信息收集/修改

MS-SAMR协议在信息收集/修改方面能做的事情很多,如枚举/修改对象的ACL、用户&组信息、枚举密码策略等。此处以枚举本地管理员组账户为例

通常进行本地管理员组账户的枚举会调用NetLocalGroupGetMembers()这一API,前面提到过这类API底层也是调用MS-SAMR协议,先来看一下正常调用的过程:

1、SamrConnect:获取Server对象的句柄

2、SamrOpenDomain:打开目标内置域的句柄

3、SamrLookupNamesInDomain:在内置域中搜索Administrators的RID

4、SamrOpenAlias:根据Administrators的RID打开别名句柄

5、SamrGetMembersInAlias:枚举别名对象中的成员SID

此时我们如果想要开发自动化的信息收集工具(如SharpHound),那么我们需要考虑工具的通用性,比如在第3步调用SamrLookupNamesInDomain()时,我们需要传入"Administrators",但在某些系统中管理员组的名字可能有差异,如部分非英文操作系统中该组名为"Administradors",或者运维修改了本地管理员组名称,这样我们直接调用NetLocalGroupGetMembers()便不合适了

此时我们可以考虑优化这一操作,我们可以注意到本地管理员组在不同Windows系统上的RID始终为544

那么我们可以这样调用:

1、SamrConnect:获取Server对象的句柄

2、SamrOpenDomain:打开目标内置域的句柄

3、SamrOpenAlias:打开RID为544对象的别名句柄

4、SamrGetMembersInAlias:枚举该别名对象中的成员SID

按此思路,我们可以将MS-SAMR的API利用到我们自己工具的武器化or优化上

4. 添加域内机器账户

调用SamCreateUser2InDomain()时指定AccountType为USER_WORKSTATION_TRUST_ACCOUNT可以在域内添加机器账户

// Create computer in domain
status = SamCreateUser2InDomain(hDomainHandle, &computerName, USER_WORKSTATION_TRUST_ACCOUNT, USER_ALL_ACCESS | DELETE | WRITE_DAC, &hUserHandle, &grantAccess, &relativeId);

impacket的addcomputer.py包含了该方法,因为LDAPS需要证书的不稳定所以添加了SAMR(SAMR是Windows GUI环境添加机器使用的协议)

这个地方感觉还是有一些误区的,通过LDAP修改unicodePwd确实需要在加密的连接中操作,但LDAPS并不是必须的,像powermad.ps1在加密LDAP中添加机器账户同样可以成功,并且非常稳定

我们实战中大多数情况下添加机器账户都是在利用基于资源约束委派时,为了拿到一个有SPN的账户所以才选择添加机器账户。但我实际测试中发现该方法并不会自动为机器账户添加SPN,而通过LDAP或其他RPC为机器账户添加SPN又感觉有些画蛇添足,只能先作为一种添加机器账户的实现方法,如果其他方法不成功时可以尝试

0x02 参考

https://docs.microsoft.com/zh-cn/openspecs/windows_protocols/ms-samr/4df07fab-1bbc-452f-8e92-7853a3c7e380

https://github.com/SecureAuthCorp/impacket/

https://snovvcrash.rocks/2020/10/31/pretending-to-be-smbpasswd-with-impacket.html

https://blog.cptjesus.com/posts/sharphoundtechnical

作者:[email protected]Amulab

0x00 前言

在前一篇《利用MS-SAMR协议修改用户密码》中介绍了利用MS-SAMR修改用户密码并还原的技巧。在本篇文章中,我们继续介绍MS-SAMR协议的一些其它利用。

0x01 利用

1. 添加本地用户

在渗透测试过程中,我们经常会遇到在目标机器添加账户但被杀软拦截掉的情况。现在较为通用的绕过方法是通过调用NetUserAdd()等API来添加用户

我们同样也可以利用MS-SAMR协议中的SamrCreateUser2InDomain()来添加用户(其实调用MS-SAMR是NetUserAdd()等API的底层实现)

需要注意的有两点,一点是Windows操作系统(域控除外)中的“域”分为内置域(Builtin Domain)和账户域(Account Domain)

◼内置域(Builtin Domain):包含在安装操作系统时建立的默认本地组,例如管理员组和用户组

◼账户域(Account Domain):包含用户、组和本地组帐户。管理员帐户在此域中。在工作站或成员服务器的帐户域中定义的帐户仅限于访问位于该帐户所在物理计算机上的资源

因此我们需要在账户域中添加普通用户,然后在内置域中找到Administrators组,再将该用户添加到内置域中的Administrators中

第二个需要注意的是,利用SamrCreateUser2InDomain()添加的账户默认是禁用状态,因此我们需要调用SamrSetInformationUser()在用户的userAccountControl中清除禁用标志位:

// Clear the UF_ACCOUNTDISABLE to enable account
userAllInfo.UserAccountControl &= 0xFFFFFFFE;
userAllInfo.UserAccountControl |= USER_NORMAL_ACCOUNT;
userAllInfo.WhichFields |= USER_ALL_USERACCOUNTCONTROL;
RtlInitUnicodeString(&userAllInfo.NtOwfPassword, password.Buffer);

// Set password and userAccountControl
status = SamSetInformationUser(hUserHandle, UserAllInformation, &userAllInfo);

在实现时,如果直接调用MS-SAMR的话在设置用户密码时会非常复杂,涉及到加密算法并且可能需要SMB Session Key(用impacket很好实现,但impacket不支持当前用户身份执行)

但我们可以调用samlib.dll的导出函数,在上一篇文章中提到过这些导出函数其实是封装了协议的调用,实现会更简单一些,代码Demo:https://github.com/loong716/CPPPractice/tree/master/AddUserBypass_SAMR

2. 解决密码过期限制

假设在渗透测试过程中,我们收集到一台服务器的用户账户,但当想要访问目标SMB资源时,发现该账户密码已过期。此处以psexec横向为例,目标显示STATUS_PASSWORD_MUST_CHANGE错误:

此时我们可以利用samba中的smbpasswd来修改该用户的密码

修改之后使用新密码就可以正常访问目标的SMB资源了:

实际上smbpasswd调用的是MS-SAMR的SamrUnicodeChangePasswordUser2(),该方法不需要上下文句柄,并且支持SMB空会话(Null Session)调用

https://github.com/samba-team/samba/blob/e742661bd2507d39dfa47e40531dc1dca636cbbe/source3/libsmb/passchange.c#L192

另外impacket之前也更新了该方法的example,并且该脚本支持hash传递:

https://github.com/SecureAuthCorp/impacket/blob/master/examples/smbpasswd.py

3. 信息收集/修改

MS-SAMR协议在信息收集/修改方面能做的事情很多,如枚举/修改对象的ACL、用户&组信息、枚举密码策略等。此处以枚举本地管理员组账户为例

通常进行本地管理员组账户的枚举会调用NetLocalGroupGetMembers()这一API,前面提到过这类API底层也是调用MS-SAMR协议,先来看一下正常调用的过程:

1、SamrConnect:获取Server对象的句柄

2、SamrOpenDomain:打开目标内置域的句柄

3、SamrLookupNamesInDomain:在内置域中搜索Administrators的RID

4、SamrOpenAlias:根据Administrators的RID打开别名句柄

5、SamrGetMembersInAlias:枚举别名对象中的成员SID

此时我们如果想要开发自动化的信息收集工具(如SharpHound),那么我们需要考虑工具的通用性,比如在第3步调用SamrLookupNamesInDomain()时,我们需要传入"Administrators",但在某些系统中管理员组的名字可能有差异,如部分非英文操作系统中该组名为"Administradors",或者运维修改了本地管理员组名称,这样我们直接调用NetLocalGroupGetMembers()便不合适了

此时我们可以考虑优化这一操作,我们可以注意到本地管理员组在不同Windows系统上的RID始终为544

那么我们可以这样调用:

1、SamrConnect:获取Server对象的句柄

2、SamrOpenDomain:打开目标内置域的句柄

3、SamrOpenAlias:打开RID为544对象的别名句柄

4、SamrGetMembersInAlias:枚举该别名对象中的成员SID

按此思路,我们可以将MS-SAMR的API利用到我们自己工具的武器化or优化上

4. 添加域内机器账户

调用SamCreateUser2InDomain()时指定AccountType为USER_WORKSTATION_TRUST_ACCOUNT可以在域内添加机器账户

// Create computer in domain
status = SamCreateUser2InDomain(hDomainHandle, &computerName, USER_WORKSTATION_TRUST_ACCOUNT, USER_ALL_ACCESS | DELETE | WRITE_DAC, &hUserHandle, &grantAccess, &relativeId);

impacket的addcomputer.py包含了该方法,因为LDAPS需要证书的不稳定所以添加了SAMR(SAMR是Windows GUI环境添加机器使用的协议)

这个地方感觉还是有一些误区的,通过LDAP修改unicodePwd确实需要在加密的连接中操作,但LDAPS并不是必须的,像powermad.ps1在加密LDAP中添加机器账户同样可以成功,并且非常稳定

我们实战中大多数情况下添加机器账户都是在利用基于资源约束委派时,为了拿到一个有SPN的账户所以才选择添加机器账户。但我实际测试中发现该方法并不会自动为机器账户添加SPN,而通过LDAP或其他RPC为机器账户添加SPN又感觉有些画蛇添足,只能先作为一种添加机器账户的实现方法,如果其他方法不成功时可以尝试

0x02 参考

https://docs.microsoft.com/zh-cn/openspecs/windows_protocols/ms-samr/4df07fab-1bbc-452f-8e92-7853a3c7e380

https://github.com/SecureAuthCorp/impacket/

https://snovvcrash.rocks/2020/10/31/pretending-to-be-smbpasswd-with-impacket.html

https://blog.cptjesus.com/posts/sharphoundtechnical