![](https://habrastorage.org/getpro/habr/upload_files/103/d13/13f/103d1313f3a4b135594bdf445fe990fe.png)
Самостоятельное распространение программ‑вымогателей в локальной сети в качестве сетевого червя давно уже не является чем‑то уникальным и новым. Программа‑вымогатель WannaCry в 2017 году распространялась в локальной сети, используя уязвимость SMBv1 MS17–010. Для этого создатели WannaCry использовали эксплойт EternalBlue и бэкдор DoublePulsar из публикации хакерской группировки The Shadow Brokers «Lost in Translation». Но стоит отметить, это всё же немного другая история, отличная от современных RaaS.
В настоящее время уязвимости такого плана и масштаба в арсенале вымогателей появляются не часто, но всегда есть возможность распространения с помощью доступных легитимных механизмов. Для реализации таких способов необходимо наличие корректных учетных данных, которые партнеры RaaS в большинстве случаев и так похищают на этапе постэксплуатации. Программы‑вымогатели LockBit используют групповые политики для своего распространения в локальной сети, а в образцах BlackCat (APLHV) для самораспространения используется содержащаяся в них в зашифрованном и сжатом виде утилита Sysinternals PsExec.
По‑видимому, авторы LockBit для совершенствования своего продукта, а также чтобы не отставать от конкурента, добавили опцию распространения “psexec_netspread”. Но сразу оговоримся, сама утилита PsExec в данном случае не применяется. Интересное мнение о неработоспособности данной функции высказали коллеги. Давайте разберемся в новом механизме распространения в локальной сети, реализованном в LockBit 3.0.
В сентябре 2022 года в публичный доступ «утек» билдер LockBit 3.0, используемый RaaS LockBit. Конечно, эта утечка неплохо помогла ресерчерам в их исследовании LockBit 3.0, но при этом и нельзя умолчать о громадном вреде, которые несут такие общедоступные публикации. По сути, это «оружие», которое получают все без разбора киберхулиганы и хактивисты различной политической окраски. Для атак на российские компании были использованы программы‑вымогатели, созданные в том числе и с помощью данного билдера.
Для анализа сэмплов LockBit 3.0 использовались разработанные скрипты, позволяющие значительно облегчить их анализ. Также среди этих скриптов вы можете найти и реализацию криптографических алгоритмов шифрования файлов в LockBit на Python.
![Рис. 1. Фрагмент конфигурации LockBit 3.0 в формате JSON из утекшего в публичный доступ билдера Рис. 1. Фрагмент конфигурации LockBit 3.0 в формате JSON из утекшего в публичный доступ билдера](https://habrastorage.org/getpro/habr/upload_files/26f/b77/14c/26fb7714cfcb1750b38743f15536f5b3.png)
Этап 1. Проверка указанных учетных данных
Распространение в локальной сети осуществляется при включенной в конфигурации LockBit опции «psexec_netspread» при запуске программы‑вымогателя в режиме полного шифрования системы или шифрования в безопасном режиме (safe mode). Но при этом, как видим (рис. 2), для самораспространения необходим еще и некоторый токен пользователя (g_hUserToken
).
![Рис. 2. Фрагмент функции полного шифрования системы EncryptEverything Рис. 2. Фрагмент функции полного шифрования системы EncryptEverything](https://habrastorage.org/getpro/habr/upload_files/d99/dd5/0f2/d99dd50f210185e7b215d9ae4b6e0308.png)
Токен пользователя (g_hUserToken
) программа‑вымогатель получает ранее в функции, которую мы назвали Prepare
, при этом, разумеется, для этого должна быть включена опция конфигурации имперсонификации “impersonation” (рис. 3), а также указаны корректные администраторские учетные данные в поле “impers_accounts”.
![Рис. 3. Имперсонификация. Фрагмент функции Prepare Рис. 3. Имперсонификация. Фрагмент функции Prepare](https://habrastorage.org/getpro/habr/upload_files/0c0/257/41a/0c025741abf867d91c18118c388a07d9.png)
В функции LogonAccounts
(рис. 4) определяется имя домена, а далее осуществляется последовательный перебор учетных записей, указанных в поле конфигурации “impers_accounts” и попытка аутентификации для каждой записи с помощью функции API LogonUserW
. В случае успешной аутентификации перебор учетных записей прекращается, из функции возвращается токен пользователя, а использованные для входа имя домена, имя пользователя и пароль шифруются и сохраняются в глобальные переменные g_pEncDomain
, g_pEncUser
и g_pEncPassword
соответственно. Впоследствии эти данные, как это показано на рис. 2, используются в качестве параметров функции RunNetSpread
.
Функции с именами IsRunningAsSvc
и RunAsSvc
рассмотрим позже, они будут использоваться на последнем этапе.
![Рис. 4. Фрагмент функции LogonAccounts Рис. 4. Фрагмент функции LogonAccounts](https://habrastorage.org/getpro/habr/upload_files/011/f99/2dd/011f992dd61aef04c9b494cac8acd7d8.png)
Для взаимодействия между процессами LockBit в функции RunNetSpread
создается канал IPC (Inter‑Process Communication) в виде именованного пайпа (PIPE1
) (рис. 5)
\\.\pipe\<PIPE1_NAME>
где PIPE1_NAME
— UUID‑подобная строка {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}
, полученная с помощью хеша MD5 от Unicode‑строки <DECRYPTION_ID>_IPC$
, где DECRYPTION_ID
— строка с первыми 8 байтами в шестнадцатеричном представлении модуля (n) публичного ключа RSA‑1024.
Пример:
DECRYPTION_ID: 4D30CBF764117970
PIPE1_NAME: {1B7F1036-41FE-3F89-169A-86DB06D0C609}
![Рис. 5. Фрагмент функции RunNetSpread Рис. 5. Фрагмент функции RunNetSpread](https://habrastorage.org/getpro/habr/upload_files/fd1/895/590/fd1895590c27dac3843b74788d83f452.png)
Далее программа‑вымогатель запускает себя в контексте безопасности учетной записи, полученной в LogonAccounts
, при запуске также добавляет параметр командной строки "‑psex". Если текущая учетная запись — LocalSystem, для запуска нового процесса программы используется функция API CreateProcessAsUserW(g_hUserToken, …)
, в ином случае — CreateProcessWithLogonW
с именем пользователя, именем домена и паролем, расшифрованных из g_pEncDomain
, g_pEncUser
, g_pEncPassword
.
После этого в канал IPC PIPE1
записываются строка с аргументами командной строки, использованными при первоначальном запуске программы‑вымогателя (рис. 6). Затем программа‑вымогатель продолжает обычное функционирование, в том числе и шифрование данных на хосте.
![Рис. 6. Фрагмент функции RunNetSpread Рис. 6. Фрагмент функции RunNetSpread](https://habrastorage.org/getpro/habr/upload_files/2d2/fdf/57e/2d2fdf57e20710508942fdfcc503afeb.png)
Функция RunNetSpread
возвращает дескриптор запущенного процесса, и вызывающая функция ожидает его завершения (рис. 2).
При самораспространении же с помощью групповых политик программа‑вымогатель запускается с параметром “‑gspd”, в остальном же все действия программы‑вымогателя идентичны на данном этапе.
Этап 2. Выполнение программы-вымогателя с аргументом "-psex"
На предыдущем этапе программа-вымогатель была запущена в контексте безопасности учетной записи, указанной в конфигурации, с добавлением аргумента командной строки "‑psex". Проверка аргументов командной строки в LockBit 3.0 осуществляется по контрольным суммам так же, как и в BlackMatter, впрочем, и как многое другое (рис. 7-8).
![Рис. 7. Фрагмент функции Payload Рис. 7. Фрагмент функции Payload](https://habrastorage.org/getpro/habr/upload_files/4df/1e8/28e/4df1e828e54cc710f6a70a310a194255.png)
![Рис. 8. Фрагмент функции Payload Рис. 8. Фрагмент функции Payload](https://habrastorage.org/getpro/habr/upload_files/772/bf7/70d/772bf770d85f2b535524925ecc2ac879.png)
В функции PsexHandler
программа открывает ранее созданный основным процессом LockBit канал IPC \\.\pipe\<PIPE1_NAME>
, из которого получает строку с первоначальными аргументами командной строки, и затем в случае успеха вызывает функцию NetSpread
(рис. 9).
![Рис. 9. Функция PsexHandler Рис. 9. Функция PsexHandler](https://habrastorage.org/getpro/habr/upload_files/0f1/ed2/03f/0f1ed203fa659e64847fdfd4e7f490be.png)
В функции NetSpread
(рис. 10) создается еще один канал IPC PIPE2
(функция CreateAndReadPipe2
)
\\.\pipe\<PIPE2_NAME>
где PIPE2_NAME
– UUID-подобная строка, полученная с помощью хеша MD5 от Unicode-строки в нижнем регистре
\\<COMP_NAME>.<DOMAIN_NAME>\_IPC$
COMP_NAME
– имя компьютера, DOMAIN_NAME
– имя домена.
Стоит отметить, что для приведения строки в нижний регистр в программе используется функция _wcslwr
, которая не учитывает локальных языковых настроек.
Пример:
DOMAIN_NAME: rootdomain.net
COMP_NAME: MYDC1
PIPE2_NAME: {ABCA3D07-9E6B-A1F0-443E-768D0BF31AE5}
COMP_NAME: MYPC1
PIPE2_NAME: {8A2A1C43-2D7E-ACCC-BD0E-98F7911AE5B7}
Дескриптор именованного канала PIPE2
дублируется с помощью NtDuplicateObject
для уже существующего процесса explorer.exe или lsass.exe, в результате чего будет закрыт впоследствии данным процессом.
Программа получает список компьютеров домена (функция GetADCompList
).
![Рис. 10. Начальный фрагмент функции NetSpread Рис. 10. Начальный фрагмент функции NetSpread](https://habrastorage.org/getpro/habr/upload_files/89f/17f/840/89f17f840398d04595d7be0047a5545d.png)
Получение списка компьютеров в GetADCompList
осуществляется двумя способами. Первый способ — перечисление контроллеров домена с помощью функций API DsGetDcOpenW
/ DsGetDcNextW
. Второй способ — перечисление собственно компьютеров Active Directory с помощью запросов LDAP, для перечисления используются функции API ADsOpenObject
, ADsBuildEnumerator
, ADsEnumerateNext
и интерфейсы IADs
, IADsContainer
.
Далее для каждого хоста из указанного списка создается поток (рис. 11), но одновременно может выполняться не более 64 потока. В функцию потока передается имя хоста в виде
\\<COMP_NAME>.<DOMAIN_NAME>\
где COMP_NAME
– имя компьютера, DOMAIN_NAME
– имя домена.
![Рис. 11. Фрагмент функции NetSpread Рис. 11. Фрагмент функции NetSpread](https://habrastorage.org/getpro/habr/upload_files/a5a/3a9/513/a5a3a9513a00a8dda7bd9de327372807.png)
В функции NetConnAddOrCancel
с помощью функции API WNetAddConnection2W
осуществляется подключение к административным сетевым ресурсам компьютера (Admin Shares) ADMIN$
и IPC$
(рис. 12). Подключение к ресурсу IPC$
позволяет осуществлять удаленное взаимодействие между процессами LockBit.
Программа проверяет наличие канала IPC PIPE2 на хосте
\\<COMP_NAME>.<DOMAIN_NAME>\pipe\<PIPE2_NAME>
Если именованный пайп PIPE2
на хосте уже существует, дальнейших действий по распространению для данного компьютера не осуществляется.
Имя PIPE2_NAME
используется также в качестве имени службы, создаваемой удаленно на компьютере, и имени копируемого на этот компьютер файла.
![Рис. 12. Фрагмент функции потока CompSpreadThreadProc Рис. 12. Фрагмент функции потока CompSpreadThreadProc](https://habrastorage.org/getpro/habr/upload_files/426/925/8b7/4269258b76a86d03764de5610fee6760.png)
Программа-вымогатель создает на другом компьютере каталог
\\<COMP_NAME>.<DOMAIN_NAME>\ADMIN$\Temp
и копирует в него свой исполняемый файл под именем <PIPE2_NAME>.exe
(рис. 13).
![Рис. 13. Фрагмент функции потока CompSpreadThreadProc Рис. 13. Фрагмент функции потока CompSpreadThreadProc](https://habrastorage.org/getpro/habr/upload_files/f16/7e8/180/f167e8180bd9811c1f7d5d5458113a7c.png)
На компьютере удаленно создается и запускается служба с именем PIPE2_NAME
, для которой используется скопированный на компьютер исполняемый файл программы-вымогателя со следующими аргументами командной строки (рис. 14):
%%SystemRoot%%\Temp\<PIPE2_NAME>.exe -k LocalServiceNetworkRestricted
![Рис. 14. Фрагмент функции потока CompSpreadThreadProc Рис. 14. Фрагмент функции потока CompSpreadThreadProc](https://habrastorage.org/getpro/habr/upload_files/b34/254/753/b342547531bac266c9fdee6af6bc03a2.png)
После успешного запуска в канал IPC PIPE2
записываются ранее полученные через канал IPC PIPE1
данные – строка с первоначальными аргументами командной строки. Далее служба удаляется и происходит отключение от административных сетевых ресурсов компьютера (Admin Shares) ADMIN$
и IPC$
(рис. 15).
![Рис. 15. Фрагмент функции потока NetConnAddThreadProc Рис. 15. Фрагмент функции потока NetConnAddThreadProc](https://habrastorage.org/getpro/habr/upload_files/052/4a9/653/0524a965307f0d23c1c99cf5fadcb021.png)
Этап 3. Выполнение службы на компьютере
Ранее на 1 этапе мы упоминали функции с именами IsRunningAsSvc
и RunAsSvc
, которые вызывались в Prepare
(рис. 3). В функции IsRunningAsSvc
осуществляется проверка наличия аргумента командной строки "LocalServiceNetworkRestricted" с помощью контрольной суммы строки (рис. 16). Эта проверка осуществляется заранее, до проверки аргументов в функции Payload
(рис. 7).
![Рис. 16. Фрагмент функции IsRunningAsSvc Рис. 16. Фрагмент функции IsRunningAsSvc](https://habrastorage.org/getpro/habr/upload_files/b4f/094/d4e/b4f094d4e54ae11aeafd6df20da399d9.png)
Таким образом, если программа-вымогатель запущена с аргументом командной строки "LocalServiceNetworkRestricted", запускается функция RunAsSvc
, которая осуществляет запуск программы как системной службы (рис. 17).
![Рис. 17. Фрагмент функции RunAsSvc Рис. 17. Фрагмент функции RunAsSvc](https://habrastorage.org/getpro/habr/upload_files/6b0/6e7/b38/6b06e7b38d14460512792bac209f95e2.png)
В функции SvcMain
программа создает IPC канал с именем PIPE2_NAME
и читает из него данные в буфер (рис. 18). После этого служба завершает свою работу.
![Рис. 18. Функция SvcMain Рис. 18. Функция SvcMain](https://habrastorage.org/getpro/habr/upload_files/52e/225/9e4/52e2259e4acb5c443e7df6844ee6b8b1.png)
Далее после завершения службы выполняется следующий за StartServiceCtrlDispatcherW
код, а именно запускается функция RunMe
, которой в качестве параметра передаются данные, полученные из IPC канала PIPE2
. Функция RunMe
запускает исполняемый файл программы-вымогателя с аргументами командной строки, переданными первоначально программе на 1-м этапе. RunMe
определяет идентификатор сеанса физической консоли (GetActiveConsoleSessionID
) и устанавливает его для токена текущего процесса (процесса службы) (NtSetInformationToken
) и запускает процесс шифрования компьютера в контексте безопасности текущего процесса (CreateProcessAsUserW
).
Таким образом, запуск программы-вымогателя на одном из компьютеров домена при наличии корректных учетных данных администратора домена в конфигурационных данных программы-вымогателя приводит к шифрованию компьютеров (рис. 19) и контроллера домена (рис. 20).
![Рис. 19. Выполнение программы-вымогателя на компьютере домена MYPC1 Рис. 19. Выполнение программы-вымогателя на компьютере домена MYPC1](https://habrastorage.org/getpro/habr/upload_files/02b/ab5/f68/02bab5f68085ccc4a1c1b1545b15cf33.png)
![Рис. 20. Выполнение программы-вымогателя на контроллере домена MYDC1 Рис. 20. Выполнение программы-вымогателя на контроллере домена MYDC1](https://habrastorage.org/getpro/habr/upload_files/ccf/afa/c8d/ccfafac8d83d3bddb8931b5c18edaa55.png)
Как видим, все работает...