域渗透-kerberos协议分析


文章中对之前的文章提出了一些疑问,如果发现有错误,还望斧正

环境搭建

这里的域环境搭建就不再细说

主机ip用户主机名
域控192.168.164.133administratorad.test.com
域内主机192.168.164.129testuser.test.com

两台主机均为win2008r2

名词解释

(1)Client:访问服务的客户机

(2)Server:提供服务的服务器

(3)KDC(Key Distribution Center):密钥分发中心 

(4)KDC中分成两个部分:Authentication Service和Ticket Granting Service
    Authentication Service(AS):身份验证服务
    Ticket Granting Service(TGS):票据授予服务

    AS和TGS如下:

    Authentication Service:AS的作用就是验证Client端的身份,验证通过之后,AS就会给TGT票据(Ticket Granting Ticket)给Client.
    Ticket-granting cookie(TGC):存放用户身份认证凭证的cookie,在浏览器和CAS Server间通讯时使用,是CAS Server用来明确用户身份的凭证。TGT封装了TGC值以及此Cookie值对应的用户信息.
    Ticket-granting ticket(TGT):TGT对象的ID就是TGC的值,在服务器端,通过TGC查询TGT.


    Ticket Granting Service(TGS):TGS的作用是通过AS发送给Client的TGT换取访问Server端的ST(Server Ticket)给Client.
    SEerver Ticket(ST):ST服务票据,由TGS服务发布.


(5)Active Directory(AD):活动目录

(6)Domain Controller(DC):域控制器

(7)Ticket-granting cookie(TGC):存放用户身份认证凭证的cookie,在浏览器和CAS Server间通讯时使用,是CAS Server用来明确用户身份的凭证。TGT封装了TGC值以及此Cookie值对应的用户信息.

(8)Ticket-granting ticket(TGT):TGT对象的ID就是TGC的值,在服务器端,通过TGC查询TGT.

认证过程

我们这里直接抓包来看,让域内机器user使用用户test来登录
在这里插入图片描述

AS-REQ

在这里插入图片描述

Pvno  kerberos协议版本号:05(Hex)
5MSG-TYPE 类型 AS_REQ对应(krb-as-req)0a(Hex)
PA-DATA  预认证信息数据 一个列表,包含若干个认证消息用于认证,每个认证消息有type和value。
AS_REQ 阶段主要用到的有两个
  1.ENC_TIMESTAMP
  这个是预认证,就是用用户hash加密时间戳,作为value 发送给AS服务器。然后AS服务器那边有用户hash,使用用户hash进行解密,获得时间戳,如果能解密,且时间戳在一定的范围内,则证明认证通过。
  2.PA_PAC_REQUEST
  这个是启用PAC支持的扩展。PAC(Privilege Attribute Certificate)并不在原生的kerberos里面,是微软引进的扩展。PAC包含在AS_REQ的响应body(AS_REP)。这里的value对应的是include=true或者include=false(KDC根据include的值来判断返回的票据中是否携带PAC)。
REQ_BODY 
  1.cname
  PrincipalName 类型。PrincipalName包含type和value。
  KRB_NT_PRINCIPAL = 1 means just the name of the principal 如daizhibin
  KRB_NT_SRV_INST = 2 service and other unique instance (krbtgt) 如krbtgt,cifs
  KRB_NT_ENTERPRISE_PRINCIPAL = 10 如 user@domain.com
  在AS_REQ里面cname 是请求的用户,这个用户名存在和不存在,返回的包有差异,可以用于枚举域内用户名。
  2.sname
  PrincipalName 类型,在AS_REQ里面sname是krbtgt,类型是KRB_NT_SRV_INST
  3.realm 域名
  4.from 发送时间
  5.till 到期时间
  原文中的到期时间说可以作为流量监测,但是我在本地抓包时发现,win2008r2默认的到期时间即为文章中说的值,所以无法作为流量监测判定依据
  6.nonce
  随机生成的一个数kekeo/mimikatz nonce是12381973,rubeus nonce是1818848256,这个也可以用来作为特征检测工具。
  这里是原文说的,https://www.anquanke.com/post/id/190261
  但是我在本地测试时候发现,mimikatz并不会直接触发kerberos认证,pth也是注入到内存,触发的时候nonce还是走的本地,并不会涉及到mimikatz的nonce,而rubeus的nonce已经修复https://github.com/GhostPack/Rubeus/issues/34
  7.etype
  加密类型
