MS14-068原理

作者: const27 分类: 发布时间: 2020-09-22 14:59

参考:https://www.anquanke.com/post/id/192810

MS14-068

这个洞的危害很大,可以让任意域用户提权到域管。
适用版本: server 2000以上
补丁: kb3011780

PAC

PAC是kerberos协议里用来解决用户权限功能所设计出的东西。
在kerberos协议里面,一个用户用自己的hash拿到了TGT,接着凭借着TGT拿到了TGS,接着用TGS去访问服务。看似只要hash正确,用户就能到处访问服务,但是所有服务都可以给这个用户所访问吗?肯定是不行的,所以微软在kerberos为了实现用户权限分级,采用了PAC。
PAC被设计为存在于TGT里面。完整的kerberos权限验证流程如下。

1。用户凭借自己的hash加密时间戳并发送明文用户名到KDC,KDC认证用户成功后返回被krbtgt用户hash加密的TGT(内有ticekt包含着PAC),以及用户自身hash加密的login session key

2.用户凭借TGT票据向KDC发起指定服务的TGS_REQ。KDC用krbtgt hash解密,若解密成功则直接返回服务hash加密的TGS(这里并没考虑用户的权限,直接返回了TGS)

3.用户用TGS向服务发起请求,服务用自己的hash解密TGS后获得PAC,拿着PAC向KDC询问该用户是否有权限访问。KDC拿到PAC后再次解密,得到了PAC里的 用户的sid,以及所在的组,再判断用户是否有访问服务的权限(有些服务不会验证KDC,这样就会导致白银票据攻击)

PAC自身的结构

PAC在Ticket中的结构

又这个图可以知道,PAC只不过是ticket里Authorization DATA的一个分支。
而Authorization data的结构是这样的

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

ad-type中就有这么一个类型 AD-IF-RELEVANT 对应数字1,由上上图可知这是PAC的外壳。
若类型为 AD-IF-RELEVAN ,那么ad-data也是一个 AuthorizationData类型的结构体,也有ad-type 和ad-data.那么这个外壳ad-data的ad-type就是次外壳AD-WIN2K-PAC 了,与 AD-WIN2K-PAC 这个ad-type对应的ad-data就是一段连续空间。 这段空间包含一个头部PACTYPE以及若干个PAC_INFO_BUFFER 。
PACTYPE包含的是 cBuffers,版本以及缓冲区 。
PAC_INFO_BUFFER是key-value型的。PAC_INFO_BUFFER的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结构不应包含多个这种类型的缓冲区。附加的设备声明信息缓冲区必须被忽略。

其中比较重要的是1,6和7

0x00000001 KERBVALIDATIONINFO 这个结构用于存储用户的身份信息.它是一个结构体,这个结构体是这样的(待会我们伪造PAC的时候主要就是伪造此处额 UserId 以及 PGROUP_MEMBERSHIP GroupIds )服务器解包PAC后提取用户的sid以及groupid,然后就把当前发包过来的用户权限当成sid,groupid的权限处理。

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;

0x00000006和0x00000007 6是服务器校验和,由server密码加密。7是KDC校验和,又KDC密码加密。存在的目的就是防止PAC被篡改。

MS14068

这个漏洞的产生主要是微软犯下了三个错误:
1.对校验和的算法实现不够细致,导致在校验和生成时可以不用管server和KDC的hash直接生成,而且生成出来的校验和还是合法的
2.PAC可以不用放在TGT中,即使是这样,KDC也能照常解析出TGT外的PAC
3.下面再说

那么这个漏洞大致的攻击原理是什么呢。
首先,我们在as_request的时候,把include-PAC标志设置为false,那么as_rep就不会在TGT中返回PAC了。然后这个时候我们自己伪造一个pac,在TGS_REQ时发过去就行了。伪造的pac修改USER SID&GROUP SID(在PAC的 0x00000001 KERBVALIDATIONINFO 结构)可以把我们的用户权限改到很高(域管),从而达到提权到域管的能力。

那么伪造PAC,我们就遇到了两个问题:
1.pac里有校验和,防止自己被篡改,我们得有server和KDC密码才能使校验和合法。
2.pac按理说应该在TGT里,但是TGT是被kbrtgt hash加密的,我们无法获取kbrtgt hash继而无法修改TGT内容,继而不能修改PAC。

来说说如何绕过PAC校验和问题。
我们刚刚说过,0x00000006和0x00000007 这两个结构的存在是为了防止PAC被篡改,这个校验和算法采用的是个叫checksum算法然后把kdc hash和服务hash当作key对PAC加密产生的值,从而防止PAC被篡改。但是checksum算法是有很多种的,md5也是checksum的分支之一,修改PAC后,我们只需设置加密算法为MD5并用MD5算法对0x00000001 KERBVALIDATIONINFO进行加密,将生成的值放入两个检验和即可,KDC拿到0x00000001 KERBVALIDATIONINFO,并且通过解析数据包获取当前加密算法为MD5,然后对其进行MD5加密,若加密结果与校验和一致,则认为PAC未被修改

再来说说如何绕过krbtgt hash加密TGT的问题。
因为我们在AS_REQ时设置include-PAC为false,TGT里就不会包含PAC了。那么我们在TGS_REQ时如何把PAC传递给KDC?只需要把PAC放入req-body即可。
这样KDC依旧会正常解析这个TGS_REQ包

注意TGS_REQ里的include-pac依旧是false。
然后KDC接收到PAC后会先解密TGT拿到authenticator里的key对PAC进行解密(TGS_REQ时加密PAC用的key是随机生成的,这个key会放在authenticator里),然后验证一下PAC的签名,若成功然后把解密得到的PAC采用server key和KDC key重新生成校验和,拼接成一个新的TGT返回给客户端。
上面这一段就是微软犯下的第三个错误,很不可思议,居然莫名其妙的返回了一个包含了PAC的TGT回来。总结来说就是构造了一个畸形的TGS_REQ,从TGS_RES得到了一个包含伪造PAC的TGT。

原理就是上面这些,然后我们用包含伪造PAC的TGT到处访问服务即可。

M14068利用

1.工具kekeo https://github.com/gentilkiwi/kekeo/releases/tag/2.2.0-20200718

具体方法为,在kekeo里先执行 kerberos::purge清空票据
然后再执行 exploit::ms14068 /user:xxx /password:xxx /domain:xxx /ptt
即可。

然后就dir \\域控\c$ 试试,如果可以就说明提权成功了(不是每次都能成功的)

2.golenpac https://github.com/maaaaz/impacket-examples-windows/blob/master/goldenPac.exe

这个工具好用,

执行类似上述命令,就能返回一个域控的 system权限的cmd shell回来,感觉蛮好用
另外在最后指定域控机器时,可以指定域控以外的机器并获取他们的本地system权限用户.
但返回的似乎不是域控?

3.ms14068.exe https://github.com/ianxtianxt/MS14-068

用MS14068 exp制造一个ccache文件。

然后使用mimikatz,把生成的ccache注射进入内存。

然后dir一下域控c$,发现能够访问

既然如此,那直接psexec开启,拿shell

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

Leave a Reply

Your email address will not be published. Required fields are marked *

标签云