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…