Windows内网协议学习Kerberos篇之PAC
轉(zhuǎn)自:https://www.anquanke.com/post/id/192810
author: daiker@360RedTeam
0x00 前言
這是kerbreos篇的最后一篇文章了。這篇文章主要講的內(nèi)容是微軟為了訪問控制而引進(jìn)的一個擴(kuò)展PAC,以及PAC在歷史上出現(xiàn)過的一個嚴(yán)重的,允許普通用戶提升到域管的漏洞MS14068。
?
0x01 PAC 介紹
網(wǎng)上很多版本的kerberos的流程是
上面這個流程看起來沒錯,卻忽略一個最重要的因素,那就是用戶有沒有權(quán)限訪問該服務(wù),在上面的流程里面,只要用戶的hash正確,那么就可以拿到TGT,有了TGT,就可以拿到TGS,有了TGS,就可以訪問服務(wù),任何一個用戶都可以訪問任何服務(wù)。也就是說上面的流程解決了”Who am i?”的問題,并沒有解決 “What can I do?”的問題。
為了解決上面的這個問題,微軟引進(jìn)了PAC,引進(jìn)PAC之后的kerberos流程變成
特別說明的是,PAC對于用戶和服務(wù)全程都是不可見的。只有KDC能制作和查看PAC。
?
0x02 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 ????????????????????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結(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 的類型如下表所示
| 類型 | 意義 |
| 0x00000001 | 登錄信息。PAC結(jié)構(gòu)必須包含一個這種類型的緩沖區(qū)。其他登錄信息緩沖區(qū)必須被忽略。 |
| 0x00000002 | 憑證信息。PAC結(jié)構(gòu)不應(yīng)包含多個此類緩沖區(qū)。第二或后續(xù)憑證信息緩沖區(qū)在接收時必須被忽略。 |
| 0x00000006 | 服務(wù)器校驗(yàn)和。PAC結(jié)構(gòu)必須包含一個這種類型的緩沖區(qū)。其他登錄服務(wù)器校驗(yàn)和緩沖區(qū)必須被忽略。 |
| 0x00000007 | KDC(特權(quán)服務(wù)器)校驗(yàn)和(第2.8節(jié))。PAC結(jié)構(gòu)必須包含一個這種類型的緩沖區(qū)。附加的KDC校驗(yàn)和緩沖區(qū)必須被忽略。 |
| 0x0000000A | 客戶名稱和票證信息。PAC結(jié)構(gòu)必須包含一個這種類型的緩沖區(qū)。附加的客戶和票據(jù)信息緩沖區(qū)必須被忽略。 |
| 0x0000000B | 受約束的委派信息。PAC結(jié)構(gòu)必須包含一個S4U2proxy請求的此類緩沖區(qū),否則不包含。附加的受約束的委托信息緩沖區(qū)必須被忽略。 |
| 0x0000000C | 用戶主體名稱(UPN)和域名系統(tǒng)(DNS)信息。PAC結(jié)構(gòu)不應(yīng)包含多個這種類型的緩沖區(qū)。接收時必須忽略第二個或后續(xù)的UPN和DNS信息緩沖區(qū)。 |
| 0x0000000D | 客戶索取信息。PAC結(jié)構(gòu)不應(yīng)包含多個這種類型的緩沖區(qū)。附加的客戶要求信息緩沖區(qū)必須被忽略。 |
| 0x0000000E | 設(shè)備信息。PAC結(jié)構(gòu)不應(yīng)包含多個這種類型的緩沖區(qū)。附加的設(shè)備信息緩沖區(qū)必須被忽略。 |
| 0x0000000F | 設(shè)備聲明信息。PAC結(jié)構(gòu)不應(yīng)包含多個這種類型的緩沖區(qū)。附加的設(shè)備聲明信息緩沖區(qū)必須被忽略。 |
下面詳細(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; //用戶的sid ULONG 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)。
| 類型 | 含義 | 簽名長度 |
| 0xFFFFFF76 | KERBCHECKSUMHMAC_MD5 | 16 |
| 0x0000000F | HMACSHA196_AES128 | 12 |
| 0x00000010 | HMACSHA196_AES256 | 12 |
包含校驗(yàn)和。簽名的長度由SignatureType字段的值確定
當(dāng)KDC為RODC時,包含密鑰版本號的前16位。當(dāng)KDC不是RODC時,此字段不存在。
?
0x03 相關(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è)計(jì)是要用到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。在上一篇文章里面對于AP_REQ介紹得不多。
只是說了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_pac from kek.util import? gt2epoch from kek.krb5 import AD_WIN2K_PAC,AuthorizationData,AD_IF_RELEVANT from pyasn1.codec.der.encoder import encode if __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] = None ad1[0]['ad-type'] = authorization_data[0] ad1[0]['ad-data'] = authorization_data[1] ad = AuthorizationData() ad[0] = None ad[0]['ad-type'] = AD_IF_RELEVANT ad[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 測試工具只是為了理清楚漏洞流程。更為方便的利用請見底下。
?
0x04 部分相關(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)限
本文由360靈騰安全實(shí)驗(yàn)室原創(chuàng)發(fā)布
轉(zhuǎn)載,請參考轉(zhuǎn)載聲明,注明出處:?https://www.anquanke.com/post/id/192810
安全客 - 有思想的安全新媒體
?
?
總結(jié)
以上是生活随笔為你收集整理的Windows内网协议学习Kerberos篇之PAC的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员吐槽:四年被三家公司裁员补偿,网友
- 下一篇: 好工具推荐系列:Windows系统查看各