Пользователь
46,5
рейтинг
30 сентября 2014 в 23:06

Разработка → Исследуем китайские роутеры на RT5350

Однажды, lolipop купил роутер на алиэкспрессе. Да не простой роутер, а очень компактный и дешевый, с 2 Ethernet-портами, USB, да еще и от фирмы, которая в начале 2000-х продавала свои mp3-плееры на территории РФ: Nexx WT1520H.
image
Стандартная прошивка, как и почти всегда, была скудная, и, конечно же, хотелось заменить ее на что-то более вменяемое. Но вот незадача — никаких альтернативных прошивок под роутер нет, и прошить непонятно как, т.к. никакие другие прошивки не принимались через веб-интерфейс, заголовок прошивки я раньше такой не видел, да и binwalk ничего в ней не находил, стало быть, она зашифрована:
00000000  32 33 35 30 6b d9 39 00  00 00 0e 02 00 00 00 00  |2350k.9.........|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 3e 19 53 c5  |............>.S.|
00000020  63 f5 51 9f 82 74 2d 03  2e 2f 1f 32 9c 4a 93 96  |c.Q..t-../.2.J..|
00000030  15 82 23 d0 b2 7e d7 1b  13 c3 1b 1f 06 fa f8 e0  |..#..~..........|
00000040  bb 43 9b c6 ee fc 4b 7a  e6 50 71 2b f4 f3 95 c3  |.C....Kz.Pq+....|
00000050  63 d0 a3 9c 92 2e 16 c6  19 1c 4a 93 cb 95 c3 63  |c.........J....c|
00000060  d2 9b 1a f5 2e 16 c6 19  1c 4a 93 f9 68 3c 9c 73  |.........J..h<.s|
00000070  14 63 d5 10 5e d3 6b 25  2b c2 2e 07 eb 85 73 25  |.c..^.k%+.....s%|
00000080  9b 6b c0 f2 d8 9b cf 65  56 ac a9 c2 28 61 dd 55  |.k.....eV...(a.U|
00000090  18 a4 5b e9 ba 11 93 ec  30 76 4f 40 c1 f0 7c cb  |..[.....0vO@..|.|
000000a0  36 d3 b3 93 fe 3d 6b 10  66 fa 43 39 f2 f6 c0 91  |6....=k.f.C9....|

lolipop слил данные с флешки через программатор, и мы начали в них ковыряться.

Исследование прошивки


За весь процесс инициализации оборудования и запуска программ отвечает собственный инит — /sbin/rc. Это такой комбаин покруче busybox, в котором содержится практически вся логика работы роутера:
Скрытый текст
.text:0040E758                 .globl start_services
.text:0040E758 start_services:                          # CODE XREF: main+14C8p
.text:0040E758                                          # DATA XREF: main+14C0o ...
.text:0040E758
.text:0040E758 var_10          = -0x10
.text:0040E758 var_8           = -8
.text:0040E758
.text:0040E758                 li      $gp, 0x7EBF8
.text:0040E760                 addu    $gp, $t9
.text:0040E764                 addiu   $sp, -0x20
.text:0040E768                 sw      $ra, 0x20+var_8($sp)
.text:0040E76C                 sw      $gp, 0x20+var_10($sp)
.text:0040E770                 la      $t9, start_syslog
.text:0040E774                 nop
.text:0040E778                 jalr    $t9 ; start_syslog
.text:0040E77C                 nop
.text:0040E780                 lw      $gp, 0x20+var_10($sp)
.text:0040E784                 nop
.text:0040E788                 la      $t9, start_proftpd
.text:0040E78C                 nop
.text:0040E790                 jalr    $t9 ; start_proftpd
.text:0040E794                 nop
.text:0040E798                 lw      $gp, 0x20+var_10($sp)
.text:0040E79C                 nop
.text:0040E7A0                 la      $t9, start_telnetd
.text:0040E7A4                 nop
.text:0040E7A8                 jalr    $t9 ; start_telnetd
.text:0040E7AC                 nop
.text:0040E7B0                 lw      $gp, 0x20+var_10($sp)
.text:0040E7B4                 nop
.text:0040E7B8                 la      $t9, load_smb_driver
.text:0040E7BC                 nop
.text:0040E7C0                 jalr    $t9 ; load_smb_driver
.text:0040E7C4                 nop
.text:0040E7C8                 lw      $gp, 0x20+var_10($sp)
.text:0040E7CC                 nop
.text:0040E7D0                 la      $t9, sys_led_init
.text:0040E7D4                 nop
.text:0040E7D8                 jalr    $t9 ; sys_led_init
.text:0040E7DC                 li      $a0, 2
.text:0040E7E0                 lw      $gp, 0x20+var_10($sp)
.text:0040E7E4                 nop
.text:0040E7E8                 la      $t9, start_upnp
.text:0040E7EC                 nop
.text:0040E7F0                 jalr    $t9 ; start_upnp
.text:0040E7F4                 nop
.text:0040E7F8                 lw      $gp, 0x20+var_10($sp)
.text:0040E7FC                 nop
.text:0040E800                 la      $t9, start_dhcpd
.text:0040E804                 nop
.text:0040E808                 jalr    $t9 ; start_dhcpd
.text:0040E80C                 nop
.text:0040E810                 lw      $gp, 0x20+var_10($sp)
.text:0040E814                 nop
.text:0040E818                 la      $t9, start_ntpc
.text:0040E81C                 nop
.text:0040E820                 jalr    $t9 ; start_ntpc
.text:0040E824                 nop
.text:0040E828                 lw      $gp, 0x20+var_10($sp)
.text:0040E82C                 nop
.text:0040E830                 la      $t9, start_dns
.text:0040E834                 nop
.text:0040E838                 jalr    $t9 ; start_dns
.text:0040E83C                 nop
.text:0040E840                 lw      $gp, 0x20+var_10($sp)
.text:0040E844                 nop
.text:0040E848                 la      $t9, start_ddns
.text:0040E84C                 nop
.text:0040E850                 jalr    $t9 ; start_ddns
.text:0040E854                 nop
.text:0040E858                 lw      $gp, 0x20+var_10($sp)
.text:0040E85C                 nop
.text:0040E860                 la      $t9, start_igmp_proxy
.text:0040E864                 nop
.text:0040E868                 jalr    $t9 ; start_igmp_proxy
.text:0040E86C                 nop
.text:0040E870                 lw      $gp, 0x20+var_10($sp)
.text:0040E874                 nop
.text:0040E878                 la      $t9, start_ipmac_bind
.text:0040E87C                 nop
.text:0040E880                 jalr    $t9 ; start_ipmac_bind
.text:0040E884                 nop
.text:0040E888                 lw      $gp, 0x20+var_10($sp)
.text:0040E88C                 nop
.text:0040E890                 la      $t9, start_block_ipmac
.text:0040E894                 nop
.text:0040E898                 jalr    $t9 ; start_block_ipmac
.text:0040E89C                 nop
.text:0040E8A0                 lw      $gp, 0x20+var_10($sp)
.text:0040E8A4                 nop
.text:0040E8A8                 la      $t9, start_block_port
.text:0040E8AC                 nop
.text:0040E8B0                 jalr    $t9 ; start_block_port
.text:0040E8B4                 nop
.text:0040E8B8                 lw      $gp, 0x20+var_10($sp)
.text:0040E8BC                 nop
.text:0040E8C0                 la      $t9, start_ddos
.text:0040E8C4                 nop
.text:0040E8C8                 jalr    $t9 ; start_ddos
.text:0040E8CC                 nop
.text:0040E8D0                 lw      $gp, 0x20+var_10($sp)
.text:0040E8D4                 nop
.text:0040E8D8                 la      $t9, start_monitor_rate
.text:0040E8DC                 nop
.text:0040E8E0                 jalr    $t9 ; start_monitor_rate
.text:0040E8E4                 nop
.text:0040E8E8                 lw      $gp, 0x20+var_10($sp)
.text:0040E8EC                 nop
.text:0040E8F0                 la      $t9, start_upgraded
.text:0040E8F4                 nop
.text:0040E8F8                 jalr    $t9 ; start_upgraded
.text:0040E8FC                 nop
.text:0040E900                 lw      $gp, 0x20+var_10($sp)
.text:0040E904                 nop
.text:0040E908                 la      $t9, start_conntrack_limit
.text:0040E90C                 nop
.text:0040E910                 jalr    $t9 ; start_conntrack_limit
.text:0040E914                 nop
.text:0040E918                 lw      $gp, 0x20+var_10($sp)
.text:0040E91C                 nop
.text:0040E920                 la      $t9, start_macfilter
.text:0040E924                 nop
.text:0040E928                 jalr    $t9 ; start_macfilter
.text:0040E92C                 nop
.text:0040E930                 lw      $gp, 0x20+var_10($sp)
.text:0040E934                 nop
.text:0040E938                 la      $t9, start_black_management
.text:0040E93C                 nop
.text:0040E940                 jalr    $t9 ; start_black_management
.text:0040E944                 nop
.text:0040E948                 lw      $gp, 0x20+var_10($sp)
.text:0040E94C                 nop
.text:0040E950                 la      $t9, start_wlan_wps
.text:0040E954                 nop
.text:0040E958                 jalr    $t9 ; start_wlan_wps
.text:0040E95C                 nop
.text:0040E960                 lw      $gp, 0x20+var_10($sp)
.text:0040E964                 nop
.text:0040E968                 la      $t9, start_trakerurl
.text:0040E96C                 nop
.text:0040E970                 jalr    $t9 ; start_trakerurl
.text:0040E974                 nop
.text:0040E978                 lw      $gp, 0x20+var_10($sp)
.text:0040E97C                 lw      $ra, 0x20+var_8($sp)
.text:0040E980                 move    $v0, $zero
.text:0040E984                 jr      $ra
.text:0040E988                 addiu   $sp, 0x20
.text:0040E988  # End of function start_services

Путем дедукции и nmap было выяснено, что на роутере запущен telnetd, который доступен через WAN-интерфейс! Вот это дела! Однако, залогиниться не получалось ни под пользователем root, ни под пользователем admin.
В качестве telnetd выступает busybox. Давайте заглянем в него (функция login_main):

image

Т-а-а-к, теперь пускает до ввода пароля, однако стандартный пароль «admin» не принимается. Интересно. Смотрим дальше:

image

Вот так дела! Логин nexxadmin, пароль y1n2inc.com0755, с доступом через WAN.
В прошивке есть mtd_write, так что ничто не мешает нам уже сейчас залить OpenWRT прямо на флеш, что и было сделано lolipop, но все же было интересно разреверсить алгоритм шифрования. К сожалению, моих навыков ассемблирования MIPS в голове явно недостаточно, и я испытывал большой дискомфорт только смотря на весь этот код, поэтому я заказал себе такой же роутер, и, о чудо, через 2 месяца он был у меня.

Продолжаем исследование


image
Подключен только RX, земля общая с лаптопом по USB-питанию.

Обновить роутер можно как через веб-интерфейс, так и по tftp (который, опять же, слушает WAN!). Tftp-демон (upgraded из rc), похоже, сломан, т.к. обновление через него не приводило к обновлению прошивки в роутере, хотя и никаких ошибок не было. Следует заметить, что обновление прошивки по tftp требует аутентификации с таким же паролем, как и на веб-интерфейс, так что тяжело назвать его backdoor, скорее просто неправильно сконфигурированный сервис.

Я решил исследовать обновление прошивки именно через tftp.
Простое обновление через стандартный tftp-клиент приводило к «Upgrade not possible: Incorrect Password» от upgraded. Давайте заглянем в него:

image

Обычные клиенты, похоже, не умеют отправлять tftp-опции, поэтому я скачал python-библиотеку tftpy, модифицировал одну строку в файле-примере клиента, и все заработало:
--- tftpy_client.py     2014-09-30 21:48:57.375550027 +0400
+++ tftpy_client.py_    2014-09-30 21:48:50.355520342 +0400
@@ -83,7 +83,7 @@
 
     progresshook = Progress(tftpy.log.info).progresshook
 
-    tftp_options = {}
+    tftp_options = {'admin': ''}
     if options.blksize:
         tftp_options['blksize'] = int(options.blksize)
     if options.tsize:

Отлично! Теперь осталось разобраться с шифрованием прошивки. В rc есть функция decrypto, выглядит она как-то так:

image

Найти ключ в статике я не смог, поэтому я приступил к отладке. Чтобы отлаживать что-то на устройстве, разумеется, нужно сначала собрать отладчик. linux_server от IDA Pro не собирают под MIPS (а роутер построен именно на этой архитектуре), так что нужно было как-то собрать gdbserver под роутер. В роутере используется старое-престарое ядро 2.6.21 с uClibc 0.9.28. Первым делом, я решил воспользоваться buildroot, чтобы он и toolchain с uClibc собрал, и gdbserver статически. Отлично, все собралось, вроде запускается, однако, при отладке через IDA Pro, сервер постоянно падает, какие-то странные ошибки ptrace выдает, ну, думаю, надо пересобрать его с заголовками от ядра 2.6.21 и с uClibc 0.9.28, т.к. uClibc никогда не обещал бинарную совместимость. В интернете нашелся Ralink SDK с нужной версией ядра и uClibc. GDBServer, собранный этим toolchain, вел себя один-в-один как старый. К сожалению, в IDA Pro имеется какая-то несовместимость с gdbserver, который запущен на MIPS. К счастью, gdbserver замечательно работает с обычным gdb, собранным под mips (./configure --target mipsel-linux).
Я очень редко что-то отлаживаю в голом gdb, а удобные надстройки и скрипты для него работают только с x86 и ARM. К счастью, я нашел репозиторий с .gdbinit для MIPS, и удобство отладки заметно увеличилось. Все происходило как-то так:

image

В конечном счете, ключ был найден всего несколькими строчками выше, чего и следовало ожидать:

image

После того, как я написал скрипт для расшифровки прошивки, lolipop прислал мне еще одну с похожим заголовком, но от другого роутера. Первые 4 символа (magic) у нее были R3G2. Поискав эту строку в Google, обнаружилось, что все уже сделано до нас, еще аж в начале 2013 года :(
В любой расшифрованной прошивке есть строка Linux Kernel Image, которая находится всегда по одному и тому же смещению. Эта строка длиннее, чем XOR-ключ, а это значит, что нам не нужно его доставать из rc у разных производителей, а мы можем просто «найти» его из этой строки.

Но недостаточно только распаковать прошивку, нужно ее еще и запаковать, чтобы была возможность обновить ее через веб-интерфейс. Как оказалось, в функции обновления присутствует подсчет контрольной суммы прошивки:

image

Что выглядит на C примерно вот так:
    for (i=0; i<f.len-1; i+=2)
    {
           checksum += (data[i+1] << 8 ) | data[i];
    }
    
    if (i < f.len)
    {
          checksum += data[i];
          printf("Got odd byte: 0x%02X\n", data[i]);
          i+=1;
    }

    checksum = checksum + (checksum >> 16) + 0xffff;
    checksum = ~(checksum + (checksum >> 16)) & 0xffff;
    printf("Checksum = 0x%04X\n", checksum);
    
    data[i] = checksum & 0xFF;
    data[i+1] = (checksum >> 8) & 0xFF;

Теперь у нас есть все необходимое, чтобы заливать любые прошивки через веб-интерфейс.

Ссылки

Расшифровывалка
Зашифровывалка

Заключение

Данный способ подходит для многих устройств на SoC RT5350. Вероятно, это какой-то штатный способ обновления прошивки из SDK.
Прошивки c backdoor и такого низкого качества вынуждают потребителя искать нормально работающий софт для своего устройства. lolipop добавил поддержку данного устройства в OpenWRT, и скоро ее добавят в Trunk. А еще, вчера наконец-то вышел релиз OpenWRT Barrier Breaker! (анонса на сайте еще нет).
Так и живем.
@ValdikSS
карма
622,0
рейтинг 46,5
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

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

  • +2
    А telnet-backdoor есть только конкретно в Nexx, а не во всех роутерах на RT5350, правильно ли я понимаю?
    • +3
      Да. Он прям на всем модельном ряду Nexx.
    • 0
      А вот tftpd-бэкдор есть не только у nexx, но и у многих других.
  • +1
    Оппа-па, оказывается, на ramips допилили OpenWRT.
    И как оно?
    Аппаратный NAT, я так понимаю, не работает. А как софтовый? Тянет 100 мбит на RT305x?
    • +1
      Его уже довольно давно допилили.
      Если надо, могу потестировать, но на 5350. Думаю, 100 мегабит-то он пережует без инкапсуляции, а как выше тестировать — не знаю, порты-то 100-мегабитные.
      • 0
        Меня именно без инкапсуляции и интересует.
        Я попробую на своей Tenda W306R — там RT3052. Консоль у меня, если что, всё равно там припаяна.

        Спасибо.
        • 0
          Аппаратный предположительно можеть работать на неофициальном китайском форке openwrt, downloads.openwrt.org.cn/PandoraBox/ralink/rt305x/packages/.
          И еще есть интересный проект — симбиоз юзерспейса openwrt и ядра и модулей от ралинк от китайского производителя vonets.com/products.asp?ClassID=96, но только для новых 7620.
        • +1
          О! Отпишитесь, пожалуйста, как чего, по итогам. А то я паре человек устанавливал 306-е и у самого 316-я. Любопытно.
          • 0
            Отписываюсь.

            Плачу горькими слезами — NAT-ит через кабель 50 мбит/с, во время загрузки ssh-консоль роутера еле двигается. Тогда как Wive-RTNL NAT-ит всю сотню.
            Как это не прискорбно — пришлось возвращаться на Wive.
  • +2
    Хорошая работа.
  • +1
    А кто может посоветовать продающуюся в РФ такого же типа небольшую коробочку с двумя LAN и прошивающуюся на openwrt? Чтобы получала по dhcp снаружи адрес, цеплялась к нашему openvpn серверу и весь трафик изнутри прокидывала через vpn. Можно даже без ната!

    Эта всем устраивает, кроме aliexpress — таможня большую партию не пропустит…
    • 0
      Если партия реально большая — почему не купить на Alibaba? Там будет куда дешевле за счёт опта. Возможно, разница как раз покроет растаможку.
      • 0
        увы, не настолько, а то конечно так бы и сделали…
        • +1
          Тут на Хабре был пост, в котором посредник заявляет о том, что может привезти и коммерческую партию с хитрым способом растаможки на юр. лицо. Можете попробовать.
          • 0
            Полно таких посредников через Казахстан возят… Стремно очень.
            • 0
              Ну я возил через одного такого пару раз — все ок было.
              • 0
                Так это же как в анекдоте про поручика Ржевского — «Можно и по морде, конечно, но в основном — впендюриваю!»(с) :-)
    • +1
      Возможно, NetGear WNR612v2
      habrahabr.ru/post/189720/
      wiki.openwrt.org/toh/netgear/wnr612v2

      И TP-Link TL-WR720N
      wiki.openwrt.org/toh/tp-link/tl-wr720n

      И D-Link DIR-456

      Обязательно 2 LAN?
      NETGEAR PR2000 (Возможно, перепрошивается)
      Buffalo WLAE-AG300N
      TP-LINK TL-WR710N
  • +2
    У MikroTik есть чудесная штука mAP цена вот только $45, но зато RouterOS на борту…
  • 0
    Красавцы!
  • 0
    Не понятно, как вам удалось вытащить прошивку в открытом виде.
    Еще лет 15 назад в микропроцессорах был спец флаг при программировании, который защищал от чтения содержимого.
    Или взяли китайский firmware, расшифровали, а после уже ковыряли ID'ой?
    • +4
      Выпаяли флешку, воткнули в программатор, прочитали.
    • 0
      Обычно в роутерах контроллер использует внешнюю память, к которой он обращается по SPI интерфейсу.
    • 0
      Это в микроконтроллерах со встроенной flash есть биты защиты.
      В микросхемах с внешней памятью только сравнительно недавно появилась возможность прошить ключ шифрования, зачастую однократно. В таком случае программатор не помог бы.
    • 0
      Там обычная serial flash NOR типа Winbond какого-нибудь. 450р для нее программатор стоит.
  • 0
    del
  • 0
    Правильно ли я понял, прошивка зашифрованна лишь при передаче через интернет, а на флешке была в открытом виде?
    Имена портам и переменным вы сами присваивали или ida подтянула?
    • 0
      Правильно.
      Имена функций были частично видны, имена переменных я задавал сам.
      • 0
        Здорово что имена хоть часть видны, я давече ковырял прошивку магнитолы Ford на tms470 arm7tdmi в статике только общие аспекты смог понять, ядро запроса кода разблокировки так и не нашел, функции и переменные безымянны… возможно существует способ прикрутить header от процессора к Иде, что бы хотябы порты переименовались, но я незнаком с ним.
  • 0
    То есть, чтобы установить на девайс OpenWRT нужно взять OpenWRT, зашифровать и передать по tftp?
    • 0
      При загрузке по tftp образ шифровать не требуется. Достаточно выставить у себя адрес 192.168.1.55, поднять tftp сервер, положить в корень файл с именем вида mac-адрес девайса без разделителей и в нижнем регистре и подать питание на девайс с зажатой кнопкой reset. Можно предварительно запустить wireshark или любой другой сетевой сниффер, ибо у разных моделей могут быть записаны различные IP адреса tftp сервера. И ещё неплохо бы убедиться, что в роутере стоит флеш подходящего под загружаемый образ размера.
      • 0
        Спасибо, конечно, за ответ )
        Я уже успел угробить 1520, подпаять к нему проводки и восстановить из консоли восстановления

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.