Аналитики в области информационной безопасности столкнулись с изощрённой техникой закрепления вредоносного ПО в системе, которая позволяет злоумышленникам длительное время сохранять доступ к инфраструктуре жертвы. Механизм, обнаруженный в ходе расследования инцидента с программой-вымогателем DragonForce, использует скрытые возможности языка Python для выполнения бэкдора, создающего SOCKS5-туннель для командования и управления. Этот подход демонстрирует эволюцию тактик киберпреступников в сторону использования легитимных инструментов и сложной обфускации для уклонения от обнаружения.
Описание
В ходе стандартного анализа артефактов на заражённых компьютерах специалисты обратили внимание на нетипичное задание в Планировщике задач Windows с именем "523135538". Его функция заключалась в запуске исполняемого файла "pythonw.exe" из нестандартного каталога "C:\ProgramData\cp49s\" без передачи каких-либо аргументов командной строки. Обычно подобное поведение подозрительно, так как легитимные приложения редко запускают интерпретатор Python без указания скрипта. Первоначальная гипотеза о сторонней загрузке DLL (DLL sideloading) не подтвердилась. Вместо этого в той же директории был обнаружен файл "sitecustomize.py". Этот модуль обладает особым свойством в экосистеме Python: он автоматически импортируется и выполняется при каждом запуске любого скрипта или интерпретатора Python в системе. Помещение вредоносного кода в этот файл гарантирует его выполнение независимо от того, как был вызван "pythonw.exe".
Анализ скрипта "sitecustomize.py" раскрыл хитроумный механизм условного запуска полезной нагрузки. Код использовал функцию "Py_GetArgcArgv" из C API Python для определения количества переданных аргументов командной строки. Если аргумент был только один (сам "pythonw.exe"), что соответствовало конфигурации задания планировщика, скрипт автоматически находил и исполнял файл "b5yogiiy3c.dll", расположенный в том же каталоге. Этот файл, несмотря на расширение DLL, на самом деле являлся многослойно обфусцированным скриптом на Python, что и служило следующей стадией атаки.
Основная полезная нагрузка, скрытая в "b5yogiiy3c.dll", была защищена несколькими слоями сложной обфускации, затрудняющей статический анализ. Код использовал переименование функций в случайные строки, сплющивание потока управления (control-flow flattening) и кодирование ключевых фрагментов с помощью Base85 - алгоритма, реже встречающегося в системах обнаружения по сравнению с Base64. После последовательного прохождения трёх слоёв деобфускации исследователям удалось восстановить финальный скрипт. Его функционал был чётко сфокусирован: создание SOCKS5-прокси для туннелирования трафика на внешний сервер управления. Прокси использовал порт 443, маскируясь под обычный HTTPS-трафик. Модульная архитектура бэкдора, включающая классы для управления соединениями, ретрансляции данных и основного управления, указывала на профессиональную разработку и возможность масштабирования.
Согласно отчёту экспертов по угрозам, данный туннелирующий бэкдор известен под названием VIPERTUNNEL и ассоциируется с группировками UNC2165 и EvilCorp. Его часто используют как вторичную нагрузку после первоначального заражения через кампании типа FAKEUPDATES для обеспечения устойчивого доступа к сети жертвы. Такой доступ в дальнейшем может быть монетизирован, в том числе путём продажи другим группам, специализирующимся на ransomware-атаках. В данном случае активность программ-вымогателей была связана с DragonForce, однако прямых доказательств передачи доступа именно через этот экземпляр VIPERTUNNEL обнаружено не было.
Интересно, что аналогичный фреймворк обфускации был обнаружен и в других вредоносных образцах, например, в похитителе учётных данных ShadowCoil, который таргетирует браузеры на основе Chromium и Firefox. Это указывает на возможное использование одних и тех же инструментов разработки или общее происхождение угроз. Примечательной деталью стало наличие в коде ShadowCoil проверки на отладку для Linux (через файл "/proc/self/status"), что является аномалией для вредоноса, ориентированного на Windows. Это может свидетельствовать о кроссплатформенной природе самого фреймворка обфускации или о планах злоумышленников расширить арсенал для атак на Linux-системы в будущем.
Расследование также позволило выявить и проанализировать инфраструктуру злоумышленников. Помимо серверов C2 для VIPERTUNNEL, были обнаружены системы, использующие фреймворк для постэксплуатации Pyramid. Этот инструмент, работающий через HTTP и использующий легитимный "python.exe" для выполнения кода в памяти, трудно обнаружить традиционными EDR-решениями. Уникальной чертой развёртываний Pyramid в данной кампании стала специфическая HTTP-ошибка 401 с заголовком аутентификации "Basic realm="Proxy"", что позволило исследователям эффективно выявлять связанные серверы с помощью поисковых систем по интернет-вещам, таких как Censys.
Анализ временной шкалы развития бэкдора показал четыре основных этапа: от ранних версий с многочисленными ошибками в коде в конце 2023 года до современных, отполированных production-вариантов, наблюдавшихся в конце 2025 года. Эволюция включает отказ от отладочной информации, улучшение архитектуры и внедрение более сложных методов обфускации. Несмотря на возраст кампании, значительная часть инфраструктуры C2 остаётся активной, а используемые техники продолжают обеспечивать низкий уровень обнаружения. Это подчёркивает постоянную угрозу со стороны сложных, многоступенчатых атак, которые используют легитимное ПО и тщательно скрывают свою активность для долгосрочного закрепления в корпоративных сетях.
Индикаторы компрометации
IPv4
- 104.238.60.108
- 104.238.61.144
- 108.181.115.171
- 108.181.115.254
- 108.181.182.143
- 158.255.213.22
- 162.248.224.223
- 162.248.225.165
- 162.252.173.12
- 173.44.141.226
- 185.174.101.240
- 185.174.101.69
- 185.180.198.3
- 185.233.166.124
- 185.33.86.15
- 185.72.8.121
- 185.72.8.137
- 185.72.8.65
- 193.203.49.90
- 193.5.65.151
- 23.227.193.172
- 37.1.212.18
- 38.135.54.24
- 38.146.28.93
- 38.180.81.153
- 45.56.162.61
- 45.66.248.150
- 45.82.85.50
- 88.119.175.65
- 88.119.175.70
- 92.118.112.143
- 92.118.112.208
Domains
- CarryingItAll.com
- chateaugalicia.com
- joealdana.com
- rentiantech.com
SHA256
- 0212a0e0b6454fec8382268bf888c7f3a9716ba30d4ca34f2babe6e8ceaf2a7c
- 055f9a7cdda3b31883b5712290ccfbf3afbb14805321dbd99fcbf8ed4764ea25
- 05c61e9a8a7e8a3548afd765786f45181746c8e846912ca40aa5b7fa62262dc5
- 070b2a1bcce06b7e00706e368f871f7587fbec40ab827a02b73e9897ea221465
- 097d59852cdb90b68794c6554a89d11244f99375e1fd58ee594e30cd600fe66b
- 0f0db5079a9fbd760bb24ee979e2e808b2dc089c17033310838474a53a267f04
- 12ae155e8199695d68562890b5ea4d5013ac2f0fbca5ff67bc0907a7d7fec602
- 1633832a753c8537cb099e431bed4e33e65652ffa4bfaa23afdce71b05651b7d
- 1b7109ba3b20ece0b456fc03614f65548877d4743453dd10f7e810f1d6ac6ceb
- 1cc59f160255a97f68567369540134d6583ea732af843842c7123a84d317c784
- 2d58240827a684573c006f04c78b99d79ab9818993b450164e71f59cbff8c0e3
- 2d8ce4136f47ebded2ea489ea452cdc99b7638c94f56a6096e0c47897652f01a
- 2e5a9592ed31a0dd5656ce8506ee3a83565e715bd3eb9a2b077ff6a8b71a5244
- 319939aaefb0c306c5dcbd9104f9d21a1f227dab06f7aa451e6fc9c747874fe9
- 3207127b0190eaddf9092e9b01a031f64c3bc3af6744d3b8bdd2e5ee048e5478
- 32e1103fbebc2da104b86665f3d05543ee6bf1c9858bc9010499f051cf1963bf
- 35cc1e3d3a157fd46799847391d88f80e1d9215b63f2d5ac5322579d932c1412
- 3c19d4360acf8ab4ae999c491698699f4b33242b5d4ca01a35345d5fb558cfc4
- 3ef9f3f8741b00c812d1e33d28d0e86837147ae6eb441b2095a368d338501ebc
- 3f3e05b727b65d0abe18c1592919f95b7a818cfc7634c91bb826dd9441522e33
- 3f72ffff5ff4969f3d03def9a886ac900b449fa65f6e98d4610e013e01f43193
- 42e88b8d00767b4f2b51ee5ce30da381f703f408eeef8ca212cf44e60faa15d6
- 433a7c3fe0c744e91866f1e653d0f1346881ef4148a54e036b4470c6aba282cc
- 44737c38542b63f60492e37ee69bc30aa6d38b5d07ce2c53eccac0ad68670efd
- 45774351354928dd78c939cad20f91bb212872a20c63505ebf4bebdbba74dd71
- 48ad4a533807c71acdf6ffbd781ea11d3c7822ff625cad4fa6cc38827f5c45d1
- 4a4c43514316c368f57f68b6de9684efb66c37ae620da661d5aa917f5cd564f1
- 4ab1376d90a3999e4af7c08325af10807b840e8eab698fcfdc453297f5dad5bd
- 4bb2f52df4ab8147a750ff1cac8845bbc5ec7d9ca57a81bc8522d9b0f7356dff
- 4da5c9487bf85133a1fd56c3d793ce4eca2c7a88c72843a88c15bcec1599aa9a
- 5199183ad5bc7b6090f19170a8798b0d4855b702a4911af8a4ec61925bda985a
- 535d7438c4da5df2de32bdb5adbc1d9ef0572502727e85118d775ffff1440146
- 54cbe290051980c511d3aa1d3c9847fef997d0d5c38182064ef5eaad2397a27a
- 56c1546e20965873510e7f9e81fb30c12676e57d641bcc881e11700649dc4d91
- 57fe27bde73ac2e5cec527971f7026d11f0db8ebf566db0ffec15b7c4a6f3f83
- 5bc1f8b3c50dc6c81aad215f24996271eb00c218f608d9ef20ec99d7b4130415
- 5cb4ddfc5ad906961c8d41c73046d0ab41bdaf5e6cf44a02a370e149721f6ed4
- 6277a5119de4163805a07c63bce65772e158ee2164cadadb92a2815fcf8fb571
- 64639a381b26102e5c4817b976d50d5b2b2eb7ae78f5c7da947edfe5a20a7489
- 64d8f12cdcd1dfa7a3c012a36c011a43303dc8357b7899db254a022b187cba03
- 668b77e4e53490eba960abd7f482ff5126af4b16abb4dd3972e533444d5dffa9
- 68a9afcf6be360cbe63b22238ab342f2038738af7571304d5b9e7894a83bd04d
- 6a4e87bec6da6001a53fef2feb5bc6f81b461370da8abc9a9912721071c24300
- 6b560ab85dfb47603f67b7978572bb23bcea303d98c9624a7fe51aacddcadaa3
- 6b784c8731cc964f6029ead93a50769f2dbe4812c19fea88ecec7b4744c340c9
- 6d5949612708c2a125020731eb82f930b1d70fca58109072c77fdded65b02c6d
- 74f5309915bbf53ccf3048bdb66d357a7939ffbcc972cc239d5ff49c3e0a2bbe
- 74f7193876493c068a1b308fa5620ff9f5e0322925f195338cbe0abb4f132fd0
- 7aa0f3fd45c8b1e8c5ae9c06041f24f4c71cb247587dfea6440b10e67ebb5f30
- 7cc2aac1a47457c1aa06510de58b539a8b1b6df0817374c8330d928c6daa70f2
- 7e7841189912f875db543ca9941790782ba4d0d30d85c7ba484a1aa908a64b5f
- 7ec0f91eb7dafa6bdf93b6362ff391d7a87ebca38021b0da1de95360d32e016d
- 813f89f92501588c8229cc369ee4847a9d9818ba1cb5ae65f2942683f85bfb2f
- 906f80a485832dbdc663aa4873728d6d3291931031c7a53e2080a6b337c26341
- 99db12259078ab0fa0efc63b287c9e3c793476272e8d38e5c3895e2b99099897
- a03752027416bcee647881535a5c055a770d9c25630a2792495d042632ed81c0
- a7bb8f2c5ca3897a9c3ca3ee1a5974c03000510cd8cab68fcb332a8455e0799d
- a864694417614175a5698a5ae771aabc4c4f6cfa48acb980d942519d46791ead
- a9173d786af251ce5300fc57a901017056f51417381eb62bfea714d736b68f05
- af2fb6c99b3c2b2311a619a76dd51cf928ba8e9a7a4c74d79642bef7217e2bcd
- afd77ee76b93e0377ca4d075409b41a772a66758ca8ed9894d4228028c4367c6
- b13ceeb14f707fabc7a689aee41005d7f1ff526223d6a43701dc1ca3513a0895
- b6f6db65733f5735600296fd804397f2f41c138af3e91c85a214e4fcd452bd42
- b7efa6daa471c34e4753f9eb09e70de013077bedf62972449afe9ea0185abe1c
- baa412223f945dcb24a7f55a90709ddf7a228c8e5726a5b145a2c6220b6837c5
- bba5d69a1bf2a57ba653f8da948eafa84f6546b8344783dd9202fdc5cf8a5a18
- bc970c4b07c945d225ee0f68c65271603e56c2e377d5c39d2cf113704915dccd
- bef0a83fb7c7600984a3dc4ea3276f5031bd029b734988b6fa742b57c48d4e1b
- bfcd27af620be644481df607398ceff2cdf64302be2109b758e7f1c465b8bc1c
- c563eb24a4a90152c234adb0be184a38049c68dbe214aacdca5d1977e598af38
- c92090cca0dee6624469362adcf9728c92c5185c4bee2fa86b77b87c451a9ae6
- ccfa2a85c2ca12cafb6819c9521be8c886d970dcf65a3d19529984676d1eca9c
- ce068a250edd34425123d1c8ad5c9e7d126a9b11648689ca0a6a588eabaac429
- d3d1992901fa45ddd26a80e60295d38f57c83a9aea5c54bb306279fcb4d937a9
- d4c9b47d0f9753f1538724c6f47ffc9f3217ffd94b46a02e7f864365d8cafab5
- d4f548b2877f8ed7237c1b6f28d014090eeb574b8471e72d5329658a74a0b589
- d63b5e4634dde2aa02970501b3fe45fb52953951432232d8167d31cf9a2f7fcc
- d804cd2d448f5985a61f04edf910f9686340241d6d42b650c6b22bdec1517eb6
- d885793d84f4b0d295893b925f938bdf341a699c957d68854762d16a86aa864f
- d97d8544dcfd573a88123c4c5ccb76dd1560bbefdba6db473b66cac96f4cbb0d
- daca113fa439b50c2b91099c47932a16853fe0c8728b6fa00cba3066b0986503
- e45f935195d12b4e691fe39d9e43efa1b81f6303c19e4cd7823ff6f3a03e3153
- e7bbf40533fd939c0aa64446671209bb70a85e5b7ea4aab1923e37034cb3b996
- e94af836df4ddd74a933906b508836712fe4fe18cfc0cdf8890c4d22b7a11540
- eb15f77924658bb33300a93ee9a4fc07e874e8324d986452c673928ea85681b7
- ef08579497578b10d9256ac9b7542636cd55e461fd5b6deb82970d84f3c7de4d
- f17c05ce7476c11c58731d4081e4f5e5288df15e301cbc43bb0d245998c33140
- fb9b46f942d1f06a6176ecd6e4dae0d5b7b692682c978bbc479f7f903851b53a
YARA
| 1 2 3 4 5 6 7 8 9 10 | rule AV_match_shcoil { meta: author = "Evgen Blohm @ InfoGuard AG" description = "Hunt for samples that have ShadowCoil related AV matches that often also used for VIPERTUNNEL samples" date = "2025-02-09" condition: for any engine, signature in vt.metadata.signatures : ( signature contains "ShCoil" or signature contains "ShadowCoil" ) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | rule ShadowCoil_Packed_Python { meta: author = "YungBinary" description = "Modified the original rule " target_entity = "file" source = "https://www.esentire.com/blog/unpacking-shadowcoils-ransomhub-ex-affiliate-credential-harvesting-tool" strings: $a = "exec(pc_start(" ascii $b = "get_hw_key():" ascii $c = "'vm', 'virtual'" ascii $d = "TracerPid:" ascii condition: vt.metadata.file_type == vt.FileType.PYTHON and filesize < 60KB 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 37 38 39 40 41 42 43 44 45 46 | rule MALWARE_vipertunnel { meta: author = "Evgen Blohm" description = "hunting rule for socks5 backdoor aka VIPERTUNNEL" strings: // Unique Class Names and Functions $class1 = "class Wire(" ascii wide $class2 = "class Relay(" ascii wide $class3 = "class Commander(" ascii wide $class4 = "class ControllerCommandConnection" ascii wide $class5 = "class MySocket" ascii wide $class6 = "class MyServiceSocket" ascii wide $class7 = "class Handler" ascii wide // Custom Exception Names $exc1 = "ConnectionTimeoutOccuredError" ascii wide $exc2 = "BadLengthData" ascii wide $exc3 = "CloseException" ascii wide $exc4 = "ExitException" ascii wide $exc5 = "ConnectionClosedError" ascii wide $exc6 = "ConnectionResetError" ascii wide $exc7 = "ConnectionAbortedError" ascii wide $exc8 = "ConnectionRefusedError" ascii wide // Logic-specific strings $logic1 = "self.must_equal = " ascii wide $logic2 = "struct.unpack('BBB', self." ascii wide $logic3 = "def _bridge(self):" ascii wide $logic4 = "socket.socket = Wire" ascii wide // unique variables $var1 = "main_flag_to_close" ascii wide $var2 = "TIMEOUT_FOR_SOCKET_OPERATION" ascii wide // Unique Identifiers $user = "AnyLogin" ascii wide $secret = "AnyPassword" ascii wide condition: filesize < 60KB and vt.metadata.file_type == vt.FileType.PYTHON and ( (3 of ($class*) and 3 of ($exc*)) or (2 of ($class*) and 2 of ($exc*) and 1 of ($logic*) and 1 of ($var*)) or ($user and $secret) ) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | rule MALWARE_vipertunnel_typos{ meta: description = "Hunting for ViperTunnel Python Proxies using some left over typos" strings: $typo1 = "__setatrr__" ascii wide // __setattr__ $typo2 = "deamon" ascii wide // daemon $typo3 = "allow_no_verifing" ascii wide // allow_no_verifying $typo4 = "ConnectionTimeoutOccuredError" ascii wide // ConnectionTimeoutOccurredError $typo5 = "% ((target" ascii wide // logged as tuple condition: filesize < 60KB and vt.metadata.file_type == vt.FileType.PYTHON and ( (3 of ($typo*)) ) } |
| 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 | rule MALWARE_vipertunnel_obfuscation { meta: author = "Evgen Blohm" description = "Finding files using the same obfuscation as in IR1361" strings: // decoding/decryption related keywords $crypto1 = "b85decode" ascii wide $crypto2 = "PBKDF2" ascii wide $crypto3 = "HKDF" ascii wide $crypto4 = "MODE_GCM" ascii wide $crypto5 = "MODE_CTR" ascii wide $crypto6 = "ChaCha20" ascii wide $crypto7 = "blake3" ascii wide // dynamically imported functions $imp1 = "join" ascii wide $imp2 = "chr" ascii wide $imp3 = "map" ascii wide $imp4 = "map" ascii wide $imp5 = "zip" ascii wide $imp6 = "bytes" ascii wide $imp7 = "getattr" ascii wide $imp8 = "builtins" ascii wide // static imports $s_imp1 = "import zlib" ascii wide $s_imp2 = "import sys" ascii wide $s_imp3 = "import base64" ascii wide $s_imp4 = "import AES" ascii wide $s_imp5 = "import SHA256" ascii wide $s_imp6 = "import os" ascii wide $s_imp7 = "import blake3" ascii wide $s_imp8 = "import hashlib" ascii wide // base85 encoded chars/strings $enc4 = "WNBw*b94" ascii wide // digest $enc5 = "WMyM=d2n<" ascii wide // decrypt $enc6 = "V{dhCbN" ascii wide // count $enc7 = "Zf|a5Wd" ascii wide // nonce $enc8 = "WMyM=d2n=JVQyq!c4cyDW_b" ascii wide // decrypt_and_verify $enc9 = "Wq4&{" ascii wide // exec condition: vt.metadata.file_type == vt.FileType.PYTHON and filesize < 40KB and ( (3 of ($crypto*) and 3 of ($imp*) and 2 of ($s_imp*) and 2 of ($enc*)) ) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | rule MALWARE_vipertunnel_obfuscation_old { meta: author = "Evgen Blohm" description = "" strings: $func1 = "decode('utf-8')" ascii wide $func2 = "int.from_bytes" ascii wide $func3 = "while True:" ascii wide $func4 = "sys.exit(0)" ascii wide $imp1 = "import blake3" ascii wide $imp2 = "import base64" ascii wide $imp3 = "import hashlib" ascii wide condition: filesize > 10KB and filesize < 80KB and vt.metadata.file_type == vt.FileType.PYTHON and ( (3 of ($func*) and 3 of ($imp*)) ) } |