С конца 2022 года не менее 25 сайтов, связанных с курдской общиной, передавали неизвестным операторам геолокацию своих посетителей. В части случаев сбор шёл дальше: смартфон жертвы снимал изображение через фронтальную камеру, а отдельным пользователям предлагали установить приложение, которое выглядело официальным. Кампания оставалась незамеченной больше полутора лет. Среди пострадавших ресурсов - редакции новостей северо-востока Сирии, сайты автономной курдской администрации, структуры местных вооружённых сил и политические организации в Турции и Ираке.
Описание
Схема начиналась с обычной страницы. Человек открывал привычный новостной ресурс, и при загрузке срабатывал скрытый код. Сначала он проверял, с какого устройства пришёл посетитель, и только владельцам смартфонов показывал запрос на доступ к местоположению. Внешне запрос выглядел стандартно, поэтому многие соглашались. Получив разрешение, код отправлял координаты на сервер, спрятанный на том же взломанном сайте. Владельцы ресурсов о происходящем не знали, а посетители не догадывались, что их сведения уходят на сторону.
Расследование Sekoia Threat Detection & Research выявило четыре разновидности этого кода. Простейшая собирала только координаты и встречалась на семнадцати сайтах. Вторая добавляла к ним идентификатор, который сохранялся в браузере жертвы на 400 дней и позволял связывать между собой посещения разных ресурсов. Третья считывала технические параметры устройства, заряд батареи и снимала изображение с фронтальной камеры. Четвёртая, самая сложная, вела отобранных посетителей на страницу загрузки вредоносного приложения для Android. Один из сайтов за два года сменил три версии кода.
Почти никаких изощрённых приёмов вроде уязвимостей нулевого дня здесь не применялось. При этом собранные сведения злоумышленники пропускали через взломанные серверы, поэтому отследить конечный пункт назначения почти невозможно. Внешне трафик выглядел как обычное обращение к сайту новостей. Именно это и позволило кампании оставаться незамеченной так долго. Заметна и оплошность авторов схемы: один вспомогательный файл назывался иначе, чем в обращавшемся к нему коде, из-за чего часть задуманной слежки не работала вовсе.
Самым опасным инструментом стало мобильное приложение. Оно маскировалось под программу курдского новостного агентства из Эрбиля. После запуска приложение открывало сайт агентства внутри себя, поэтому владелец видел привычные новости и не замечал подвоха. При установке программа запрашивала доступ к контактам, геолокации и файлам на устройстве - такой набор разрешений сразу вызывал вопросы. Через десять секунд после открытия скрытая служба начинала отправлять координаты владельца на сервер и ждала команд. Оператор мог получить сведения об устройстве и установленных приложениях, выгрузить записную книжку, изучить содержимое памяти или забрать отдельный файл. Закрепления в системе программа не оставляла и работала, только пока приложение открыто.
Установку предлагали не всем. Список активных модулей оператор задавал удалённо, поэтому ссылку на загрузку получали только заранее отобранные люди. Такие ссылки, скорее всего, рассылали в мессенджерах от имени знакомых ресурсов. Одновременно код проверял, не открыт ли браузер в режиме приватного просмотра, и молчал, если пользователь включил защиту. Такая осторожность и продуманное распределение ролей между модулями отличают кампанию от типичных массовых подстановок.
География тоже говорит о многом. Курды - разделённый народ, который живёт на территории четырёх стран: Турции, Ирана, Ирака и Сирии. Часть пострадавших ресурсов относится к сирийскому северо-востоку, где курдская администрация управляет территориями де-факто. Другие связаны с партиями и движениями, действующими в Турции. Третьи работают в Иракском Курдистане. Разрозненность сообщества делает сбор даже обрывочных сведений о нём ценным для разведки.
Атаку приписывают спецслужбам региона, но прямых доказательств нет. Анкара считает все пострадавшие ресурсы связанными с Рабочей партией Курдистана, поэтому турецкие службы - первый подозреваемый. Сирийская разведка пытается вернуть контроль над северо-востоком страны и тоже заинтересована в сведениях о местных силах. Наиболее вероятной выглядит версия о властях Иракского Курдистана: у них давние противоречия с курдской администрацией Сирии и налажен обмен информацией с Турцией. Косвенным доводом служит задержание журналиста одного из взломанных изданий в октябре 2023 года. Технических совпадений с известными группировками - турецкими, иранскими или российскими - не нашлось. Скорее всего, за кампанией стоит ранее неизвестная группа с ограниченными возможностями и небольшим опытом.
Владельцам сайтов полезно относиться к своим ресурсам внимательнее. Регулярные обновления системы управления контентом закрывают большинство лазеек, через которые злоумышленники попадают внутрь. Время от времени имеет смысл просматривать служебные каталоги и искать посторонние вставки в шаблонах. Двухфакторная аутентификация для администраторов и разграничение прав доступа усложняют захват панели управления. Пользователям достаточно внимательно читать запросы разрешений: новостному сайту незачем знать координаты или открывать камеру. Кампания просуществовала больше года именно потому, что такие запросы никого не насторожили.
Индикаторы компрометации
IPv4
- 170.75.161.102
- 23.95.14.63
- 24.246.223.228
Domain
- ciwanensoresger.com
- dicle.fm
- dirbesiye.fm
- halkin-dg.com
- hawarnews.com
- hbdh.info
- init4afrin.org
- kongra-star.org
- leftkup.com
- lekolin.org
- nuceciwan129.xyz
- orkesfm.com
- pajk.org
- rojnews.news
- ronahi.net
- ronahi.video
- sdf-press.com
- sehidenrojava.com
- star-fm.net
- targetplatform.net
- tev-dem.com
- thkp-c.org
- webmail.onlinearuba.net
- ypj-office.com
- ypjrojava.net
- yra-ufm.com
- zindi24.com
MD5
- 7ff9e87f8c8ea10e6aa688c491c81283
SHA1
- 6c75d5f31fe386a1ec94b85cfb7f873b2e100062
SHA256
- 2d75110d4c227c59b9c8fb02cc54b99d0b41e33a2fe1ad50e2fdf0cfb1e701d5
YARA
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | rule apt_SilentSelfie_Rojnews_application_apk { meta: id = "8d9036f6-2603-4d8d-a33d-ecae0c0b1cd2" version = "1.0" description = "Detects malicious RojNews application" source = "Sekoia.io" creation_date = "2024-05-21" classification = "TLP:WHITE" strings: $ = { 00 05 4D 6F 64 65 6C 00 } $ = { 03 31 30 31 00 03 31 30 32 00 03 31 30 33 00 03 31 30 34 00 } $ = { 09 61 6E 64 72 6F 69 64 49 44 00 } $ = { 0A 61 6E 64 72 6F 69 64 5F 69 64 00 } $ = { 08 50 6F 73 74 44 61 74 65 00 } $ = { 0B 4E 65 74 77 6F 72 6B 49 6E 66 6F 00 } $ = { 0F 61 70 70 5F 70 61 63 6B 61 67 65 6E 61 6D 65 00 } $ = { 0F 61 70 70 5F 75 70 64 61 74 65 5F 64 61 74 65 00 } $ = { 15 6E 65 74 77 6F 72 6B 5F 6F 70 65 72 61 74 6F 72 5F 6E 61 6D 65 00 } condition: uint32be(0) == 0x6465780A and filesize < 3MB and 8 of them } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | rule apt_SilentSelfie_WateringHole_compromised_html_body { meta: id = "ef1095e9-faa2-4fcb-bbc8-c7c98c4d86e0" version = "1.0" source = "Sekoia.io" creation_date = "2024-05-21" classification = "TLP:WHITE" strings: $s1 = "body" nocase $s2 = "gL()" condition: $s1 in (@s2-60..@s2) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | rule apt_SilentSelfie_WateringHole_variant_one { meta: id = "d9b1427e-241d-4beb-8bb8-582116b2a4db" version = "1.0" source = "Sekoia.io" creation_date = "2024-05-21" classification = "TLP:WHITE" strings: $s0 = "navigator.userAgent.match(" $s1 = ".php?';" $s2 = "params = 'log=" $s3 = "+ ',' +" condition: $s1 in (@s0..@s2) and $s2 in (@s1..@s3) } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | rule apt_SilentSelfie_WateringHole_variant_two { meta: id = "ab5af795-808f-42b7-ba09-a910263855b5" version = "1.0" source = "Sekoia.io" creation_date = "2024-05-21" classification = "TLP:WHITE" strings: $ = "sC()" $ = "checkC" $ = "sessionIdVal" $ = "function sP(" $ = "x.readyState===x.DONE&&200" condition: all of them } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | rule apt_SilentSelfie_WateringHole_variant_three { meta: id = "af264e75-73e8-4623-8565-f84fe4e91cbe" version = "1.0" source = "Sekoia.io" creation_date = "2024-05-21" classification = "TLP:WHITE" strings: $ = "hex_hmac_md5" $ = "facingMode" $ = "getWebRTC" $ = "sessionIdVal" $ = "function gL()" condition: all of them and filesize < 100KB } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | rule apt_SilentSelfie_WateringHole_variant_four { meta: id = "2d4f7ff1-35ed-4c3c-82f0-e169bd29e719" version = "1.0" source = "Sekoia.io" creation_date = "2024-05-21" classification = "TLP:WHITE" strings: $ = "checkRules(" $ = "getModuleList(" $ = "globalUAData" $ = "binl2rstr" $ = "sessionIdVal" $ = "&webrtc=" $ = "handleSuccess" $ = "&referer=" condition: all of them and filesize < 50KB } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | rule apt_SilentSelfie_WateringHole_php_gateway { meta: id = "5c4bc7c1-1512-4703-a407-f0dbc7f11d26" version = "1.0" source = "Sekoia.io" creation_date = "2024-05-21" classification = "TLP:WHITE" strings: $ = "sysOther" fullword $ = "sendRequest" $ = "base64_decode" $ = "otherHeader" fullword $ = "webrtc" fullword $ = "php://input" $ = "battery" fullword $ = "webgl" fullword condition: uint32be(0) == 0x3c3f7068 and filesize < 9KB and 6 of them } |