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

MATCH (c: CA) WHERE c.attributesubjectaltname2 = 'Enabled' with c.dnshostname as name, c as ca

MATCH (m: Computer) WHERE m.name = name RETURN m, ca


Проверка ESC7

Для эксплуатации ESC7 необходимо получить все короткие пути от любых объектов до центра сертификации с перечислением прав, специфичных для центра сертификации. Запрос Cypher получается такой (рис. 4.84):

MATCH p=allshortestpaths((m)-[r: MemberOf|ManageCA|ManageCertificates*1..]->(n: CA)) WHERE m<>n RETURN p


Рис. 4.84. Результат проверки ESC7


Проверка ESC8

Аналогично с ESC6, необходимо проверить наличие у свойства центра сертификации

webenrollement
состояния Enabled.

MATCH (c: CA) WHERE c.webenrollement = 'Enabled' RETURN c

Дальше уже выполняется техника Relay для получения сертификата.

Внимание

Настройки сервера центра сертификации могут запрещать входящий NTLM-трафик, но это уже другие настройки, не относящиеся к текущему проекту.

Проверка ESC9 и ESC10

Эксплуатация будет зависеть от множества факторов, например настроек KDC, которые обычный пользователь не сможет увидеть, если только они не настроены через групповые политики. Второй фактор – это наличие прав на изменение параметров объектов «пользователь», а вот третий фактор мы сможем посмотреть. Для этого найдем все шаблоны сертификатов, у которых установлен флаг

CT_FLAG_NO_SECURITY_EXTENSION,
в нашем случае это свойство
nosecurityextension
. Запрос Cypher будет следующим:

MATCH p=(t: Template)-[r: HostedOn]->(c: CA) WHERE t.nosecurityextension = TRUE RETURN p


Проверка ESC11

Возможность эксплуатации

ESC11
зависит от отсутствия флага
IF_ENFORCEENCRYPTICERTREQUEST.
По умолчанию он всегда присутствует, тем не менее можно проверить. Запрос Cypher будет следующим:

MATCH (c: CA) WHERE c.enforceencrypticertrequest = 'Disabled' RETURN c

Добавление запросов в BloodHound

Скорей всего, результаты по ADCS будут постоянными, поэтому стоит все созданные выше запросы добавить в код BloodHound на постоянной основе. Ранее мы уже рассматривали добавление запроса в Pre-Build Analytics Queries вкладки Analysis, сейчас же мы будем добавлять запросы, связанные с ADCS, разработанные нами ранее.

Откроем на редактирование файл

PrebuildQueries.json
, который находится в директории
src\components\SearchContainer\Tabs\.
Перейдем к блоку
Find Shortest Paths to Domain Admins
и после него добавим следующий код:

{

"name": "ESC1",

"category": "ADCS Paths",

"queryList":[

{

"final":false,

"title": "Select a Domain…",

"query": "MATCH (n: Domain) RETURN n.name ORDER BY n.name DESC"

},

{

"final":true,

"query": "MATCH p=((m)-[r: CanEnroll|MemberOf*1..]->(t: Template {authclient: TRUE, enrolleesuppliessubject: TRUE, pendallrequests: FALSE})-[r1:HostedOn]->(c: CA)) WHERE t.domain = $result RETURN p",

"allowCollapse":true

}

]

},

В этом запросе мы добавили еще один запрос для выбора домена, по которому будет осуществляться поиск.

Для проверки сохраним файл и соберем приложение:

npm run build: win32

Запустим обновленную версию BloodHound, перейдем во вкладку Analysis и выполним добавленный запрос.


Рис. 4.85. Результат выполнения запроса


Если результат нас удовлетворяет, добавим остальные запросы в BloodHound.

Перед ESC1 добавим еще один запрос, отвечающий за отсутствие или наличие глобального подтверждения на выпуск сертификата:

{

"name": "Global Approvement",

"category": "ADCS Paths",

"queryList":[

{

"final":false,

"title": "Select a Domain…",

"query": "MATCH (n: Domain) RETURN n.name ORDER BY n.name DESC"

},

{

"final":true,

"query": "MATCH(c: CA) WHERE ANY (x IN c.requestdisposition WHERE x CONTAINS 'PendingFirst') AND c.domain = $result RETURN c",

"allowCollapse":true

}

]

},

Во всех остальных запросах будут меняться только

name
и второй
query
, поэтому добавим их одним блоком.

{

"name": "ESC2",

"category": "ADCS Paths",

"queryList":[

{

"final":false,

"title": "Select a Domain…",

"query": "MATCH (n: Domain) RETURN n.name ORDER BY n.name DESC"

},

{

"final":true,

"query": "MATCH p=((m)-[r: CanEnroll|MemberOf*1..]->(t: Template {anypurpose: TRUE, pendallrequests: FALSE})-[r1:HostedOn]->(c: CA)) WHERE t.domain = $result RETURN p",

"allowCollapse":true

}

]

},

{

"name": "ESC3",

"category": "ADCS Paths",

"queryList":[

{

"final":false,

"title": "Select a Domain…",

"query": "MATCH (n: Domain) RETURN n.name ORDER BY n.name DESC"

},

{

"final":true,

"query": "MATCH p=(m)-[r: CanEnroll|MemberOf*1..]->(t: Template)-[r1:HostedOn]->(c: CA) WHERE (t.requestagent = TRUE OR (t.enrollmentagent = TRUE AND t.authclient=TRUE)) AND t.domain = $result RETURN p",

"allowCollapse":true

}

]

},

{

"name": "ESC4",

"category": "ADCS Paths",

"queryList":[

{

"final":false,

"title": "Select a Domain…",

"query": "MATCH (n: Domain) RETURN n.name ORDER BY n.name DESC"

},

{

"final":true,

"query": " MATCH p=allshortestpaths((m)-[r: MemberOf|GenericAll|WriteDacl|WriteProperty|WriteOwner|Owns*1..]->(n: Template)) WHERE m<>n and n.domain = $result and NONE (x IN nodes(p) WHERE x.objectid =~ '(?i)S-1–5-.*-512|S-1–5-.*-519 |.*-544 |.*-500 |.*-502 |.*-548') WITH n AS Templates, p as p1 MATCH p2=(Templates)-[r1:HostedOn]->(c: CA) RETURN p1, p2",

"allowCollapse":true

}

]

},

{

"name": "ESC5",

"category": "ADCS Paths",

"queryList":[

{

"final":false,

"title": "Select a Domain…",

"query": "MATCH (n: Domain) RETURN n.name ORDER BY n.name DESC"

},

{

"final":true,

"query": "MATCH(m: CA) WHERE m.domain = $result WITH collect(m.dnshostname) as ca MATCH p=(n)-[r: MemberOf|AdminTo*1..]->(c: Computer) WHERE c.name IN ca RETURN p",

"allowCollapse":true

}

]

},

{

"name": "ESC6",

"category": "ADCS Paths",

"queryList":[

{

"final":false,

"title": "Select a Domain…