前言
這篇文章主要講的內(nèi)容是微軟為了訪問控制而引進(jìn)的一個擴(kuò)展PAC,以及PAC在歷史上出現(xiàn)過的一個嚴(yán)重的,允許普通用戶提升到域管的漏洞MS14068。
一.PAC介紹
網(wǎng)上很多版本的kerberos的流程是
1.用戶向KDC發(fā)起AS_REQ,請求憑據(jù)是用戶hash加密的時間戳,KDC使用用戶hash進(jìn)行解密,如果結(jié)果正確返回用krbtgt hash加密的TGT票據(jù)
2.用戶憑借TGT票據(jù)向KDC發(fā)起針對特定服務(wù)的TGS_REQ請求,KDC使用krbtgt hash進(jìn)行解密,如果結(jié)果正確,就返回用服務(wù)hash 加密的TGS票據(jù)
3.用戶拿著TGS票據(jù)去請求服務(wù),服務(wù)使用自己的hash解密TGS票據(jù)。如果解密正確,就允許用戶訪問。
上面這個流程看起來沒錯,卻忽略一個最重要的因素,那就是用戶有沒有權(quán)限訪問該服務(wù),在上面的流程里面,只要用戶的hash正確,那么就可以拿到TGT,有了TGT,就可以拿到TGS,有了TGS,就可以訪問服務(wù),任何一個用戶都可以訪問任何服務(wù)。也就是說上面的流程解決了”Who am i?”的問題,并沒有解決 “What can I do?”的問題。
為了解決上面的這個問題,微軟引進(jìn)了PAC,引進(jìn)PAC之后的kerberos流程變成
1.用戶向KDC發(fā)起AS_REQ,請求憑據(jù)是用戶hash加密的時間戳,KDC使用用戶hash進(jìn)行解密
如果結(jié)果正確返回用krbtgt hash加密的TGT票據(jù),TGT里面包含PAC,PAC包含用戶的sid,用戶所在的組。

2.用戶憑借TGT票據(jù)向KDC發(fā)起針對特定服務(wù)的TGS_REQ請求,KDC使用krbtgt hash進(jìn)行解密
如果結(jié)果正確,就返回用服務(wù)hash 加密的TGS票據(jù)(這一步不管用戶有沒有訪問服務(wù)的權(quán)限,只要TGT正確,就返回TGS票據(jù),這也是kerberoating能利用的原因
任何一個用戶,只要hash正確
可以請求域內(nèi)任何一個服務(wù)的TGS票據(jù),具體內(nèi)容可以參考windows內(nèi)網(wǎng)協(xié)議學(xué)習(xí)Kerberos篇之TGSREQ& TGSREP)
3.用戶拿著TGS票據(jù)去請求服務(wù),服務(wù)使用自己的hash解密TGS票據(jù)。
如果解密正確,就拿著PAC去KDC那邊詢問用戶有沒有訪問權(quán)限,域控解密PAC。
獲取用戶的sid,以及所在的組,再判斷用戶是否有訪問服務(wù)的權(quán)限,有訪問權(quán)限(有些服務(wù)并沒有驗(yàn)證PAC這一步
這也是白銀票據(jù)能成功的前提,因?yàn)榫退銚碛杏脩鬶ash,可以制作TGS,也不能制作PAC,PAC當(dāng)然也驗(yàn)證不成功,但是有些服務(wù)不去驗(yàn)證PAC,這是白銀票據(jù)成功的前提)就允許用戶訪問。
特別說明的是,PAC對于用戶和服務(wù)全程都是不可見的。只有KDC能制作和查看PAC。
二.PAC結(jié)構(gòu)
PAC的結(jié)構(gòu)如下圖所示。