这个地方要注意的是如果在配置里面选择用hash(不是plaintext)的话,hash的加密类型,要跟etype一样。因为KDC是按照etype类型选择用户对应加密方式的hash,如果是选择明文(plaintext),那么client 会按照etype里面的加密方式将明文加密成hash

AS获取用户名之后,获取对应的ntlm值,通过加密的方法加密数据信息,并且验证时间戳,之后生成随机字符串Session Key,使用用户的ntlm值加密Session Key,使用krbtgt用户的ntlm加密Session Key和客户端信息,一起返回客户端

Send=user_NTML_Hash(Session Key)+krbtgt_NTML_Hash(Session Key+client_info1)[TGT]

抓包的真实情况

AS-REQ存在俩种包

  1. 不存在pA-ENC-TIMESTAMP字段的,和前面存在密码字段的
    在这里插入图片描述

AS-REP

用户名和密码正确(第二个包)

在这里插入图片描述

用户名不正确(第一个包)

这里很明显就可以看到,用户名不正确返回的结果有很大差异,可以利用这个方法来爆破用户名??,
在这里插入图片描述

用户名正确(第一个包)

在这里插入图片描述

密码不正确(只有第一个包,无第二个包)

在这里插入图片描述
这里可以看到首先发送一个不带密码的AS-REQ,判断用户名是否正确,之后再发送一个带密码的AS-REQ,来判断是否通过认证
我们可以通过第一步判断用户名的包进行一个用户枚举,通过返回值的不同来进行爆破

客户端在收到AS-REP之后使用ntlm解密获得Session Key,使用Session Key加密客户端信息和时间戳,连同TGT发送给TGS

Send=Session Key(time+client_info2)+krbtgt_NTML_Hash(Session Key+client_info1)[TGT]

TGS-REQ

在这里插入图片描述
TGS接受到数据后,使用krbtgtntlm解密tgt,获得Session Key,使用Session Key解密获得client_info2time,对比tgt当中的clinet_info1time,通过验证之后,TGS发送票据给客户端

Send=Server_Hash(Server Session Key+Client_info+time)[Trick]+Session key(Server Session Key)

这里有个问题,为什么要来回发送这个tgt,反正AS和TGS都在域控内,
1.因为服务器少于客户端,如果每个tgt都存在服务器内,需要进行一个映射表,产生开销
2.在AS和TGS内部传输可能存在一些问题
req-body
在这里插入图片描述

padding:0
kdc-options:用于与KDC约定一些选项设置
realm:域名
sname:这里是要请求的服务
till:到期时间
(参考的文章说到期时间为20370913024805Z为mimikatz的特征,)这里抓包验证一下,win2008默认也是这个特征,这是个伪命题
nonce:随机生成数 
etype:加密类型

TGS-REP

在这里插入图片描述
客户端使用Session key解密Server Session Key,向服务端提交请求,并提供TicketServer Session key加密的客户端信息与时间戳 ,与服务器进行通信。通过认证后Ticket会一致在客户端内存中。

Send=Server_Hash(Server Session Key+Client_info+time)[Trick]+Server Session Key(Client_info2+time)

S4U2SELF

S4U2self 使得服务可以代表用户获得针对服务自身的kerberos服务票据。这使得服务可以获得用户的授权( 可转发 的用户TGS票据),然后将其用于后期的认证(主要是后期的s4u2proxy),这是为了在用户以不使用 Kerberos 的方式对服务进行身份验证的情况下使用。这里面很重要的一点是服务代表用户获得针对服务自身的kerberos票据这个过程,服务是不需要用户的凭据的,其中转发这部分主要是委派使用,

S4U2PROXY

s4u2proxy 使得服务1可以使用来自用户的授权( 在S4U2SELF阶段获得),然后用该TGS(放在AddtionTicket里面)向KDC请求访问服务2的TGS,并且代表用户访问服务2,而且只能访问服务2。

ST认证

这里直接使用先知的图
1.服务端验证客户端:防止非法用户操作
在这里插入图片描述

2.客户端验证服务端:防止误入恶意服务
在这里插入图片描述

PS:PAC并不是所有服务都开启的,这需要配置验证KDC PAC 签名。没有验证PAC,可能会导致白银票据攻击。因为开启PAC后,就算攻击者拥有用户hash,能制作ST票据后,无法通过PAC验证,还是无法访问服务。

PAC

