Как-то раз захотелось автору чего-то нового на замену хорошему, и решил он подключиться к GPON от одного известного оператора. И была автору поставлена в квартиру волшебная коробочка, через которую можно было звонить по телефону, выходить в интернет и смотреть телевизор, а заведен в нее при этом настоящий оптический кабель. И зовут эту коробочку optical network terminal (ONT) Sercomm RV6688, сделана она по заказу этого самого оператора и раскрашена соответствующим логотипом.
Работает коробочка. А автору не сидится, и опять захотелось чего-то большего, и решил он разобрать(ся), как же все это волшебство внутри коробочки получается и можно ли им тонко управлять. Но какое может быть волшебство без сюрпризов.

Отправная точка


Что удалось найти по теме в сети Интернет. Кроме известного из инструкции учетной записи пользователя admin/admin с правами «ниже плинтуса», на технических форумах удалось раскопать «секретную» (не привожу ее тут) учетную запись с расширенными правами support, которая дает больше степеней свободы, но не позволяет заглянуть глубоко в операционную систему ONT. Еще упоминались «дыры» в web-интерфейсе, через которые можно было повысить права пользователей, но которые были оперативно устранены в новых прошивках и поэтому потеряли актуальность.

Свой путь


Опыт общения с подобным оборудованием подсказывал, что у ONT где-то должен присутствовать порт для сервисного обслуживания. Обычно это последовательный порт RS-232, который (редко) выведен наружу в D-sub разъеме с уровнями напряжений 12В либо присутствует на плате в виде штыревой колодки с уровнями TTL +5В или +3.3В, т.е. чистый UART без дополнительной микросхемы преобразования уровней напряжений. Часто на этот порт, который в Linux-е именован устройством tty*, выведена консоль Linux (ведь никто не сомневается, что внутри ONT Linux? :) ) и консоль загрузчика Redboot, U-boot, Barebox и др. Доступ к этой консоли предоставил бы широкое поле действий. Но внешнего разъема я не нашел.
В общем я придерживался этих предположений, когда начал развинчивать ONT. Для эстетов несколько слов о наклейке-пломбе защиты. Пластиковый корпус RV6688 можно «хитро» приоткрыть, без срыва пломбы. Если чуть «напрячь» на изгиб крепление опломбированного винта, то можно даже извлечь плату, что и было сделано.

Плата ONT:

Беглый осмотр платы после задержавшегося на несколько секунд на оптическом модуле взгляда выявил вероятного кандидата на тот самый сервисный порт. А подписи RX, TX, GND только укрепили это мнение. Проверка мультиметром показала, что это UART с уровнями 3.5В.

Сервисный порт:

У меня не оказалось в тот момент под рукой переходника USB<->UART (TTL), но была в наличие плата Arduino Mega 2560, которая и выступила в роли преобразователя сигналов. На всякий случай я залил в нее пустой скетч, не задействующий UART меги (переводящий входы в высокоимпедансное состояние).

Arduino Mega 2560 в качестве USB<->UART преобразователя:

Далее сборка простенького кабеля, подключение к ПК, запуск любимой терминальной программы Tera Term. И наконец удовлетворение от отображения ожидаемых строк журнала загрузки с приглашением прервать процесс загрузки в течении 1 секунды и войти в окружение загрузчика U-Boot. В конце загрузки появляется приглашение login Linux. Но ни одна из известных пар логин/пароль ONT не подошла, поэтому следующим этапом исследования стал вход в окружение загрузчика U-Boot, который дал бы возможность управлять процессом загрузки Linux, в том числе возможно позволил бы обойти приглашение login!

Начало вывода загрузки:
BL LILAC STARTER VER-2.1.06.0-BL (Aug 26 2013 - 17:00:31)
SOC ID: BL_23570
Init DDR3.... 128MB
Attempt to boot from NAND...
Try to load bootloader from boot bank 0
Bootloader Loaded to DRAM
Cache enabled, start bootloader...
....
Enter 'Ctrl+C' to stop autoboot:  0
....

И вот бы уже расслабиться и, попивая кофе, не спеша просматривать переменные окружения U-Boot, но разработчики ONT преподнесли интересный сюрприз.

Оказалось, что комбинация Ctrl+C не работает, и войти в окружение U-Boot на этом этапе не представляется возможным! Я перепробовал множество других и даже случайных комбинаций клавиш, менял настройки терминальной программы, скорость связи. Безрезультатно. Подозревал, что не работает отправка данных с ПК (RX в ONT), но в конце процедуры загрузки, когда появлялось приглашение login Linux, ввод с клавиатуры уже работал. В общем работа за клавиатурой уже ничего не могла дать. (Думаю все-таки есть какая-то комбинация клавиш, но...)

