Продолжаем цикл статей «Учим старого псаовым трюкам», посвященных расширению возможностей BloodHound. Это популярный инструмент, который используется для сбора и анализа данных во время проведения пентеста внутренней инфраструктуры на базе Active Directory. BloodHound позволяет визуализировать некорректные настройки объектов Active Directory и строить цепочки атак. Его основная особенность – использование теории графов при анализе данных. В сегодняшнем посте рассмотрим способ представления GPO Client Side Extension в читаемом виде и добавление этой информации в базу BloodHound.
GPO – объект домена, и он обладает атрибутами, которые определяют, что данный GPO будет выполнять. За это отвечают атрибуты gpcuserextensionnames (применение GPO в контексте пользователя) и gpcmachineextensionnames (применение GPO в контексте компьютера). Эти атрибуты представляют собой GUID Client Side Extension (CSE). Сопоставление GUID CSE и функционала можно найти на странице Microsoft. У GPO также есть четкая структура каталогов и наименования файлов. Корневой каталог для GPO определяется атрибутом gpcfilesyspath. Проще говоря, атрибуты gpcuserextensionnames и gpcmachineextensionnames – это инструкции и указатели на определенные файлы, которые будут применяться.
CSE представляет собой набор GUID, а название не всегда дает представление о том, какие инструкции выполняет групповая политика, поэтому возникла идея написать скрипт, который будет преобразовать CSE в читаемый вид и добавлять информацию в базу Neo4j.
Займемся созданием скрипта в PowerShell. Сначала нужно составить hashtable, который будет использоваться для преобразования CSE. Ссылка на перечень выше.
$GpoGuidRef = @{
'00000000-0000-0000-0000-000000000000' = 'Core GPO Engine'
'0E28E245-9368-4853-AD84-6DA3BA35BB75' = 'Preference CSE GUID Environment Variables'
'0F6B957D-509E-11D1-A7CC-0000F87571E3' = 'Tool Extension GUID (Computer Policy Settings)'
'0F6B957E-509E-11D1-A7CC-0000F87571E3' = 'Tool Extension GUID (User Policy Settings) / Restrict Run'
'1612b55c-243c-48dd-a449-ffc097b19776' = 'Preference Tool CSE GUID Data Sources'
...
'0F3F3735-573D-9804-99E4-AB2A69BA5FD4' = 'Advanced Audit Policy Snapin'
}
Результаты будем записывать в файл:
[string]$OutFile = "Result_" + $(Get-Date -f ddMMyyyyhhmmss) + ".log"
Так как атрибуты gpcuserextensionnames и gpcmachineextensionnames представлены в виде [{CSE}{CSE}][{CSE}{CSE}], нужно составить шаблоны регулярных выражений для извлечения данных из квадратных и фигурных скобок:
$extPattern = "(?<=\[)[^]]+(?=\])"
$guidPattern = "(?<=\{).+?(?=\})"
Первый шаблон извлекает информацию из квадратных скобок, а второй – из фигурных.
На следующем шаге нужно выгрузить все групповые политики. Здесь будет использоваться ADSI-запрос, результат которого затем будет обрабатываться.
$DomainObject = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName
$Domain = $DomainObject.name
$ObjectSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$CurrentDomain)
$DirEntry = New-Object System.DirectoryServices.DirectoryEntry
$ObjectSearcher.SearchRoot = $DirEntry
$ObjectSearcher.Filter = "(&(objectClass=groupPolicyContainer))"
$ObjectSearcher.PageSize = 1000
$Objects = $ObjectSearcher.FindAll()
Теперь в цикле нужно извлечь атрибуты gpcuserextensionnames, gpcmachineextensionnames и атрибут objectguid, который будет использоваться как идентификатор для поиска GPO в базе neo4j. По очереди будет выполняться проверка наличия данных в атрибутах. Потом шаблоны регулярных выражений извлекают CSE и преобразуют в читаемый вид. На последних этапах формируются набор преобразованных данных и строка запроса Cypher.
На выходе будет множество запросов MATCH, поэтому используется инструкция CALL {}.
foreach($object in $Objects)
{
$objectGuid = [guid]$Object.Properties.objectguid.Item(0)
if ($Object.Properties.gpcmachineextensionnames -ne $null)
{
$exts = [Regex]::Matches($Object.Properties.gpcmachineextensionnames, $extPattern).Value
$collects = @()
foreach ($ext in $exts)
{
$guids = [Regex]::Matches($ext, $guidPattern).Value
$collects += $GpoGuidRef[$guids] -join ': '
}
$collectionGuid = '"{0}"' -f ($collects -join '","')
Add-Content $OutFile "CALL {MATCH (g:GPO) WHERE g.objectid =~ '(?i)$objectGuid' SET g.machineextname = [$collectionGuid]}"
}
if ($Object.Properties.gpcuserextensionnames -ne $null)
{
$exts = [Regex]::Matches($Object.Properties. gpcuserextensionnames, $extPattern).Value
$collects = @()
foreach ($ext in $exts)
{
$guids = [Regex]::Matches($ext, $guidPattern).Value
$collects += $GpoGuidRef[$guids] -join ': '
}
$collectionGuid = '"{0}"' -f ($collects -join '","')
Add-Content $OutFile "CALL {MATCH (g:GPO) WHERE g.objectid =~ '(?i)$objectGuid' SET g.userextname = [$collectionGuid]}"
}
После запуска скрипта получаем файл с результатами выполнения в виде запросов Cypher.
Полученные данные надо скопировать, вставить в поле запроса в Browser Neo4j и нажать кнопку «выполнить». Теперь, если перейти в BloodHound и выбрать групповую политику, можно увидеть, что в разделе EXTRA PROPERTIES появились новые поля.
На этом сегодня все. А наши предыдущие посты о расширении возможностей BloodHound можно почитать здесь, здесь и здесь. До новых встреч!
Автор: Дмитрий Неверов, руководитель группы анализа защищенности внутренней инфраструктуры, "РТК-Солар"