PAC整體的結(jié)構(gòu)上是一個AuthorizationData的結(jié)構(gòu)
AuthorizationData ::= SEQUENCE OF SEQUENCE {ad-type [0] Int32,ad-data [1] OCTET STRING}
AuthorizationData結(jié)構(gòu)的ad-type主要有以下幾個
AD-IF-RELEVANT 1AD-INTENDED-FOR-SERVER 2AD-INTENDED-FOR-AppLICATION-CLASS 3AD-KDC-ISSUED 4AD-AND-OR 5AD-MANDATORY-TICKET-EXTENSIONS 6AD-IN-TICKET-EXTENSIONS 7AD-MANDATORY-FOR-KDC 8Reserved values 9-63OSF-DCE 64SESAME 65AD-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結(jié)構(gòu)。
這個AuthorizationData的ad-type 為AD-WIN2K-PAC,ad-data為一段連續(xù)的空間,
這段空間包含一個頭部PACTYPE以及若干個PAC_INFO_BUFFER
頭部PACTYPE包括cBuffers,版本以及緩沖區(qū),PAC_INFO_BUFFER為key-value型的
key 的類型如下表所示


下面詳細(xì)介紹四個比較重要的
0x00000001 KERBVALIDATIONINFO
這個結(jié)構(gòu)是登錄信息,也是整個PAC最重要的部分,整個PAC就靠它來驗(yàn)證用戶身份了,是個結(jié)構(gòu)體,如下
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; //用戶的sidULONG PrimaryGroupId;ULONG GroupCount;[size_is(GroupCount)] PGROUP_MEMBERSHIP GroupIds;//用戶所在的組,如果我們可以篡改的這個的話,添加一個500(域管組),那用戶就是域管了。在ms14068 PAC簽名被繞過,用戶可以自己制作PAC的情況底下,pykek就是靠向這個地方寫進(jìn)域管組,成為使得改用戶變成域管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 PACCLIENTINFO
客戶端Id(8個字節(jié)):
- 包含在Kerberos初始TGT的authtime
NameLength(2字節(jié))
- 用于指定Name 字段的長度(以字節(jié)為單位)。
Name
- 包含客戶帳戶名的16位Unicode字符數(shù)組,格式為低端字節(jié)序。
0x00000006和0x00000007
0x00000006 對應(yīng)的是服務(wù)檢驗(yàn)和,0x00000007 對應(yīng)的是KDC校驗(yàn)和。分別由server密碼和KDC密碼加密,是為了防止PAC內(nèi)容被篡改。
存在簽名的原因有兩個:
首先,存在帶有服務(wù)器密鑰的簽名,以防止客戶端生成自己的PAC并將其作為加密授權(quán)數(shù)據(jù)發(fā)送到KDC,以包含在票證中。
其次,提供具有KDC密鑰的簽名,以防止不受信任的服務(wù)偽造帶有無效PAC的票證。
兩個都是PACSIGNATUREDATA結(jié)構(gòu),他包括以下結(jié)構(gòu)。
- SignatureType(4個字節(jié))
類型含義簽名長度0xFFFFFF76KERBCHECKSUMHmac_MD5160x0000000FHMACSHA196_AES128120x00000010HMACSHA196_AES25612
- Signature
包含校驗(yàn)和。簽名的長度由SignatureType字段的值確定
- RODCIdentifier(2個字節(jié)):
當(dāng)KDC為RODC時,包含密鑰版本號的前16位。
當(dāng)KDC不是RODC時,此字段不存在。
三.相關(guān)安全問題
1. MS14068
補(bǔ)丁編號是KB3011780,域里面最嚴(yán)重的漏洞之一,它允許任意用戶提升到域管權(quán)限。下面簡要分析下該漏洞。
該漏洞最本質(zhì)的地方在于Microsoft Windows Kerberos KDC無法正確檢查Kerberos票證請求隨附的特權(quán)屬性證書(PAC)中的有效簽名,這里面的簽名就是上面提到的服務(wù)檢驗(yàn)和以及KDC校驗(yàn)和。
導(dǎo)致用戶可以自己構(gòu)造一張PAC。
簽名原本的設(shè)計是要用到HMAC系列的checksum算法,也就是必須要有key的參與,我們沒有krbtgt的hash以及服務(wù)的hash,就沒有辦法生成有效的簽名,但是問題就出在,實(shí)現(xiàn)的時候允許所有的checksum算法都可以,包括MD5。
那我們只需要把PAC 進(jìn)行md5,就生成新的校驗(yàn)和。
這也就意味著我們可以隨意更改PAC的內(nèi)容,完了之后再用md5 給他生成一個服務(wù)檢驗(yàn)和以及KDC校驗(yàn)和。
在MS14-068修補(bǔ)程序之后,Microsoft添加了一個附加的驗(yàn)證步驟,以確保校驗(yàn)和類型為KRBCHECKSUMHMAC_MD5。
在KERBVALIDATIONINFO結(jié)構(gòu)里面,我們看到有這兩個字段。

