Идём по киберследу: Анализ защищенности Active Directory c помощью утилиты BloodHound — страница 20 из 46

'LocalUser') {

if (type === 'Computer') {

if (!name.includes('.') || name.split('.').length < 3) {

setError(

'Computer name must be similar to COMPUTER.

DOMAIN.COM'

);

return;

}

} else {

if (!name.includes('@') || name.split('@'). length > 2) {

setError('Name must be similar to NAME@DOMAIN.COM');

return;

}

let dpart = name.split('@')[1];

if (!dpart.includes('.')) {

setError('Name must be similar to NAME@DOMAIN.COM');

return;

}

}

}

Сохраняем измененный файл и собираем приложение.

npm run build: win32

Запускаем новую версию BloodHound и в Raw Query выполняем запрос Cypher.

MATCH (l: LocalUser) RETURN l


Рис. 4.14. Результат добавления новой метки


Проверим добавление нового узла через форму BloodHound. Правой клавишей вызовем контекстное меню и выберем Add Node.


Рис. 4.15. Добавление локальной учетной записи через форму


Повторно выполним запрос в Raw Query.

MATCH (l: LocalUser) RETURN l


Рис. 4.16. Результат добавления локальной учетной записи


Автоматическая проверка локальной учетной записи

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


Настройка лаборатории

Подготовим лабораторию:

● Включим локальную учетную запись

Administrator
на всех доступных хостах и установим для нее пароль Qwerty321.

● Создадим локальную учетную запись

Test
с паролем Qwerty123 и добавим ее в группу локальных администраторов на любом хосте.

● Удалим из базы все узлы с меткой

LocalUser

MATCH (l: LocalUser) DELETE l


Сбор информации

Разработаем скрипт на Powershell и назовем его

CheckLocalAdmin.ps1
. Алгоритм работы скрипта будет следующим:

● Получить из параметров имя пользователя и пароль.

● Создать запрос Cypher на создание узла локального пользователя.

● Получить из домена все незаблокированные компьютеры, имеющие атрибут

dnshostname
.

● В качестве проверки пары логин-пароль используется подключение сетевого диска

c$
.

● На основании результатов подключения формируется запрос на создание связи AdminTo между узлами.

function Check-LocalAdmin{

[CmdletBinding()]

Param (

[Parameter (Mandatory=$false, Position=0)]

[string]

$User,

[Parameter (Mandatory=$false, Position=1)]

[string]

$Password

)

# Создаем файл отчета

[string]$OutFile = "CheckLocalAdmin_$User.log"

# Генерируем guid для локальной учетной записи

$userid = ([guid]::NewGuid()). toString(). toUpper()

# Формируем запрос Cypher для создания нового узла на основании информации,

# полученной ранее. Результат записывается в файл отчета

Add-Content $OutFile "MERGE (l: LocalUser {name: toUpper('$User'), objectid:'$userid', password:'$Password'});"

# С помощью ADSI-запроса получаем все незаблокированные компьютеры,

# которые имеют атрибут dnshostname

$searcher = ([adsisearcher]' (&(objectCategory=computer)(dnshostname=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))')

$searcher.PageSize = 1000

$objects = $searcher.FindAll()

foreach($object in $objects)

{

# Получаем имя компьютера

$computername = $object.Properties.name.Item(0)

# Получаем SID компьютера

$computerid = (New-Object System.Security.Principal.SecurityIdentifier($object.Properties.objectsid.Item(0),0)).Value

# Формируем имя пользователя для аутентификации

$luser = $computername + "\" + $User

# Формируем данные для аутентификации

$cred = New-Object System.Management.Automation.PSCredential $luser, ($Password | ConvertTo-SecureString -AsPlainText -Force)

# Выполняем проверку учетных данных на компьютере

try

{

# Проверяем, можем ли мы подключить сетевой диск

# с использованием учетных данных, полученных ранее

if (New-PSDrive -Name ForTest -PSProvider FileSystem -Root \\$computername\c$ -Credential $cred -ErrorAction SilentlyContinue)

{

# В случае успеха отключаем сетевой диск

Remove-PSDrive ForTest

# И записываем результат в файл отчета в виде Cypher

Add-Content $OutFile "MATCH (l: LocalUser {objectid:'$userid'}) MATCH(c: Computer {objectid:'$computerid'}) MERGE (l)-[r: AdminTo]->(c);"

}

else

{

# Обрабатываем ошибки при подключении

# В данном случае учетные данные верны, но нет прав

if ($error[0].exception -Match 'Access is denied')

{

# Записываем результаты в файл отчета,

# устанавливая флаг, что это потенциальный администратор

Add-Content $OutFile "MATCH (l: LocalUser {objectid:'$userid'}) MATCH(c: Computer {objectid:'$computerid'}) MERGE (l)-[r: AdminTo]->(c) SET r.ispotential = TRUE;"

}

}

}

catch

{

continue

}

}

}

Внимание

Данный скрипт имеет определенные ограничения, например, сетевой диск

c$
может быть отключен.

Совет

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

Приступим к выполнению проверки. У нас есть две локальные учетные записи,

Administrator
и
Test
. Запустим скрипт дважды с разными учетными данными:

..\CheckLocalAdmin.ps1

Check-LocalAdmin -User Administrator -Password Qwerty321

Check-LocalAdmin -User Test -Password Qwerty123

Стоит обратить внимание, что во втором случае мы получили информацию, что учетная запись

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

Загрузим данные с помощью скрипта для загрузки: