В корпоративных доменах часто встречаются пароли из словарей — в некоторых случаях это равносильно паролю, написанному на воротах. Смотрите сами.
Администратор правильно настроил политику паролей в домене: минимум 12 символов, три класса символов, история, блокировки. Но проверка показывает, что пароли учётных записей сотрудников есть в публичных дампах и словарях. «Сложные» пароли вроде Zima2025!, P@ssw0rd и Qwerty123! формально соответствуют политике, но злоумышленнику понадобится не так много попыток, чтобы подобрать такие пароли.
Проблема в том, что доменная политика проверяет пароль на соответствие правилам, но ничего не знает про его значение. Она не в курсе, что P@ssw0rd — самый заезженный «сложный» пароль на планете, а пароль из названия компании и года подбирается с трёх попыток.
Почему пароли — всё ещё слабое звено №1
Мы в InfoWatch защищаем данные компаний от утечек, и во многих инцидентах видна закономерность: чаще всего всё начинается не с хитрой уязвимости нулевого дня, а с учётной записи, к которой подобрали пароль или чей пароль утёк из-за переиспользования на публичном сервисе.А что стоит между учётной записью и злоумышленником? В большинстве инфраструктур — всё ещё только пароль: не аппаратный ключ, не биометрия и не второй фактор на каждом сервисе, а строка, которую сотрудник придумал сам и, будем честны, придумал так себе. Можно сколько угодно внедрять MFA, PAM и Zero Trust — пароль в AD остаётся фундаментом, на который всё это опирается. Скомпрометированная доменная учётная запись открывает вход злоумышленнику. В итоге — компрометация всего домена и громкая история: простой производства, отмены рейсов, утечки персональных данных…
И это не абстрактная страшилка, а то, что происходит в реальности. По данным Verizon DBIR за 2025 год, украденные учётные данные — вектор первичного доступа №1: в атаках на веб-приложения они участвуют в 88% случаев, а базовым требованиям сложности отвечали лишь 3% скомпрометированных паролей. IBM Cost of a Data Breach 2024 ставит компрометацию учётных данных на первое место среди причин утечек (16% инцидентов), причём такие взломы дольше всего остаются незамеченными — в среднем 292 дня на обнаружение и локализацию, а средняя цена утечки дошла до 4,9 млн долларов. В России тренд тот же: по данным Positive Technologies, в первой половине 2024 года кража учётных данных фигурировала в 21% успешных атак на организации — на 9 процентных пунктов больше, чем годом ранее.
Сложные алгоритмы и ИИ не дают 100% защиты от скомпрометированного пароля, а зачастую либо ловят аномалию с большим опозданием, либо вовсе не реагируют. Реклама SIEM и поведенческих систем обещает ML-модели и выявление аномалий — но вход с валидным, пусть и украденным, паролем выглядит для них как обычный логин легитимного пользователя, придраться не к чему. Атакующие осваивают всё более изощрённые техники обхода, а базовый приём остаётся прежним: зайти в службу каталогов под настоящим паролем, который оказался не только у владельца. Поэтому пароли разумнее проверять заранее, а не рассчитывать, что аномалию поймают уже по ходу атаки.
Что будем делать
Здесь и появляется аудит паролей: проверяем, что реально стоит у пользователей прямо сейчас. Защита данных начинается с защиты учётных записей — и тут мы можем помочь: показать слабые и утёкшие пароли раньше, чем их найдёт кто-то снаружи.В этой статье я хочу рассказать, как регулярно проверять пароли пользователей. Для этого разверну лабораторный домен на Windows Server 2025, соберу словарь из базы Have I Been Pwned и собственного списка паролей организации, а потом с помощью PowerShell-модуля DSInternals проверю, у кого из пользователей пароль угадывается по словарю, — не зная и не подбирая сам пароль. Начнём с короткой теории (без неё половина метода выглядит магией), дальше — сплошная практика с командами и скриншотами.
Немного теории: почему хеш одного и того же пароля везде одинаковый
Это ключевой момент — именно поэтому метод проверки и работает. Разберёмся, что на самом деле лежит в базе AD.NT-хеш: MD4 без соли
Когда пользователь задаёт пароль, Active Directory не хранит его в открытом виде (если только явно не включена обратимо шифруемая история, но об этом ниже). Хранится NT-хеш (он же NTLM-хеш, он же unicodePwd), который вычисляется предельно просто:
Код:
NT-хеш = MD4( UTF-16LE( пароль ) )
То есть пароль переводится в кодировку UTF-16 Little Endian и один раз прогоняется через MD4. И всё. Здесь нет соли, нет итераций, нет привязки к имени пользователя, домену или машине.
Следствие, которое и делает возможным наш аудит: один и тот же пароль всегда даёт один и тот же NT-хеш — в вашем домене, в соседнем домене и в дампе десятилетней давности. Пароль Qwerty123! превращается в один и тот же NT-хеш 44BF0244F032CA8BAADDDA0FA9328BF8 — ровно эти 32 hex-символа — у кого угодно.
Именно поэтому существуют и радужные таблицы, и база Have I Been Pwned: можно один раз посчитать NT-хеши всех утёкших паролей и потом просто искать совпадения. Нам не нужно знать пароль пользователя — достаточно сравнить его NT-хеш с заранее посчитанным списком. Сравнение хеш-в-хеш, никакого перебора.
LM-хеш: legacy, который иногда всё ещё жив
Исторический предшественник — LM-хеш (LAN Manager). Он ещё хуже: пароль приводится к верхнему регистру, обрезается до 14 символов, режется на два блока по 7 символов и шифруется DES. Из-за этого он ломается за минуты. Начиная с Windows Server 2008 LM-хеши по умолчанию не хранятся, но в доменах с долгой историей и старыми настройками (NoLMHash) они иногда остаются. Аудит стоит того, чтобы это проверить — DSInternals покажет учётные записи, у которых LM-хеш всё ещё присутствует.Kerberos-ключи: а вот здесь соль появляется
Может, тогда выручает Kerberos? Отчасти.- Ключ RC4-HMAC (тип шифрования 23) в Kerberos — это буквально тот же самый NT-хеш. То есть RC4 наследует ту же проблему: ключ без соли, детерминированный, одинаковый везде. Отсюда, кстати, растёт Kerberoasting.
- Ключи AES128/AES256 (типы 17 и 18) считаются иначе — через функцию string-to-key (PBKDF2) с солью. Соль формируется из имени realm (в верхнем регистре) и имени пользователя, например LAB.LOCALj.ivanov. Поэтому AES-ключ разный у разных учётных записей даже при одинаковом пароле, и готовым списком его так просто не проверишь.
Как это лежит внутри ntds.dit
«Но ведь база ntds.dit зашифрована!» — да, но это шифрование хранилища, а не пароля. Внутри NT-хеши дополнительно зашифрованы ключом PEK (Password Encryption Key), а сам PEK зашифрован BootKey (SYSKEY), который хранится в ветке реестра SYSTEM. Это защита данных на диске, а не соль: как только у вас есть права снять реплику или прочитать ntds.dit вместе с BootKey, вы получаете те же самые детерминированные NT-хеши. Ровно это DSInternals и делает за нас — расшифровывает слой хранилища и отдаёт «чистые» NT-хеши для сравнения.Обратимо шифруемые пароли (reversible encryption)
Отдельная находка, которую полезно искать: атрибут «Store password using reversible encryption». Если он включён, пароль хранится не в виде хеша, а шифруется ключом, производным от SYSKEY, — то есть его можно вернуть в открытый вид. DSInternals покажет такие учётные записи со свойством ClearTextPassword. По умолчанию опция выключена, но её иногда включают ради старых протоколов (например, CHAP) и забывают. Это прямой риск.Сравнить с утечками или ломать в лоб?
У аудита паролей есть два принципиально разных пути, и их часто путают.Первый — взлом хешей (offline cracking): выгрузить NT-хеши и натравить на них hashcat со словарями, правилами и масками, восстанавливая пароли в открытом виде. Так можно узнать даже нетривиальный пароль, которого нет ни в одной утечке. Но этот способ достаточно ресурсоёмкий (нужны GPU и время).
Второй — сравнение хешей со словарём и базой утечек, о котором эта статья. Он не восстанавливает пароль, а отвечает на один вопрос: есть ли такой хеш в списке заведомо плохих. Отсюда плюсы — быстро (бинарный поиск, минуты вместо часов), без GPU, и вы не касаетесь открытых паролей. Минус — метод видит только то, что уже попало в словарь или утечку: уникально слабый, но не «засвеченный» пароль он пропустит.
На практике это не «или-или». Сравнение с HIBP и собственным словарём — быстрый первый проход, который снимает основную массу проблем; брутфорс hashcat подключают точечно и по согласованию, когда нужно копать глубже. Здесь мы идём быстрым и безопасным путём — сравнением.
Инструменты
DSInternals — открытый PowerShell-модуль Михаэля Графнеттера (Michael Grafnetter) для низкоуровневой работы с Active Directory. Нас интересуют два командлета:- Get-ADReplAccount — забирает учётные записи вместе с секретами (NT-хеши и прочее) прямо с контроллера домена по сети, штатным механизмом репликации между контроллерами (тот самый DCSync). Онлайн-режим, ничего останавливать не нужно.
- Test-PasswordQuality — берёт выгруженные учётные записи и проверяет их по словарям: сравнивает NT-хеши с базой утёкших, ищет пустые/повторяющиеся/обратимо шифруемые пароли и другие проблемы.
Собственный словарь — то, чего в HIBP по определению нет: пароли, характерные именно для вашей организации.
Разворачиваем стенд
Чтобы никого не подставить, всё проверяем на изолированном стенде. Минимальная конфигурация:- виртуальная машина с Windows Server 2025 в роли контроллера домена (DC01);
- новый лес/домен, например lab.local (NetBIOS LAB);
- несколько тестовых пользователей с заведомо слабыми паролями, чтобы было что находить.
Код:
git clone https://github.com/safebuffer/vulnerable-ADInvoke-VulnAD -UsersLimit 100 -DomainName 'lab.local'
Он создаёт сотню пользователей с предсказуемыми паролями (вроде Changeme123!), прячет пароли в описаниях объектов и настраивает классические огрехи — как раз то, что должен подсветить наш аудит.
Для наглядности примеров ниже я вдобавок завёл несколько именованных учётных записей с говорящими паролями — на контроллере домена, под администратором домена (в рабочей среде так, разумеется, не делают):
Код:
Import-Module ActiveDirectory$pw = @{ 'j.ivanov' = 'Qwerty123!' 'a.petrov' = 'Zima2025!' 'svc_backup' = 'P@ssw0rd' 's.orlova' = 'Infowatch2025' 'd.kuznetsov' = 'Qwerty123!'}foreach ($u in $pw.Keys) { New-ADUser -Name $u -SamAccountName $u -AccountPassword (ConvertTo-SecureString $pw[$u] -AsPlainText -Force) -Enabled $true}
Шаг 1. Ставим DSInternals
Модуль есть в PowerShell Gallery (на старых системах перед установкой включаем TLS 1.2):
Код:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12Install-Module DSInternals -ForceImport-Module DSInternalsGet-Module DSInternals
Установка DSInternals и проверка версии модуля
Если сервер без доступа в интернет — забираем модуль на машине с доступом через Save-Module DSInternals -Path .\ и переносим папку в C:\Program Files\WindowsPowerShell\Modules\.
Шаг 2. Готовим базу Have I Been Pwned (NTLM)
Актуальный официальный способ — утилита-загрузчик haveibeenpwned-downloader (dotnet-тул; нужен .NET SDK, иначе берём готовый бинарник из GitHub Releases проекта). Она скачивает все диапазоны хешей и собирает офлайн-файл без обращения к API в момент проверки, а флаг -n переключает базу с SHA-1 на NTLM:
Код:
dotnet tool install --global haveibeenpwned-downloaderhaveibeenpwned-downloader -n pwnedpasswords_ntlm
На выходе — файл pwnedpasswords_ntlm.txt в формате NT-ХЕШ:счётчик, отсортированный по хешу. Именно такой формат нужен параметру -WeakPasswordHashesSortedFile: по нему DSInternals делает бинарный поиск.
Первые строки базы HIBP: NT-хеш и счётчик встречаемости, сортировка по хешу
Шаг 3. Собираем собственный словарь организации
HIBP ловит то, что уже утекло у всех. Но пароль Infowatch2025 в публичные утечки мог и не попасть, а подбирается за пару попыток. Такие пароли добавляем сами. Что обычно кладут в собственный список:- название компании и продуктов во всех вариантах (InfoWatch, infowatch, iw, TrafficMonitor…);
- город, адрес, индекс, телефонные коды;
- сезоны и месяцы + текущий и прошлый год (Zima2025, Autumn2025, Leto2024);
- «клавиатурные» и вечная классика (Qwerty, Password, Admin, 123456);
- имена внутренних систем, проектов, релизов.
Код:
$base = 'infowatch','company','password','qwerty','admin','zima','leto','vesna','osen'$suffixes = '','1','12','123','!','@','2024','2025','123!','@2025'$words = foreach ($w in $base) { $cap = (Get-Culture).TextInfo.ToTitleCase($w) foreach ($s in $suffixes) { $w + $s $cap + $s ($w -replace 'a','@' -replace 'o','0' -replace 'i','1' -replace 's','$') + $s }}$words | Sort-Object -Unique | Set-Content -Encoding UTF8 .\company-weak.txt
Формат простой: один пароль в строке, в открытом виде. Test-PasswordQuality сам посчитает NT-хеши и сравнит.
Фрагмент собственного словаря: базовые слова и их вариации
Шаг 4. Забираем хеши с контроллера домена (DCSync)
Теперь получаем секреты учётных записей. В онлайн-режиме DSInternals реплицирует их с DC тем же способом, что и штатный контроллер домена:
Код:
$accounts = Get-ADReplAccount -All -Server DC01 -NamingContext 'DC=lab,DC=local'
Выгрузка учётных записей с контроллера домена; в кадре — только количество, сами хеши не выводим
Для этой операции учётной записи нужны права репликации каталога — Replicating Directory Changes и Replicating Directory Changes All на разделе домена. У Domain Admins они есть по умолчанию; в рабочей среде для разового аудита лучше завести отдельную учётную запись, выдать ей ровно эти два права, а после аудита — отозвать.
А если прав репликации не хватает — команда честно об этом скажет:
Ошибка доступа к репликации, когда у учётной записи нет нужных прав
Шаг 5. Запускаем проверку
Передаём выгруженные учётные записи в Test-PasswordQuality, добавив обе базы — утёкшие хеши и наш собственный словарь:
Код:
$report = $accounts | Test-PasswordQuality ` -WeakPasswordHashesSortedFile .\pwnedpasswords_ntlm.txt ` -WeakPasswordsFile .\company-weak.txt ` -IncludeDisabledAccounts$report
-IncludeDisabledAccounts добавит в проверку отключённые учётные записи — их часто забывают, а пароли у них живут годами.
Полный отчёт приходит уже разложенным по типам находок:
Полный отчёт Test-PasswordQuality с разделами по типам находок
Шаг 6. Читаем отчёт
Test-PasswordQuality возвращает объект с готовыми списками. Самое важное:- WeakPassword — учётные записи, чей пароль нашёлся в HIBP или в вашем словаре. Главный результат.
- DuplicatePasswordGroups — группы учётных записей с одинаковым паролем (наши j.ivanov и d.kuznetsov должны оказаться здесь).
- ClearTextPassword — включено обратимое шифрование, пароль хранится восстановимо.
- LMHash — присутствует устаревший LM-хеш.
- PasswordNeverExpires, PasswordNotRequired — организационные слабости учётных записей.
- AESKeysMissing, PreAuthNotRequired (AS-REP roasting), SmartCardUsersWithPassword — дополнительные находки по гигиене.
Код:
"Слабые/утёкшие пароли:"; $report.WeakPassword"Повторяющиеся пароли:"; $report.DuplicatePasswordGroups"Обратимое шифрование:"; $report.ClearTextPassword$report.WeakPassword | ForEach-Object { [pscustomobject]@{ SamAccountName = $_ } } | Export-Csv .\weak-accounts.csv -NoTypeInformation -Encoding UTF8
Учётные записи со слабыми и утёкшими паролями — свойство WeakPassword
Учётные записи с одинаковым паролем — свойство DuplicatePasswordGroups
На нашем стенде в WeakPassword ожидаемо попадают все пятеро: три пароля совпали с базой HIBP, Zima2025! и Infowatch2025 — с нашим словарём. А DuplicatePasswordGroups показывает пару с одинаковым паролем. Метод работает, причём мы ни разу не «подбирали» пароль — только сравнивали хеши.
Только не обольщайтесь: конкретные пароли (Zima2025! и прочие) мы знаем лишь потому, что сами завели их на стенде. В рабочем домене Test-PasswordQuality скажет только, что пароль учётной записи есть в словаре или утечке, но сам пароль не покажет. Исключение — учётные записи с обратимым шифрованием: для них пароль приходит в ClearTextPassword открытым текстом.
Экспорт списка слабых учётных записей в CSV, чтобы передать владельцам систем
Что пойдёт не так (грабли, которые я собрал за вас)
На бумаге всё гладко, но подводных камней хватает. Что стоит предусмотреть заранее:- Нет прав репликации. Get-ADReplAccount упадёт с ошибкой доступа, если у учётной записи нет Replicating Directory Changes (All). Что делать: запускать под учётной записью с этими правами или на DC под администратором; в рабочей среде — выдать права временно и отозвать после.
- Неправильный формат базы HIBP. Файл «ordered by count» не подходит для -WeakPasswordHashesSortedFile. Что делать: берём строго ordered by hash; если пользуетесь новым каталожным форматом HIBP (папка файлов по префиксу хеша), используйте параметр -WeakPasswordHashesSortedFilePath.
- Не хватило места на диске. База NTLM весит десятки гигабайт. Что делать: заранее убедиться, что столько свободного места на диске есть.
- Нагрузка DCSync на большом домене. Репликация десятков тысяч учётных записей нагружает DC и сеть. Что делать: запускать в непиковые часы или уйти в офлайн-режим: снять ntds.dit через ntdsutil (IFM-снапшот) и разобрать Get-ADDBAccount — тогда рабочий DC вообще не трогаем.
- EDR блокирует DSInternals. Инструмент двойного назначения часто в сигнатурах. Что делать: исключение на стенде, согласование с ИБ в рабочей среде.
- Ложное чувство безопасности. DSInternals не перебирает все пароли — он сравнивает со словарём и утечками. Пароль может быть слабым, но отсутствовать в списках. Что делать: расширяем собственный словарь под вашу специфику; аудит дополняет, а не заменяет строгую политику и MFA.
- Сами результаты — чувствительные данные. CSV со списком учётных записей со слабыми паролями — это карта для атакующего. Что делать: храним в защищённом месте, передаём владельцам систем по защищённому каналу, удаляем дампы и переменную $accounts (Remove-Variable accounts) после работы.
Что делать с находками
Найти — половина дела. Дальше:- принудительная смена пароля у всех из WeakPassword (Set-ADUser ... -ChangePasswordAtLogon $true), в первую очередь у привилегированных и сервисных учётных записей;
- разбор DuplicatePasswordGroups — одинаковые пароли часто означают общий «шаблон» при заведении;
- выключить reversible encryption там, где оно всплыло, и разобраться, зачем его включали;
- сделать аудит регулярным — завести Scheduled Task, скажем, раз в месяц, и следить за динамикой.
Если командная строка не по душе
Всё выше — сценарный путь через PowerShell: гибко, бесплатно и воспроизводимо. Но если такие проверки должны идти по расписанию и с отчётами для нетехнических коллег, удобнее графические инструменты. На рынке есть готовые решения, которые делают ту же сверку хешей паролей домена с базой утечек через привычный интерфейс — с наглядными отчётами и постоянным мониторингом. Логика под капотом та же, что мы разобрали руками; меняется только упаковка.Выводы
Парольная политика проверяет пароль на соответствие правилам, но не его значение. А раз NT-хеш вычисляется без соли и всегда одинаков, эту особенность можно повернуть в любую сторону: атакующий сверит ваши хеши с утечками — а вы сделаете то же самое, только первыми. DSInternals превращает теорию в десятиминутную практику: забрали хеши, сравнили со словарём HIBP и собственным списком, получили поимённый список тех, кому пора менять пароль. Без перебора, одним сравнением.И относиться к нему стоит не как к разовому «взлому ради галочки», а как к регулярной гигиене. Слабые пароли копятся тихо, по одному, вместе с новыми учётными записями и «временными» решениями. Найти их самому всегда дешевле, чем прочитать о них в чужом отчёте о компрометации.
Западные врата Мории открывались любому, кто знал одно простое слово, заботливо написанное над входом. Проверьте, не открывается ли ваш домен так же — пока это не проверил кто-то снаружи.
Легальные и этические оговорки
Всё описанное — инструмент двойного назначения. Запускать Get-ADReplAccount и извлекать хеши из чужого домена без письменного разрешения — это неправомерный доступ, а не «аудит». Проверяйте только свою инфраструктуру и только с явной авторизацией (в идеале — с зафиксированным согласованием у владельца системы и ИБ). Хеши, дампы и отчёты — чувствительные данные: защищайте их при хранении и удаляйте после работы.Список литературы и ссылки
Документация Microsoft- Store passwords using reversible encryption — learn.microsoft.com
- Network security: Configure encryption types allowed for Kerberos — learn.microsoft.com
- Detect and remediate RC4 usage in Kerberos (почему RC4-ключ равен NT-хешу и чем это опасно) — learn.microsoft.com
- Спецификации протоколов: [MS-KILE] (расширения Kerberos) и [MS-DRSR] (репликация каталога, лежит в основе DCSync) — Microsoft Open Specifications.
- DSInternals — репозиторий на GitHub, документация Test-PasswordQuality, статья «Auditing AD Password Quality».
- Have I Been Pwned — Pwned Passwords и загрузчик PwnedPasswordsDownloader.
- VulnerableAD — быстрое наполнение стенда уязвимостями: safebuffer/vulnerable-AD.
- RFC 4757 — тип шифрования RC4-HMAC для Kerberos: rfc-editor.org.
- RFC 3961 и RFC 3962 — функция string-to-key и AES для Kerberos: 3961, 3962.
- Auditing Active Directory passwords against HaveIBeenPwned — adainese.it.
- Detecting weak passwords in Active Directory — michaelwaterman.nl.
- Verizon Data Breach Investigations Report (DBIR) 2025 — verizon.com.
- IBM Cost of a Data Breach Report 2024 — ibm.com.
- Positive Technologies, актуальные киберугрозы (первое полугодие 2024) — ptsecurity.com.