..\neo4j_uploaddata.ps1
UploadData -file.\users.txt
Рис. 4.17. Выполнение скриптов
Проверим, что у нас получилось:
MATCH p=(l: LocalUser)-[r: AdminTo]->(c: Computer) RETURN p
Рис. 4.18. Результат выполнения запроса
Если выполнить этот запрос в браузере neo4j и посмотреть на связь между
SERVER
и Test
, то мы обнаружим, что данная связь имеет свойство ispotential
.
Рис. 4.19. Свойство для связи AdminTo
Локальный администратор и групповые политикиУправление локальной учетной записью администратора может выполняться с помощью групповых политик. Можно рассматривать два варианта – изменение пароля администратора и создание новой учетной записи администратора, например с помощью скрипта.
Настройка лаборатории
Для начала подготовим лабораторию. Мы не будем создавать сами политики, просто сделаем условные обозначения:
● Создадим две OU с именами
Test1
и Test2
.● В этих OU создадим по одному объекту «компьютер» с именами
comp1
и comp2
.● Создадим по одной групповой политике для каждой OU. Первую назовем
Set Admin Password
, а вторую Create Local Admin
.● Очистим базу neo4j.
● Запустим SharpHound и загрузим новые данные в BloodHound (рис. 4.20).
Теперь создадим два узла с меткой
LocalUser
. В случае со скриптом мы можем увидеть пароль в открытом виде, но, если используются другие методы установки пароля, он будет неизвестен, хотя может быть обнаружен в других местах.MERGE (:LocalUser {name: "ADMINISTRATOR",
objectid: toUpper(randomUUID()), password: "Qwerty123",
hash: ToUpper("329b074c0058ccf1ba2e4705382963ff")})
MERGE (:LocalUser {name: "LOCALADMIN",
objectid: toUpper(randomUUID()), password: " P@ssw0rd",
hash: ToUpper("e19ccf75ee54e06b06a5907af13cef42")})
Рис. 4.20. Создание групповых политик
Внимание
В домене может быть несколько групповых политик, изменяющих пароль для локальной учетной записи
Administrator
, и пароли могут отличаться друг от друга, поэтому для каждой групповой политики лучше создать свою учетную запись с уникальным свойством objectid
.Создание узлов и связей
Для начала получим свойства
objectid
для локальных пользователей и групповых политик (рис. 4.21).MATCH (m: LocalUser) RETURN m.name, m.objectid
UNION
MATCH (m: GPO) WHERE m.name CONTAINS "ADMIN" RETURN m.name, m.objectid
Внимание
GUID создаются случайным образом за некоторым исключением. Поэтому GUID будут разные, это стоит учитывать при создании запросов.
4.21. Получение objectid узлов
Из названия групповых политик предполагаем, что первая групповая политика устанавливает новый пароль для локальной учетной записи
Administrator
, а вторая создает новую локальную учетную запись и добавляет ее в группу локальных администраторов.Теперь необходимо связать новые узлы с групповыми политиками и указать связь
AdminTo
к компьютерам, для которых применяется групповая политика. Первой будет установка нового пароля.MATCH (g: GPO {objectid:"41A40F36-E64C-4963–9D23-B51F446A5204"})
MATCH (l: LocalUser {objectid:"6160668F-96C4–4247–9095–0C048826320E"})
MERGE (g)-[: SetPassword]-(l)
Проверим, что связь создалась:
MATCH p=((g: GPO {objectid:"41A40F36-E64C-4963–9D23-B51F446A5204"})-[r: SetPassword]->(l: LocalUser)) RETURN p
Рис. 4.22. Результат добавления новой связи
Следующим шагом свяжем узел
LocalUser
с компьютерами, к которым применяется групповая политика:MATCH (g: GPO {objectid:"41A40F36-E64C-4963–9D23-B51F446A5204"})-[: GPLink|Contains*1..]->(c: Computer)
MATCH (l: LocalUser {objectid:"6160668F-96C4–4247–9095–0C048826320E"})
MERGE (l)-[: AdminTo]-(c)
Проверим, что новая связь создалась:
MATCH p=((l: LocalUser)-[r: AdminTo]->(c: Computer)) RETURN p
Рис. 4.23. Результат добавления новой связи
А теперь проверим всю цепочку:
MATCH p=((g: GPO)-[r: SetPassword|AdminTo*1..]->(c: Computer)) RETURN p
Рис. 4.24. Результат проверки всей цепочки
Для второй групповой политики все запросы будут точно такими же, только изменится
objectid
, а связь SetPassword
будет заменена на CreateUser.
MATCH (g: GPO {objectid: "CB7B245F-20FE-44EC-A540-D4D4932EEE35"})
MATCH (l: LocalUser {objectid:"8485A134–70A4–41F7-BCAA-1DF2F4ECC36B"})
MERGE (g)-[: CreateUser]-(l)
Свяжем локальную учетную запись с компьютерами, на которых применяется данная групповая политика:
MATCH (g: GPO {objectid: "CB7B245F-20FE-44EC-A540-D4D4932EEE35"})-[: GPLink|Contains*1..]->(c: Computer)
MATCH (l: LocalUser {objectid:"8485A134–70A4–41F7-BCAA-1DF2F4ECC36B"})
MERGE (l)-[: AdminTo]-(c)
И проверим всю цепочку:
MATCH p=((g: GPO)-[r: CreateUser|AdminTo*1..]->(c: Computer)) RETURN p
Рис. 4.25. Результат проверки всей цепочки
Добавление новых связей в BloodHound
Если выполнить предыдущий запрос в BloodHound через Raw Query, то мы получим аналогичный результат.
Рис. 4.26. Запрос в BloodHound
Однако если попытаться выполнить ту же операцию через поиск путей, то мы получим только то, что групповая политика связана с OU
Test2,
в которой находится компьютер comp2
. Это связано с тем, что запросы в BloodHound выполняются с перечислением всех связей, указанных в файле AppContainer.jsx
в массиве fullEdgeList
.
Рис. 4.27. Запрос через поиск путей
Если связь
AdminTo
существует в BloodHound «из коробки», то связей SetPassword
и CreateUser
нет и нам требуется их добавить.Открываем файл
AppContainer.jsx
, который находится в директории src
, находим строчку fullEdgeList
и добавляем в конец массива наши связи:…
const fullEdgeList = [
…
'DCSync',
'SyncLAPSPassword'
,'SetPassword',
'CreateUser'
];
…
Сохраняем файл и теперь открываем файл
index.js
в том же каталоге, находим строчку global.appStore
и двигаемся до edgeScheme
. Там добавляем:…
global.appStore = {
dagre: true,
…
edgeScheme:{
…
SyncLAPSPassword:'tapered',
DumpSMSAPassword:'tapered'
,SetPassword:'tapered',
CreateUser:'tapered'
},
…
Листаем код до
lowResPalette
и в edgeScheme
добавляем:…
lowResPalette:{
…
edgeScheme:{
…
DumpSMSAPassword:'line'
,SetPassword:'line',
CreateUser:'line'
,},
…
Находим строчку