其中GroupId是用戶所在所在的組,那只要我們把重要組(比如域管組)的sid加進(jìn)GroupId。
那么服務(wù)拿這用戶的TGS去詢問域管用戶是否有訪問訪問改服務(wù)的權(quán)限的時候,域控會解密PAC,提取里面用戶的sid,以及所在的組(GroupId),我們已經(jīng)把域管加進(jìn)去了,是的域控把把這個用戶當(dāng)做域管組里面的成員。
從而達(dá)到提升為域管的效果。
pykek加入的是以下組,
- 域用戶(513)
- 域管理員(512)
- 架構(gòu)管理員(518)
- 企業(yè)管理員(519)
- 組策略創(chuàng)建者所有者(520)
現(xiàn)在我們已經(jīng)能夠偽造pac,將我們放在域管的組里,然后偽造檢驗(yàn)和。但是即使用戶可以偽造PAC。
該漏洞的利用依舊還有一個棘手的問題。
前面我們說過
PAC是包含在TGT里面的,而TGT是krbtgt的用戶hash加密的,也就意味著即使我們可以偽造PAC,那我們有什么辦法講PAC放在票據(jù)里面?zhèn)鬏斀oKDC呢。
漏洞的作者用了一個很巧妙的方式!
通過查看pykek的源碼發(fā)現(xiàn), 作者將PAC加密成密文放在enc-authorization-data里面,enc-authorization-data的結(jié)構(gòu)如下
AuthorizationData::= SEQUENCE OF SEQUENCE {ad-type[0] Int32,ad-data[1] OCTET STRING}
ad-type是加密算法 ad-data是pac加密后的內(nèi)容 加密用的key是客戶端生成的。
KDC并不知道這個key
KDC會從PA-DATA里面的APREQ獲取到這個key
從而對ad-data進(jìn)行解密,然后拿到PAC,再檢查校驗(yàn)和。
可能很多人抓包,在APREQ里面并沒有找到這個key。

只是說了TGT票據(jù)就放在這個結(jié)構(gòu)體里面
這里補(bǔ)充介紹下:
APREQ的type是PADATATYPE.AP_REQ(INTEGER 1)

value是如下結(jié)構(gòu)體
AP-REQ ::= [APPLICATION 14] SEQUENCE {pvno [0] INTEGER (5),msg-type [1] INTEGER (14),ap-options [2] APOptions,ticket [3] Ticket,authenticator [4] EncryptedData -- Authenticator}
之前說的TGT票據(jù)放在這個結(jié)構(gòu)體里面,就是放在ticket里面。
authenticator 的內(nèi)容包括加密類型和用session_key加密Authenticator加密成的密文。
Authenticator的結(jié)構(gòu)如下
Authenticator ::= [APPLICATION 2] SEQUENCE {authenticator-vno [0] INTEGER (5),crealm [1] Realm,cname [2] PrincipalName,cksum [3] Checksum OPTIONAL,cusec [4] Microseconds,ctime [5] KerberosTime,subkey [6] EncryptionKey OPTIONAL,seq-number [7] UInt32 OPTIONAL,authorization-data [8] AuthorizationData OPTIONAL}
其中加密PAC的密鑰就放在subkey里面。
大體流程就是KDC拿到APREQ之后,提取里面authenticator的密文,用sessionkey解密獲得subkey,再使用subkey解密enc-authorization-data獲得PAC.而PAC是我們自己偽造的.
所以最后梳理一下MS14068漏洞利用思路。
1.發(fā)起一個 PAPACREQUEST里面選擇include_pac 為false。此時生成的TGT票據(jù)是不含有PAC的