前面说到有些服务会不使用pac,pac存在最严重的漏洞就是ms14-068
下面是pac的结构,这里参考daiker的文章https://daiker.gitbook.io/windows-protocol/kerberos/3#0x02-pac-jie-gou

PAC的结构如下图所示。

封装层

PAC整体的结构上是一个AuthorizationData的结构

AuthorizationData       ::= SEQUENCE OF SEQUENCE {
              ad-type         [0] Int32,
              ad-data         [1] OCTET STRING
 }

AuthorizationData结构的ad-type主要有以下几个

AD-IF-RELEVANT                     1
AD-INTENDED-FOR-SERVER             2
AD-INTENDED-FOR-APPLICATION-CLASS  3
AD-KDC-ISSUED                      4
AD-AND-OR                          5
AD-MANDATORY-TICKET-EXTENSIONS     6
AD-IN-TICKET-EXTENSIONS            7
AD-MANDATORY-FOR-KDC               8
Reserved values                 9-63
OSF-DCE                           64
SESAME                            65
AD-OSF-DCE-PKI-CERTID             66 (hemsath @us.ibm.com)
AD-WIN2K-PAC                     128 (jbrezak @exchange.microsoft.com)
AD-ETYPE-NEGOTIATION             129  (lzhu @windows.microsoft.com)

如上图所示,整个PAC最外层的ad-type为AD-IF-RELEVANT,ad-data还是一个AuthorizationData结构。

这个AuthorizationData的ad-type 为AD-WIN2K-PAC,ad-data为一段连续的空间,

这段空间包含一个头部PACTYPE以及若干个PAC_INFO_BUFFER

头部PACTYPE包括cBuffers,版本以及缓冲区PAC_INFO_BUFFER为key-value型的

key 的类型如下表所示

类型意义
0x00000001登录信息。PAC结构必须包含一个这种类型的缓冲区。其他登录信息缓冲区必须被忽略。
0x00000002凭证信息。PAC结构不应包含多个此类缓冲区。第二或后续凭证信息缓冲区在接收时必须被忽略。
0x00000006服务器校验和。PAC结构必须包含一个这种类型的缓冲区。其他登录服务器校验和缓冲区必须被忽略。
0x00000007KDC(特权服务器)校验和(第2.8节)。PAC结构必须包含一个这种类型的缓冲区。附加的KDC校验和缓冲区必须被忽略。
0x0000000A客户名称和票证信息。PAC结构必须包含一个这种类型的缓冲区。附加的客户和票据信息缓冲区必须被忽略。
0x0000000B受约束的委派信息。PAC结构必须包含一个S4U2proxy请求的此类缓冲区,否则不包含。附加的受约束的委托信息缓冲区必须被忽略。
0x0000000C用户主体名称(UPN)和域名系统(DNS)信息。PAC结构不应包含多个这种类型的缓冲区。接收时必须忽略第二个或后续的UPN和DNS信息缓冲区。
0x0000000D客户索取信息。PAC结构不应包含多个这种类型的缓冲区。附加的客户要求信息缓冲区必须被忽略。
0x0000000E设备信息。PAC结构不应包含多个这种类型的缓冲区。附加的设备信息缓冲区必须被忽略。
0x0000000F设备声明信息。PAC结构不应包含多个这种类型的缓冲区。附加的设备声明信息缓冲区必须被忽略。

下面详细介绍四个比较重要的

  • 0x00000001 KERB_VALIDATION_INFO

这个结构是登录信息,也是整个PAC最重要的部分,整个PAC就靠它来验证用户身份了,是个结构体,如下

