Группировка Turla, известная своими давними кибершпионскими операциями, развернула новый многокомпонентный бэкдор под названием STOCKSTAY. Целью стали государственные и военные организации Украины, а также структуры, связанные с итальянской внешней политикой. Специалисты Google Threat Intelligence Group (GTIG) провели детальный анализ этого вредоносного инструмента, который активно развивается с декабря 2022 года. STOCKSTAY демонстрирует значительное совпадение кода и функциональных возможностей с ранее использовавшимся инструментарием KAZUAR, также приписываемым Turla. Эта активность подтверждает, что Turla продолжает наращивать арсенал для проведения целевых атак в условиях текущей геополитической напряженности.
Описание
Turla является одной из старейших известных групп кибершпионажа. Её активность отслеживается как минимум с 2004 года. Группа известна использованием сложных имплантов, таких как Snake, и постоянно совершенствует методы доставки. Среди последних тактик - перехват зашифрованных сообщений Signal с помощью специализированных скриптов и захват унаследованных ботнетов для атак на украинские организации. STOCKSTAY, как показал анализ GTIG, стал очередным инструментом в этой линейке.
STOCKSTAY написан на .NET с использованием Windows Forms и общается с командным сервером (C2) через защищённое WebSocket-соединение. Для этого применяется открытая библиотека websocket-sharp. Архитектура бэкдора состоит из нескольких изолированных компонентов, которые взаимодействуют друг с другом через межпроцессное взаимодействие с помощью сообщений WM_COPYDATA. Такое разделение позволяет скрыть сетевую активность от других вредоносных процессов на инфицированной машине.
Изначально STOCKSTAY маскировался под утилиту просмотра данных фондового рынка. Это отражалось в именах файлов и структуре конфигурации. Однако в 2025 году появились варианты, притворяющиеся программами для просмотра PDF и калькуляторами. Такая маскировка помогает избежать обнаружения.
Ключевыми компонентами являются STOCKSTAY.STOCKBROKER, STOCKSTAY.STOCKMARKET и STOCKSTAY.STOCKTRADER. Первый выполняет роль туннелировщика, обеспечивая сетевое взаимодействие с C2. Второй выступает оркестратором: загружает зашифрованную конфигурацию, генерирует уникальные 4096-битные RSA-ключи для шифрования данных и идентификатор инфекции. Третий, STOCKSTAY.STOCKTRADER, является непосредственным бэкдором, поддерживающим множество команд - от удаления файлов и создания каталогов до снятия скриншотов, извлечения системной информации и выполнения произвольных процессов с тайм-аутом 60 секунд. Кроме того, существует STOCKSTAY.MARKETMAKER - загрузчик, который скачивает и распаковывает основные компоненты, настраивает автозагрузку через реестр, маскируясь под "MicrosoftUpdateOneDrive".
Особый интерес представляет подход к развёртыванию. Turla использует STOCKSTAY на разных этапах операций. На этапе получения начального доступа конфигурация часто защищена простым паролем, который легко извлекается аналитиками. Такой вариант характерен для фишинговых атак, где злоумышленники не знают точных характеристик целевой сети. На поздних этапах, после разведки, применяется привязка к окружению (environmental keying). В этом случае конфигурация расшифровывается только на конкретном хосте, определённым пользователем или в определённом домене. Это указывает на то, что Turla уже имеет доступ к сети жертвы и точно знает, какая машина атакуется.
Схожая техника используется и в инструменте KAZUAR, где хэш имени хоста применяется для дешифровки полезной нагрузки. Дополнительное сходство между STOCKSTAY и KAZUAR проявляется в архитектуре: оба используют разделение на компоненты для управления C2, оркестрации задач и выполнения. В мае 2025 года в STOCKSTAY была внедрена новая система обфускации строк K1MORPHER, основанная на генераторе псевдослучайных чисел Squirrel3. Через месяц аналогичный код появился и в KAZUAR. Эти факты позволяют GTIG с умеренной уверенностью утверждать, что оба инструмента разрабатываются одной командой.
Среди конкретных операций: в январе 2024 года STOCKSTAY был развёрнут в украинской сети одновременно с KAZUAR. После того как защитные системы зафиксировали подозрительную активность, связанную с C2 KAZUAR, STOCKSTAY, вероятно, использовался как резервный канал для повторного заражения. В феврале 2024 года инсталлятор STOCKSTAY был загружен на VirusTotal из Италии. Он маскировался под приложение ILSpy, а фишинговая страница содержала итальянские тексты, связанные с голосованием в "Circolo Degli Esteri" - организации, близкой к Министерству иностранных дел Италии. В марте-апреле 2025 года зафиксирована атака на украинский университет через вредоносные RDP-файлы, после чего загрузчик STOCKSTAY.MARKETMAKER скачивал архив с компонентами с сайта Государственной регуляторной службы Украины. В ноябре 2025 года Turla использовала уязвимость в WinRAR (CVE-2025-8088) для доставки STOCKSTAY через фишинговые письма с темой беспилотников. Жертвами стали около 20 украинских адресатов, а документы-приманки содержали отчёты о БПЛА и списки военного снаряжения.
Использование Turla STOCKSTAY свидетельствует о стремлении группы диверсифицировать инструментарий, сохраняя высокий уровень скрытности. Модульная архитектура, маскировка под легитимные приложения, применение привязки к окружению и шифрования C2-трафика делают обнаружение такого бэкдора сложной задачей. Операторы Turla активно тестируют новые методы доставки, включая фишинг через взломанные образовательные и правительственные ресурсы. Для защиты организаций рекомендуется усилить мониторинг подозрительных WebSocket-соединений, особенно к нестандартным доменам, и блокировать выполнение файлов, маскирующихся под обновления OneDrive или утилиты просмотра данных, если они не подписаны доверенным издателем. Важным является своевременное обновление программного обеспечения, в частности архиваторов, для закрытия известных уязвимостей.
Индикаторы компрометации
WebSocket Secure
- wss://driverx86-adobe.onrender.com/ws
- wss://google-ai-labs-it.onrender.com/ws
SHA256
- 1682e8d82016b3f10434d2ebac995fd3b6aa812f079bfd7888652e94a994d851
- 3627f582420ad2782d452fe6d13fae42658d1484296351d3916703e25dcadd14
- 667a8f568a611f2f3d84a366b7946b360e055bece9699c95aad619637ab72a38
- 77417df21b4b4e8d86b8bda4afeef93fd36f355362586b2d1f51121a82244167
- 813c78b5b6ef28a9c0ed35f2c6cd88fc50880ab91f8777dfe7aaccb1c24b08d5
- a40bf9c75d1bfa6d66f1179f2321de6589f80d3089d992797a9cb0e84f6196ce
- b287347a5bff8af360ce0e6500c336b6fe6d97920abc26202c9d843ffebc5f89
- c905cb512018cc55512c6a22677c3d6f389c47afd54d7c85797868fc4fcb90e9
- e2a0f4440f67998a0215d49be31746ea192bfcb4dc4ee532a218f8cf13605714
- e316b1e13154dc6115e1e0c023f6fe3d17861cae839d4a4a81779b6aad9a24f8
- e83f274bf9914c6cfc0c6b3cdadf089565f49dace4aca93287c22aba9641c8f3
- f964353b9ae4bedbe62de6c0d7eafa9fb8b87897bbaea483aedaa8ae191834da
YARA
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | rule G_Backdoor_STOCKSTAY_ConfigurationFile_2 { meta: author = "Google Threat Intelligence Group" description = "Detects encrypted configuration files associated with STOCKSTAY." hash = "40a3b969d81ef1ef35dd9ebcc6774e060b1b8949d3d74f38ca6b7d789c95cdb3" strings: $s1 = "\"SystemConfiguration\"" $s2 = "An application for getting information about current events on trading platforms" $s3 = "To set the time for updating information, enter a value in minutes in the `Interval` field" $s4 = "The `SystemConfiguration` field stores the system settings of the application." $s5 = "In the `services` field, fill in the list of addresses of services that provide the `WebSocket protocol`." $s6 = "wss://" condition: uint16(0) == 0x227B // {" and 4 of ($s*) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | rule G_Backdoor_STOCKSTAY_ConfigurationFile_3 { meta: author = "Google Threat Intelligence Group" description = "Detects early configuration files associated with STOCKSTAY." hash = "1a2ca8b8e0344fe3d80da7352206a470245443e2349a237bc093df934ddc011f" strings: $key_required_1 = "\"List 1\"" $key_required_2 = "\"List 2\"" $key_required_3 = "\"List 3\"" $key_dummy_1 = "\"BinanceApi\"" $key_dummy_2 = "\"CoinbaseCloudApi\"" $key_dummy_3 = "\"CoinbaseCloudApi Sandbox\"" $key_dummy_4 = "\"ByBitApi Spot\"" $key_dummy_5 = "\"ByBitApi Linear\"" $key_dummy_6 = "\"Info level\"" $key_dummy_7 = "\"Rate info\"" $key_dummy_8 = "\"Info level\"" condition: uint8(0) == 0x7B // { and filesize > 500 and all of ($key_required_*) and 3 of ($key_dummy*) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | rule G_Backdoor_STOCKSTAY_ConfigurationFile_5 { meta: author = "Google Threat Intelligence Group" description = "Detects plaintext configuration files used by the STOCKSTAY malware family." hash = "6cee9e838792ac5e2098362d68ce93a9a2c095d476dc16b289fe8509c99b2b8b" strings: $internal_id_1 = "\"internal_id\"" $internal_id_2 = "\"i_id\"" $internal_key_1 = "\"internal_key\"" $internal_key_2 = "\"i_k\"" $interval_engine_1 = "\"interval_engine\"" $interval_engine_2 = "\"ie\"" $level_info_1 = "\"level_info\"" $level_info_2 = "\"li\"" $time_scale_1 = "\"time_scale\"" $time_scale_2 = "\"ts\"" $span_min_1 = "\"span_min\"" $span_min_2 = "\"mx1\"" $span_max_1 = "\"span_max\"" $span_max_2 = "\"my1\"" $rate_1 = "\"rate\"" $rate_2 = "\"rt_x_y\"" $rate_control_1 = "\"rate_control\"" $service_1 = "\"service\"" $service_2 = "\"srv\"" $days_not_work_1 = "\"days_not_work\"" $days_not_work_2 = "\"dnw\"" $system_properties_1 = "\"system_properties\"" $system_properties_2 = "\"sp\"" condition: any of ($internal_id*) and any of ($internal_key*) and any of ($interval_engine*) and any of ($level_info*) and any of ($time_scale*) and any of ($span_min*) and any of ($span_max*) and any of ($rate*) and any of ($service*) and any of ($days_not_work*) and any of ($system_properties*) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | rule G_Backdoor_STOCKSTAY_CryptoContainer_1 { meta: author = "Google Threat Intelligence Group" description = "Detects code for parsing crypto containers within STOCKSTAY components." hash = "82707cfdf24dcb762f4615f01e1ba4d3dfdec4abe9cd588558d2634d7e6a5eeb" strings: $s1 = "BuildCryptoContainer" $s2 = "ParseCryptoContainer" $s3 = "Windows-1251" wide $s4 = "AesCryptoServiceProvider" $s5 = "RSACryptoServiceProvider" condition: uint16(0) == 0x5a4d and all of them } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | rule G_Backdoor_STOCKSTAY_WindowNames_1 { meta: author = "Google Threat Intelligence Group" description = "Detects STOCKSTAY window names." hash = "dfd5cb91d06b9649d4cab500343af80ad1144a9e46641cc406f43dd169003c22" strings: $import = "_CorExeMain" $s2 = "SMEditorPage" wide $s3 = "SMNetPage" wide $s4 = "StockMarketViewPage" wide $s5 = "window_system32_x128" wide $s6 = "window_system32_x64" wide $s7 = "window_system32_x32" wide condition: $import and any of ($s*) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | rule G_Downloader_STOCKSTAY_MARKETMAKER_1 { meta: author = "Google Threat Intelligence Group" description = "Detects STOCKSTAY.MARKETMAKER downloader based on method names and payload filenames." hash = "da8a96bc74e265f945f1cc6992c6dc0f9ea36ed1991f7b8d312db79d9bf78c40" strings: $f1 = "CheckAutoRun" $f2 = "SetupAutoRun" $f3 = "DownloadAndExtractZip" $f4 = "GetSystemProxy" $s0 = "_CorExeMain" $s1 = "Software\\Microsoft\\Windows\\CurrentVersion\\Run" wide $s2 = "StockMarketView.exe" wide $s3 = "SMNet.exe" wide $s4 = "SMEditor.exe" wide condition: all of them } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | rule G_Controller_STOCKSTAY_STOCKMARKET_1 { meta: author = "Google Threat Intelligence Group" description = "Detects STOCKSTAY.STOCKMARKET controller based on method and field names, and SQL queries" hash = "2af7b513c05e76d7da5f75bb0a223c894a706c99ef2c2ddfe4eae542f95a08e0" strings: $f1 = "ProtocolMessageConnect" $f2 = "ProtocolMessageEnd" $f3 = "ProtocolMessagePing" $f4 = "ProtocolMessageRequestRecv" $f5 = "ProtocolMessageRequestSend" $f6 = "ProtocolMessageTask" $f7 = "ProtocolMessageTaskSysinfo" $f8 = "TMR_AppInit_Tick" $f9 = "TMR_Engine_Tick" $f10 = "TMR_KeepAlive_Tick" $f11 = "TMR_PingNet_Tick" $f12 = "TMR_PingSystem_Tick" $f13 = "GetDataTrade" $f14 = "GetDataNews" $f15 = "InsertDataTrade" $f16 = "InsertDataNews" $sql1 = "CREATE TABLE IF NOT EXISTS News (" wide $sql2 = "CREATE TABLE IF NOT EXISTS Trade (" wide $sql3 = "CREATE TABLE IF NOT EXISTS Market (" wide $sql4 = "INSERT INTO Market ( Guid, Version, Config, Status, Launch, Type ) VALUES (@Guid, @Version, @Config, @Status, @Launch, @Type)" wide $sql5 = "INSERT INTO News (Container) VALUES (@Container)" wide $sql6 = "INSERT INTO Trade (Container) VALUES (@Container)" wide condition: 8 of ($f*) and any of ($sql*) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | rule G_Tunneler_STOCKSTAY_STOCKBROKER_1 { meta: author = "Google Threat Intelligence Group" description = "Detects STOCKSTAY.STOCKBROKER tunneler based on known IPC message handler and variable names." hash = "dfd5cb91d06b9649d4cab500343af80ad1144a9e46641cc406f43dd169003c22" strings: $s1 = "_CorExeMain" $s2 = "ProtocolMessageStatusConnection" $s3 = "ProtocolMessageResult" $s4 = "ProtocolMessageEnd" $s5 = "OnGetDataFromServer" $s6 = "webSocket" $s7 = "wmCopyData" $s8 = "tempStorage" condition: all of them } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | rule G_Backdoor_STOCKSTAY_STOCKTRADER_3 { meta: author = "Google Threat Intelligence Group" description = "Detects STOCKSTAY.STOCKTRADER backdoor based on known command handlers and FNV1a hashes." hash = "82707cfdf24dcb762f4615f01e1ba4d3dfdec4abe9cd588558d2634d7e6a5eeb" strings: $cmd_1 = "AppDel" $cmd_3 = "AppDeleteRegistryValue" $cmd_4 = "AppDir" $cmd_5 = "AppGet" $cmd_6 = "AppMkdir" $cmd_7 = "AppPut" $cmd_8 = "AppReadRegistryValue" $cmd_9 = "AppRegistryKeyExists" $cmd_10 = "AppRmdir" $cmd_11 = "AppRun" $cmd_12 = "AppWriteRegistryValue" $cmd_13 = "AppUnpackArchive" $cmd_14 = "ArchiveFiles" $cmd_15 = "GetFiles" $cmd_16 = "Sysinfo" $hash_1 = {ea8e5e34} $hash_2 = {3445694e} $hash_3 = {f73e97b6} $hash_4 = {9aa70c59} $hash_5 = {18b496c9} $hash_6 = {0f716ebc} $hash_7 = {8e2d79ce} $hash_8 = {3ae2a963} $hash_9 = {35d26840} $hash_10 = {6c41d6bc} $hash_11 = {1fdbbb2f} $hash_12 = {6ae6578d} $hash_13 = {66732be7} $hash_14 = {0b113b3d} condition: uint16(0) == 0x5a4d and ( 12 of ($cmd*) or 10 of ($hash*) ) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | rule G_Hunting_K1MORPHER_1 { meta: author = "Google Threat Intelligence Group" description = "Detects plaintext class and method names associated with the .NET class K1.Morpher" hash = "45bb8d1ab2c13bf4354294e13d3c9be15de625d807301905b98462f43f93e893" strings: $plain_api_1 = "Squirrel3" $plain_api_2 = "DecryptArraySimple" $plain_api_3 = "DecryptIntSimple" $plain_api_4 = "DecryptLongSimple" $plain_api_5 = "DecryptFloatSimple" $plain_api_6 = "DecryptStringSimple" $plain_api_7 = "DecryptDoubleSimple" $plain_api_8 = "_squ_ui1" $plain_api_9 = "_squ_ui2" $plain_api_10 = "_squ_ui3" $plain_api_11 = "InjectedSeedCipher" condition: dotnet.is_dotnet and 5 of ($plain_api*) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | rule G_Hunting_K1MORPHER_2 { meta: author = "Google Threat Intelligence Group" description = "Detects the Squirrel3 RNG implemented within K1.Morpher" hash = "45bb8d1ab2c13bf4354294e13d3c9be15de625d807301905b98462f43f93e893" strings: $squirrel3_code_1 = { 00 // nop 03 // ldarg.1 0A // stloc.0 06 // ldloc.0 7E ??????04 // ldsfld <token> 5A // mul 0A // stloc.0 06 // ldloc.0 02 // ldarg.0 58 // add 0A // stloc.0 06 // ldloc.0 06 // ldloc.0 1E // ldc.i4.8 64 // shr.un 61 // xor 0A // stloc.0 06 // ldloc.0 7E ??????04 // ldsfld <token> 58 // add 0A // stloc.0 06 // ldloc.0 06 // ldloc.0 1E // ldc.i4.8 62 // shl 61 // xor 0A // stloc.0 06 // ldloc.9 7E ??????04 // ldsfld <token> 5A // mul 0A // stloc.0 06 // ldloc.0 06 // ldloc.0 1E // ldc.i4.8 64 // shr.un 61 // xor 0A // stloc.0 06 // ldloc.0 0B // stloc.1 2B 00 // br.s 40 07 // ldloc.1 2A // ret } condition: dotnet.is_dotnet and all of them } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | rule G_Hunting_K1MORPHER_3 { meta: author = "Google Threat Intelligence Group" description = "Detects the Squirrel3 RNG implemented within K1.Morpher" hash = "391e51354118fb87dc57650cbbd94258c3f7c0a0d6868040b7a473ad626ff25e" strings: $squirrel3_code_1 = { 03 // ldarg.1 7E??????04 // ldsfld <token> 5A // mul 02 // ldarg.0 58 // add 25 // dup 1E // ldc.i4.8 64 // shr.un 61 // xor 7E??????04 // ldsfld <token> 58 // add 25 // dup 1E // ldc.i4.8 62 // shl 61 // xor 7E??????04 // ldsfld <token> 5A // mul 25 // dup 1E // ldc.i4.8 64 // shr.un 61 // xor 2A // ret } condition: dotnet.is_dotnet and all of them } |