Допил холодный кофе и обмозговал ситуацию. Эврика не заставила себя долго ждать. Во время загрузки процессор усердно читает flash-память в соответствии с этапами этой самой загрузки. Загружает в память загрузчик и его параметры до приглашения прервать загрузку и далее читает ядро системы и т.д. после одной секунды ожидания. Мысль была простой: в момент, когда на экране тикает обратный отсчет, заблокировать возможность читать данные из flash. Сработает прерывание процедуры загрузки (ошибка чтения), и будет выполнен переход в консоль U-boot для коррекции параметров загрузки (по крайней мере так я думал :) ). Из возможных вариантов реализации был выбран следующий, как наименее трудоемкий и, на мой взгляд, умеренно безопасный. Я решил закоротить ножки 43, 44 микросхемы flash после запуска загрузчика и таким образом заблокировать корректное считывание данных в момент после односекундной задержки. Что и было реализовано с помощью тонкой отвертки. Получилось с третьей попытки, когда я более уверенно стал «тыкать» отверткой.

Ножки флеша:

Вот так выглядит попытка загрузки с перемкнутыми линиями данных флеша от момента обратного отчета:
Enter 'Ctrl+C' to stop autoboot:  0
UBI: mtd1 is detached from ubi0
Creating 1 MTD partitions on "nand0":
0x000000100000-0x000000200000 : "mtd=1"
UBI: attaching mtd1 to ubi0
UBI: empty MTD device detected
UBI: create volume table (copy #1)
UBI error: ubi_scan_get_free_peb: no eraseblocks found
UBI error: ubi_init: cannot attach mtd1
UBI error: ubi_init: UBI error: cannot initialize UBI, error -28
UBI init error -28
ERROR: failed to select 'cfg' partition
Creating 1 MTD partitions on "nand0":
0x000000100000-0x000000200000 : "mtd=1"
UBI: attaching mtd1 to ubi0
UBI: empty MTD device detected
UBI: create volume table (copy #1)
UBI error: ubi_scan_get_free_peb: no eraseblocks found
UBI error: ubi_init: cannot attach mtd1
UBI error: ubi_init: UBI error: cannot initialize UBI, error -28
UBI init error -28
ERROR: failed to select 'cfg' partition
Creating 1 MTD partitions on "nand0":
0x000000100000-0x000000200000 : "mtd=1"
UBI: attaching mtd1 to ubi0
UBI: empty MTD device detected
UBI: create volume table (copy #1)
UBI error: ubi_scan_get_free_peb: no eraseblocks found
UBI error: ubi_init: cannot attach mtd1
UBI error: ubi_init: UBI error: cannot initialize UBI, error -28
UBI init error -28
ERROR: failed to select 'cfg' partition
=>

Как видим, в конце появилось приглашение командной строки U-boot. Посмотрим, что внутри (printenv):
=> printenv
bootcmd=blboot
baudrate=115200
consoledev=ttyS0
modetty0=115200n8
mtdids=nand0=nand
mtdparts=mtdparts=nand:0x100000(starter),0x100000(cfg),0x200000(uboot0),0x200000(uboot1),0x100000(cal),0x400000(linux0),0x400000(linux1),0x2800000(rootfs0),0x2800000(rootfs1),0x800000(sc_config),0x100000(bbt)
mem_reserve_low=tm=0x1400000 mc=0x400000 dsp=0x200000
EMACS_GRP_MODE=QSGMII
EMAC=EMAC0
E4_MODE=NONE
ethact=ETHMAC0
bootdelay=1
update_uboot=tftp a9d00000 u-boot.bin;blnp uboot;saveenv
update_kernel=tftp a9d00000 uImage;blnp linux;saveenv
update_rootfs=tftp a9d00000 rootfs.img;blnp rootfs;saveenv
bootargs=ubi.mtd=0 ubi.mtd=11 root=ubi0_0 rw rootfstype=ubifs console=ttyS0,115200
xx=dd
filesize=CEB800
fileaddr=A9D00000
gatewayip=192.168.1.254
netmask=255.255.255.0
ipaddr=172.21.17.188
serverip=172.21.17.155
boot_ver=1110
ethaddr=d4:21:22:xx:xx:xx
memsize=128M
stdin=serial
stdout=serial
stderr=serial
partition=nand0,0
mtddevnum=0
mtddevname=starter

Environment size: 946/262140 bytes
=>

Теперь можно подправить переменные. Увеличим паузу ожидания до 3х секунд и заменим процесс Init шеллом /bin/sh (Зачем нам login? Не, нам login не нужен). Т.е. сделаем упрощенную однопользовательскую загрузку.
Environment size: 946/262140 bytes
=> setenv bootdelay 3
=> setenv bootargs ubi.mtd=0 ubi.mtd=11 root=ubi0_0 rw rootfstype=ubifs console=ttyS0,115200 single init=/bin/sh
=> saveenv
=> printenv
...
bootargs=ubi.mtd=0 ubi.mtd=11 root=ubi0_0 rw rootfstype=ubifs console=ttyS0,115200 single init=/bin/sh
...
Environment size: 966/262140 bytes
=>

Запишем изменения (saveenv) и выполним run bootcmd или просто передернем питание ONT.
Теперь дождемся полной загрузки ONT без каких либо манипуляций отверткой.
Последние строки журнала загрузки:
UBIFS: file system size:   14450688 bytes (14112 KiB, 13 MiB, 112 LEBs)
UBIFS: journal size:       2967552 bytes (2898 KiB, 2 MiB, 23 LEBs)
UBIFS: media format:       w4/r0 (latest is w4/r0)
UBIFS: default compressor: zlib
UBIFS: reserved for root:  0 bytes (0 KiB)
Freeing unused kernel memory: 196k freed

BusyBox v1.15.3 () built-in shell (ash)
Enter 'help' for a list of built-in commands.

/bin/sh: can't access tty; job control turned off
/ #
# whoami
SuperUser

Ура, мы в rootfs.

В заключение рекомендация, как повысить права для пользователей, подключаемых по SSH.
Те, кто работал с этим ONT по SSH, видели, что там запускается не совсем традиционный shell Linux, В ONT он называется CLI. Я нашел конфигурационный файл /var/cli_pw, который содержит информацию о пользователях CLI (прежде всего SSH пользователей) и имеет синтаксис, аналогичный /etc/passwd

Не имеет смысла добавлять запись о пользователе напрямую в этот файл, т.к. каждую перезагрузку /var/cli_pw переписывается из хранящейся в другом месте конфигурации. Поэтому я использовал скрипт автозапуска /etc/rcS для добавления своего пользователя в /var/cli_pw. При каждой перезагрузке эта команда выполняется. Добавить в /etc/rcS что-то типа:
echo 'alex:$1$SERCOMM$/Yr1kjT7kcnd11coqAlgN1:0:0:root:/:/bin/sh' >> /var/cli_pw

Редактор vi в помощь.
Соответственно пользователь alex будет иметь права полного администратора при подключении по SSH к ONT.
Теперь можно вернуть переменные U-Boot в исходные значения и наслаждаться root-ованным доступом.

Комментарии (10)


  1. alexcom
    23.07.2015 13:01

    А что даёт root доступ?
    Чисто академический интерес: GPON это «одно волоконо ко всем» с разделением абонентов по времени. Возникает разумный вопрос, а возможно ли читать чужие пакеты. Оно понятно что возможно применяется шифрование, но не думаю что сильно криптойкое.


    1. Ptica79
      23.07.2015 13:31

      Ну шифрование в некоторых видах GPON применяется на аппаратном уровне. И это легко может быть AES-128 или AES-256. Так что расшифровывать за… мучаетесь.
      Тут я смотрю скорее был просто чисто академический интерес, т.к. особо вряд ли тут что поимеешь. Разве что сеть провайдера построена криво и какой-то ограничивающий функционал возложен на ONT. Тогда да, можно что-то поиметь.


      1. Disasm
        24.07.2015 00:31

        Я вот не удивлюсь, если ключ шифрования будет один на всех. Ведь его всё равно никто не узнает.[/irony]


        1. Ptica79
          25.07.2015 10:30

          Ключи шифрования легко могут формироваться динамически для каждой сессии отдельно. Например как в IPSec.


          1. Disasm
            25.07.2015 10:31

            Да никто же не спорит. Просто я не уверен, что этим кто-то вообще заморачивался, учитывая текущее состояние безопасности в роутерах.


  1. WGH
    23.07.2015 14:46

    В Arduino же 5V, а не 3.3V?


    1. Chupakabra303 Автор
      23.07.2015 15:05

      Хорошее замечание. Похоже там стоит процессор BCM68570, по которому я не смог найти информации.
      Но для некоторых Broadcom заявлено: 3.3V/2.5V CMOS with 5V tolerant I/Os, т.е. 5В не смертельны для них.
      Так что, я экстраполировал.


    1. skobkin
      27.07.2015 03:57

      В разных Arduino — разное напряжение. Есть и на 3.3.


  1. INSTE
    23.07.2015 15:01

    А какой chipset у этой штуковины? И можно ли dmesg на pastebin выложить?


  1. lorc
    24.07.2015 02:51
    +1

    Хороший способ. Я похожим методом воскрешал смартфон, на который был случайно залит кривой загрузчик. Правда в моём случае память eMMC имела BGA корпус и мне пришлось очень аккуратно засунуть под чип тонкую медную проволочку. Но способ сработал. Процессор не смог загрузиться с флеш-памяти и вывалился в загрузчик из ROM-кода. После этого стандартными утилитами Qualcomm я смог залить правильный образ.