typedef struct _KERB_VALIDATION_INFO {
   FILETIME LogonTime;
   FILETIME LogoffTime;
   FILETIME KickOffTime;
   FILETIME PasswordLastSet;
   FILETIME PasswordCanChange;
   FILETIME PasswordMustChange;
   RPC_UNICODE_STRING EffectiveName;
   RPC_UNICODE_STRING FullName;
   RPC_UNICODE_STRING LogonScript;
   RPC_UNICODE_STRING ProfilePath;
   RPC_UNICODE_STRING HomeDirectory;
   RPC_UNICODE_STRING HomeDirectoryDrive;
   USHORT LogonCount;
   USHORT BadPasswordCount;
   ULONG UserId; //用户的sid
   ULONG PrimaryGroupId; 
   ULONG GroupCount;
   [size_is(GroupCount)] PGROUP_MEMBERSHIP GroupIds;//用户所在的组,如果我们可以篡改的这个的话,添加一个500(域管组),那用户就是域管了。在ms14068 PAC签名被绕过,用户可以自己制作PAC的情况底下,pykek就是靠向这个地方写进域管组,成为使得改用户变成域管
   ULONG UserFlags;
   USER_SESSION_KEY UserSessionKey;
   RPC_UNICODE_STRING LogonServer;
   RPC_UNICODE_STRING LogonDomainName;
   PISID LogonDomainId;
   ULONG Reserved1[2];
   ULONG UserAccountControl;
   ULONG SubAuthStatus;
   FILETIME LastSuccessfulILogon;
   FILETIME LastFailedILogon;
   ULONG FailedILogonCount;
   ULONG Reserved3;
   ULONG SidCount;
   [size_is(SidCount)] PKERB_SID_AND_ATTRIBUTES ExtraSids;
   PISID ResourceGroupDomainSid;
   ULONG ResourceGroupCount;
   [size_is(ResourceGroupCount)] PGROUP_MEMBERSHIP ResourceGroupIds;
} KERB_VALIDATION_INFO;
  • 0x0000000A PAC_CLIENT_INFO

  • 客户端Id(8个字节):

    包含在Kerberos初始TGT的authtime

  • NameLength(2字节)

    用于指定Name 字段的长度(以字节为单位)。

  • Name

    包含客户帐户名的16位Unicode字符数组,格式为低端字节序。

  • 0x00000006和0x00000007 0x00000006 对应的是服务检验和,0x00000007 对应的是KDC校验和。分别由server密码和KDC密码加密,是为了防止PAC内容被篡改。

    存在签名的原因有两个。首先,存在带有服务器密钥的签名,以防止客户端生成自己的PAC并将其作为加密授权数据发送到KDC,以包含在票证中。其次,提供具有KDC密钥的签名,以防止不受信任的服务伪造带有无效PAC的票证。

    两个都是PAC_SIGNATURE_DATA结构,他包括以下结构。 1. SignatureType(4个字节)

类型含义签名长度
0xFFFFFF76KERB_CHECKSUM_HMAC_MD516
0x0000000FHMAC_SHA1_96_AES12812
0x00000010HMAC_SHA1_96_AES25612
  1. Signature

    包含校验和。签名的长度由SignatureType字段的值确定 3. RODCIdentifier(2个字节):

    当KDC为RODC时,包含密钥版本号的前16位。当KDC不是RODC时,此字段不存在。

ms14-068

补丁编号是KB3011780,域里面最严重的漏洞之一,它允许任意用户提升到域管权限。下面简要分析下该漏洞。
该漏洞最本质的地方在于Microsoft Windows Kerberos KDC无法正确检查Kerberos票证请求随附的特权属性证书(PAC)中的有效签名,这里面的签名就是上面提到的服务检验和以及KDC校验和。导致用户可以自己构造一张PAC。 签名原本的设计是要用到HMAC系列的checksum算法,也就是必须要有key的参与,我们没有krbtgt的hash以及服务的hash,就没有办法生成有效的签名,但是问题就出在,实现的时候允许所有的checksum算法都可以,包括MD5。那我们只需要把PAC 进行md5,就生成新的校验和。这也就意味着我们可以随意更改PAC的内容,完了之后再用md5 给他生成一个服务检验和以及KDC校验和。在MS14-068修补程序之后,Microsoft添加了一个附加的验证步骤,以确保校验和类型为KRB_CHECKSUM_HMAC_MD5。

域用户(513)
域管理员(512)
架构管理员(518)
企业管理员(519)
组策略创建者所有者(520)

域控解密pac获得sid,以及所在的组,所以我们需要修改用户所在的组

漏洞的实现方法是在as-req发送时选择include_pac为false,生成的tgt也就不包含pac,之后伪造一个pac,sid为用户sid,将管理组的sid加入groupid,之后将伪造的pac加密放在enc-authorization-data里面,发起TGS-REQ请求,密钥是在PA-DATA里面的AP-REQ的authenticator里面的subkey,KDC收到TGS-REQ请求后解析AP_REQ,提取authenticator,用session_key解密或者subkey,之后解密enc-authorization-data,获得pac,通过校验,

参考文章

https://xz.aliyun.com/t/8187
https://www.anquanke.com/post/id/190261
https://daiker.gitbook.io/windows-protocol/kerberos/

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值