Настроенные из шаблонов групповые политики записываются в inf-файлы. Эти файлы имеют свою структуру. В этом разделе мы рассмотрим возможность прочитать эти файлы и записать их содержимое в виде связей и свойств узлов.
Настройка лабораторииВ данном разделе будут рассматриваться групповые политики, созданные по умолчанию, поэтому дополнительная настройка не требуется.
Назначение прав пользователя (Rights Assessments)К правам пользователя относятся права на вход и разрешения. Права входа определяют, кто имеет право на вход на устройство и как они могут войти в систему. Разрешения прав пользователя управляют доступом к ресурсам компьютера и домена, а также могут переопределять разрешения, заданные для определенных объектов.
Сбор информации
Простой способ прочитать содержимое файлов
gptTmpl.inf
с помощью powershell: рекурсивно найти все inf-файлы в групповых политиках, отфильтровать файлы по наличию Rights Assessment
, прочитать содержимое файла и записать его в файл (рис. 4.38).Get-ChildItem -Path \\dc\SYSVOL\domain.local\Policies\ -Recurse -ea SilentlyContinue -Include ('*.inf')| Select-String -Pattern "Privilege Rights"|ForEach-Object {$name = $_.Path; $name; Get-Content $name;""}| Out-File Rights.txt
В PowerView1 есть функция
Get-GptTmp
[15], которая разбирает inf-файл, а результаты формирует в hashtable (рис. 4.39)...\PowerView.ps1
(Get-GptTmpl -GptTmplPath "\\dc\SYSVOL\domain.local\Policies\{6AC1786C-016F-11D2–945F-00C04fB984F9}\MACHINE\
Рис. 4.38. Результат поиска в групповых политиках
Рис. 4.39. Поиск информации с помощью PowerView
Microsoft\Windows NT\SecEdit\GptTmpl.inf" -OutputObject).PrivilegeRights
Эту информацию можно добавить в BloodHound. В качестве примера возьмем права
SeMachineAccount
:MATCH(g: GPO) WHERE g.gpcpath CONTAINS "{6AC1786C-016F-11D2–945F-00C04FB984F9}"
MATCH(g)-[: GPLink|Contains*1..]->(c: Computer)
MATCH (n) WHERE n.objectid CONTAINS "S-1–5–11"
MERGE (n)-[r: SeMachineAccount]->(c)
Проверим, что связь создалась корректно, и выполним следующий запрос в Raw Query в BloodHound:
MATCH p=(n)-[r: SeMachineAccount]->(c: Computer) RETURN p
Рис. 4.40. Проверка создания связи
Чтобы автоматизировать этот процесс, создадим скрипт
GetRightsAssessments.ps1
, который будет формировать запросы Cypher с информацией из inf-файла. За основу возьмем функцию PowerView Get-IniContent
, которая разбирает inf-файл.Алгоритм скрипта будет следующим:
● Получить все inf-файлы, в которых есть строка
Privilege Rights
.● С помощью функции
Get-IniContent
разобрать по циклу полученные inf-файлы● Выбрать интересующие права.
● Разобрать
SID
на отдельные записи.● Сформировать строку Cypher, установив свойство
isright=TRUE
для связи.function Get-RigthsAssesment
{
$DomainName = "domain.local"
$DC = "dc"
# Создание файла отчета
[string]$OutFile = "RigthsAssesment_" + $(Get-Date -f ddMMyyyyhhmmss) +".log"
# Поиск во всех inf-файлах строки Privilege Rights
$GPOs = Get-ChildItem -Path \\$DC\SYSVOL\$DomainName\ Policies\ -Recurse -ea SilentlyContinue -Include ('*. inf')| Select-String -Pattern "Privilege Rights"
foreach($GPO in $GPOs)
{
# Получить права и SID из групповой политики
$Rights = (Get-IniContent -filePath $GPO.Path). PrivilegeRights.PSObject.Properties| select name, value
# Получить guid групповой политики
$guid = $GPO.Path.Split('\')[6].ToUpper()
foreach ($Right in $Rights)
{
# Поиск интересующих прав
if ($Right.name -match "SeEnableDelegationPrivile ge|SeMachineAccountPrivilege|SeRestorePrivilege|SeTcb Privilege|SeBackupPrivilege|SeCreateTokenPrivilege|Se CreateGlobalPrivilege|SeDebugPrivilege|SeImpersonateP rivilege|SeLoadDriverPrivilege|SeTakeOwnershipPrivile ge|SeAssignPrimaryTokenPrivilege|SeRemoteInteractiveL ogonRight|SeInteractiveLogonRight")
{
foreach($sid in $Right.value)
{
# Подготовка переменных для строки запроса
$sid = $sid.Replace('*','')
$relation = $Right.name.Replace('Privilege','')
if($sid.Length -le 12)
{
$sid = $DomainName.ToUpper() +"-" + $sid
}
# Создание строки запроса Cypher
Add-Content $OutFile "MATCH(g: GPO) WHERE g.gpcpath CONTAINS '$guid' MATCH(g)-[: GPLink|Contains*1..]->(c: Computer) MATCH (n) WHERE n.objectid CONTAINS '$sid' MERGE (n)-[r:$relation]->(c) SET r.isright = true;"
}
}
}
}
}
# Get-IniContent из PowerView
function Get-IniContent ($filePath)
{
$IniObject = New-Object PSObject
switch -regex -file $FilePath
{
"^\[(.+)\]" # Section
{
$Section = $matches[1].Trim()
$Section = $Section.Replace('', '')
$SectionObject = New-Object PSObject
$IniObject | Add-Member Noteproperty $Section
$SectionObject
$CommentCount = 0
}
"^(;.*)$" # Comment
{
$value = $matches[1].Trim()
$CommentCount = $CommentCount + 1
$name = "Comment" + $CommentCount
$Name = $Name.Replace('', '')
$IniObject.$Section | Add-Member Noteproperty $Name $Value
}
"(.+?)\s*=(.*)" # Key
{
$Name,$Value = $matches[1..2]
$Name = $Name.Trim()
$Values = $Value.split(',') | ForEach-Object {$_. Trim()}
$Name = $Name.Replace('', '')
$IniObject.$Section | Add-Member Noteproperty $Name $Values
}
}
return $IniObject
}
Как вариант, можно использовать общее название связи, например
HasPrivilege
, а название прав определить в качестве свойства связи, например с именем rightname
.Тогда запрос Cypher будет иметь следующий вид:
"MATCH(g: GPO) WHERE g.gpcpath CONTAINS '$guid' MATCH(g)-[: GPLink|Contains*1..]->(c: Computer) MATCH (n) WHERE n.objectid CONTAINS '$sid' MERGE (n)-[r: HasPrivilege]->(c) SET r.isright = true SET r.rightname ='$relation'"
Оба варианта имеют свои преимущества и недостатки. В первом случае наглядно видно, какие привилегии имеет узел, но строка запроса Cypher будет увеличена, если нужно искать множество связей. Второй вариант уменьшает строку запроса, но не дает представления о том, какие права назначены, и придется смотреть в свойства связи, а BloodHound не предоставляет такой возможности.