2.偽造一個PAC
sid為當(dāng)前用戶的sid.將如下組的 sid加進(jìn)GroupId
- 域用戶(513)
- 域管理員(512)
- 架構(gòu)管理員(518)
- 企業(yè)管理員(519)
- 組策略創(chuàng)建者所有者(520)
后續(xù)kerberos測試工具會加入制作PAC的功能,現(xiàn)在暫時不支持,我們直接利用pykek的代碼來生成下,跟ms14068.py的同一文件夾底下,新建makepac.py,代碼如下
from kek.pac import build_pacfrom kek.util import gt2epochfrom kek.krb5 import AD_WIN2K_PAC,AuthorizationData,AD_IF_RELEVANTfrom pyasn1.codec.der.encoder import encodeif __name__ == '__main__':user_realm = "0day.org" #改成自己的user_name = "jack" #改成自己的user_sid = "S-1-5-21-1812960810-2335050734-3517558805-1133" #改成自己的# logon_time = gt2epoch(str(as_rep_enc['authtime']))logon_time = gt2epoch('20191112101422Z')print(logon_time)authorization_data = (AD_WIN2K_PAC, build_pac(user_realm, user_name, user_sid, logon_time))ad1 = AuthorizationData()ad1[0] = Nonead1[0]['ad-type'] = authorization_data[0]ad1[0]['ad-data'] = authorization_data[1]ad = AuthorizationData()ad[0] = Nonead[0]['ad-type'] = AD_IF_RELEVANTad[0]['ad-data'] = encode(ad1)data = encode(ad)with open("jack.pac","wb") as f:f.write(data)
注意這里的logontime來自于第一步中生成的ASREP的enc_part解密后的的authtime,在工具里面右鍵復(fù)制就行

3.發(fā)起一次服務(wù)用戶是krbtgt的TGSREQ,此時導(dǎo)入的TGT里面是不含有PAC的(在第一步里面選擇include=False返回的TGT不含有pac),然后將我們偽造的PAC是加密放在 enc-authorization-data里面。
加密用的key的放在PA-DATA里面的APREQ。
此時返回的TGS里面就含有我們偽造的PAC。
在之前的文章里面我們說過,在TGS里面,如果請求的服務(wù)是krbtgt的話,那么返回的TGS票據(jù)是可以當(dāng)做TGT的。
在我們的kerbreos測試工具里面,只需要導(dǎo)入上面makepac.py生成的pac文件。

4.Pass the ticket

這里面使用kerberos 測試工具只是為了理清楚漏洞流程。更為方便的利用請見底下。
四.部分相關(guān)的工具
kekeo

impacket
- goldenPac.py
這個工具是結(jié)合ms14-068加psexec

msf
- ms14068kerberos_checksum
msf的這個模塊也支持14068攻擊利用

pykek
全稱是Python Kerberos Exploitation Kit
應(yīng)該是ms14068漏洞利用,使用的最廣泛的一個,一般常用的ms14068.exe,就是由他打包而成的

先獲取sid

拼接成S-1-5-21-866784659-4049716574-3063611777-1104
生成tgt

驗(yàn)證tgt是否具備域管權(quán)限

作者:daiker-360RedTeam 轉(zhuǎn)載自:https://www.anquanke.com/post/id/192810