В роутерах китайского производителя Zbtlink обнаружена предустановленная вредоносная закладка, которая с завода связывается с командными серверами в интернете. Вредоносный компонент, получивший название ENDLESSDOORS, затрагивает более двадцати моделей устройств, включая популярные серии для домашнего и офисного использования.
Описание
Производитель - компания Shenzhen Zhibotong Electronics, которая выпускает роутеры под собственным брендом, а также изготавливает устройства по заказу других вендоров. В результате одно и то же устройство может продаваться под разными именами, например Wiflyer, что заметно затрудняет идентификацию. Проблеме присвоен идентификатор CVE-2026-66747.
Закладка начинает работать сразу после включения роутера. Она маскируется под системный процесс kworker, который всегда присутствует в списке задач операционной системы Linux, поэтому обнаружить её крайне сложно. При каждом включении устройство обращается к одному из четырёх командных серверов, размещённых в облачных хостингах в разных регионах мира.
Исследование VulnCheck показало, что вредоносный компонент умеет не только выполнять отдельные команды, но и открывать полноценный удалённый доступ к устройству с правами администратора. Для этого не требуется сложной эксплуатации уязвимостей - достаточно, чтобы роутер сам установил соединение с сервером атакующего. При этом закладка не проверяет подлинность командного центра и не использует механизмы шифрования для защиты управляющего канала, поэтому любой, кто контролирует адрес или канал связи, может перехватить управление.
Особую опасность представляет то, что соединение инициирует сам роутер. Из-за этого закладка работает даже за несколькими уровнями межсетевых экранов, ведь исходящий трафик обычно не блокируется. Чтобы получить доступ к устройству, злоумышленнику не нужно искать открытые порты или обходить защиту периметра - достаточно дождаться, пока роутер сам выйдет на связь. Устройство за одним файрволом так же уязвимо, как и роутер с публичным адресом.
Исследователи проверили прошивки, опубликованные на официальном сайте производителя, и подтвердили, что закладка присутствует в каждой из них. Среди затронутых моделей - CPE2801, WE1026-5G-WD, WE1326, WE2007, WE2008-DSIM, WE2416, WE3326, WE826-T3-DSIM, WG108, WG1602, WG1608-DSIM, WG209, WG2105, WG2107, WG259, WG3526, Z8102AX-2DSIM и ряд других. При этом компания активно предлагает услуги по выпуску продукции под чужими брендами, поэтому аналогичная прошивка может встречаться в роутерах других производителей. Проверять устройства нужно по номеру модели, а не по логотипу на корпусе.
Примечательно, что сами исследователи приобрели один из таких роутеров через онлайн-площадку Alibaba для проверки. Уже в лабораторных условиях устройство начало регулярно отправлять запросы на внешние серверы, что стало отправной точкой для анализа. В ходе эксперимента специалисты перехватили исходящее соединение закладки и получили полный контроль над роутером, подтвердив тем самым реальность угрозы.
Контроль над роутером открывает злоумышленнику доступ к локальной сети, в которой установлено устройство. Через такую точку входа атакующий может перенаправлять пользователей на поддельные сайты, перехватывать незашифрованный трафик и проводить атаки на другие устройства. Кроме того, роутер может использоваться как промежуточная площадка для скрытых атак на сторонние системы, что затрудняет их отслеживание. Особенно критична ситуация для гостиниц, филиалов компаний и автопарков, где подобные роутеры часто устанавливаются для организации связи и работают годами без проверки.
Поскольку закладка встроена в прошивку на этапе производства, официального обновления, устраняющего проблему, не существует. Более того, разработчики вредоносного компонента использовали исходный код публичного инструмента удалённого управления, опубликованного на GitHub ещё в 2015 году, и адаптировали его под свои задачи. Протокол обмена данными предельно прост: роутер отправляет короткое сообщение с идентификатором устройства, а сервер в ответ передаёт команды на выполнение. Вредоносный код не использует сложных методов шифрования или проверки подлинности, что упрощает его перехват.
Эксперты рекомендуют владельцам таких устройств провести инвентаризацию сетевого оборудования и сверить номера моделей со списком затронутых. При наличии технической возможности следует проверить список процессов на роутере: наличие подозрительного процесса kworker с признаками активности - повод для беспокойства. Кроме того, на межсетевом экране необходимо заблокировать исходящие подключения к известным командным серверам и настроить оповещения о таких попытках. Важно помнить, что простое блокирование без оповещения не позволит вовремя обнаружить заражённые устройства.
Для устройств, используемых в корпоративной среде или для передачи важных данных, наиболее разумным решением будет замена оборудования. Отключение вредоносного компонента вручную не гарантирует отсутствия других закладок в прошивке. Даже если роутер изолирован в отдельном сегменте сети, остаётся риск его использования в качестве канала для скрытных атак. Если замена невозможна, устройство следует разместить за строгим контролем исходящего трафика и считать его локальную сеть недоверенной.
Проблема усугубляется тем, что закладка была намеренно добавлена производителем и поставляется в прошивках уже несколько лет. Это не случайная ошибка кода, а сознательно интегрированный компонент, что делает традиционные процедуры раскрытия уязвимостей бессмысленными. Публикация исследования преследует практическую цель: дать защитникам инструменты для обнаружения заражённых устройств и предотвращения потенциальных атак. Решение об опубликовании без предварительного уведомления производителя объясняется тем, что закладка не является уязвимостью в традиционном смысле, а значит, исправление невозможно.
Индикаторы компрометации
IPv4
- 43.248.136.125
- 45.32.81.152
- 47.100.190.96
- 47.107.224.89
Domain
- online-string.com
- rbdg4nzqadui.wikaba.com
- zbtctl.epplink.net
Firmware Image Hashes
- 09ed9ad3ac886f5aaf8357127b6dd5926bd4af1e2cc687a6a4856bcaedee2667
- 1545169fa8a3ae182d8e39aca8ec6cb6849b864e38646f29017232813e397e77
- 2d558bc9a6c7e7480e946f1c0524a651554887a1c563d7633f1903d06ff493fb
- 37efadf0f4a110be0145139a43ebd032abb5b27b79b1eb2ab3578dcd31655a9e
- 47d8ffb3a9a3fe0337e3c1e355fab4847dd61952fbe9aad98aadede489ca31fd
- 4f5d8319b4bad5d9243496c1358fda4783ea9a0865c32881b3f57ecedb879570
- 6926f919da7f4447229f49842266d884369e1587df655149673e46f1d8787e47
- 71b20ebff0630b33c96bef320adc75901b34f1fd2cc9af974cf93ff37d102ec8
- 73a0d95b8e23c7780cd91e978238c6db519665b05481fb228b4db9a9ec99c8ae
- 76a17581bbde4c0550e8f4abfd903923aceeb50dc69dae4dd904628c273b90ee
- 7791de11cd27cb596deff089904a6eab3a7e0aa391f867c2389582d5c78fef4c
- b3956cfbebf9c8d0b2c7a2ecbe59e71c31a5802f2084d25d93a984c0f811e2c7
- b3e667235e9b41b8fc3594edaa64879750e7f75d7518fff7514d55837430411a
- b4fda77e082fbf961db02273999e92e715e1824140ea92b2ab30163338b6622b
- dcdaa1fe80707b8d8fde8ad36c3e62a53623aff09bf5ccc544d4c1a1a54208b8
- dee3908280b91cb7ad60c69c1d34c599ceed7c8c66c025851e5831482815b271
- efc8a8ead69c63ecfffd883cfbe6bd131082aa13c0d3b324c00d79f4c149bd92
- f019d03c2489b2bc486d71e355e07f8f2862dff078574a8662a5a45932e7e453
- f5a94e536a1cac8552fb9c327c4bac6017e034786be98cc402a149cb51250d8f
- f961e4243e759453294340bc7d1b145016d70b97ab328caf47c64ea3cd818148
kworker Hashes
- 00a1228648fffa7338076970037b89f679a166a08c4d9573f1f27973ec6ed497
- 31ee58a134b766f6ed4424a22cc2cb08cfabbc9a5f35e0ae11a250c81ccc7f5e
- 33f8c0532100eeb10213d167e5eb483394a7e43bf6d276441a1573360622011a
- ab8467e1495479693f4de8e838a5aeb61a65f3682d68f5b2d7c856cbfc91a247
- dc1f4056af20677bdc7294ae4707f0c7bdfc85d8b57db212b622b9dc09c92731
- e85104fce4061d52d47f4528df9aaf656edc49f05c0f026c5bc6b65d57eb7f22
Suricata
| 1 2 3 4 5 6 7 8 9 | alert tcp any any -> any 7000 ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant Check-in"; \ flow:established,to_server; \ dsize:39; \ pcre:"/^[A-Z0-9._-]{2,32}\x00{1,31}[\x00-\xff]{6}$/s"; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800002; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
| 1 2 3 4 5 6 7 8 9 | alert tcp any 7000 -> any any ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant Interactive Root Shell Request (rctlbash)"; \ flow:established,to_client; \ dsize:12; \ content:"|00 00 00 08|rctlbash"; depth:12; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800003; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
| 1 2 3 4 5 6 7 8 | alert dns any any -> any any ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant C2 Domain Lookup (zbtctl.epplink.net)"; \ dns.query; content:"zbtctl.epplink.net"; nocase; \ pcre:"/(^|\.)zbtctl\.epplink\.net$/i"; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800004; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
| 1 2 3 4 5 6 7 8 | alert dns any any -> any any ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant C2 Domain Lookup (online-string.com)"; \ dns.query; content:"online-string.com"; nocase; \ pcre:"/(^|\.)online-string\.com$/i"; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800005; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
| 1 2 3 4 5 6 7 8 | alert dns any any -> any any ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant C2 Domain Lookup (rbdg4nzqadui.wikaba.com)"; \ dns.query; content:"rbdg4nzqadui.wikaba.com"; nocase; \ pcre:"/(^|\.)rbdg4nzqadui\.wikaba\.com$/i"; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800006; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
Snort
| 1 2 3 4 5 6 7 8 9 | alert tcp any any -> any 7000 ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant Check-in"; \ flow:established,to_server; \ dsize:39; \ pcre:"/^[A-Z0-9._-]{2,32}\x00{1,31}[\x00-\xff]{6}$/s"; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800002; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
| 1 2 3 4 5 6 7 8 9 | alert tcp any 7000 -> any any ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant Interactive Root Shell Request (rctlbash)"; \ flow:established,to_client; \ dsize:12; \ content:"|00 00 00 08|rctlbash"; depth:12; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800003; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
| 1 2 3 4 5 6 7 | alert udp any any -> any 53 ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant C2 Domain Lookup (zbtctl.epplink.net)"; \ content:"|06|zbtctl|07|epplink|03|net|00|"; nocase; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800004; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
| 1 2 3 4 5 6 7 | alert udp any any -> any 53 ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant C2 Domain Lookup (online-string.com)"; \ content:"|0d|online-string|03|com|00|"; nocase; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800005; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
| 1 2 3 4 5 6 7 | alert udp any any -> any 53 ( \ msg:"VULNCHECK Zbtlink Router ENDLESSDOORS Implant C2 Domain Lookup (rbdg4nzqadui.wikaba.com)"; \ content:"|0c|rbdg4nzqadui|06|wikaba|03|com|00|"; nocase; \ reference:url,https://github.com/ycsunjane/rctl; \ classtype:trojan-activity; \ sid:12800006; rev:1; \ metadata: deployment Datacenter, impact compromised;) |
YARA
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | rule Zbtlink_Router_ENDLESSDOORS_Implant { meta: description = "Zbtlink Router ENDLESSDOORS implant (rctl/kworker): /usr/sbin/kworker and /usr/lib/librctl.so. Plaintext, unauthenticated root C2 with an rctlbash PTY reverse shell. Matches MIPS and aarch64 builds." reference = "https://github.com/ycsunjane/rctl" strings: $cfg = "/etc/kworker.cfg" ascii $ca = "/etc/ssl/certs/wirelesser_ca.crt" ascii $bash = "rctlbash" ascii fullword $ok = "exec success: %s" ascii $fail = "exec fail: %s" ascii $bport = "bash listen port" ascii $super = "super ip" ascii $link = "rctllink type is error" ascii condition: uint32(0) == 0x464C457F and 4 of them } |