Распаковка прошивки кабельных модемов

Распаковка прошивки кабельных модемов

Взлом кабельных модемов был очень популярен в начале 2000-х. Люди вроде DerEngel и Isabella из TCNiSO провели много исследований по данной теме. Кроме того, ей были посвящены выступления bitemytaco (R.I.P.) и BlakeSelf на конференциях DEFCON 16 и DEFCON 18, в ходе которых было сказано очень много полезного.

Автор: Bernardo Rodrigues

Взлом кабельных модемов был очень популярен в начале 2000-х. Люди вроде DerEngel и Isabella из TCNiSO провели много исследований по данной теме. Кроме того, ей были посвящены выступления bitemytaco (R.I.P.) и BlakeSelf на конференциях DEFCON 16 и DEFCON 18, в ходе которых было сказано очень много полезного.

Защитить кабельные модемы сложнее, чем встроенные устройства, так как в большинстве случаев, вы не можете управлять обновлениями своего устройства/прошивки. Как правило, это контролируется вашим провайдером. Кроме того, большинство кабельных модемов имеют достаточно ограниченный интерфейс для управления, а команды передаются через SNMP.

Прошивка кабельных модемов.

Как правило, для кабельных модемов существует три варианта прошивки:

  • Подписанная и сжатая (PKCS#7 & binary)
  • Сжатая бинарная
  • Образ RAM-дампа

Вы можете сами создать образ прошивки с помощью JTAG или, например, проанализировать подключение во время обновления. Я являюсь большим фанатом binwalk’а и никогда не понимал, почему он не позволяет распаковывать прошивку популярных кабельных модемов Broadcom, поэтому я решил исправить это.

Распаковка прошивки.

В своей работе я использовал Cisco DPC3925, широко распространенный у нас, в Бразилии. Cisco DPC3925 использует чипсет BCM3380, и имеет конфигурацию памяти 16MB Flash x 64MB DRAM.

В сжатом виде прошивка занимает около 4 МБ. Использование строк не помогло, binwalk v1.2.1 (без каких-либо дополнительных параметров) не распознал прошивку.

Стоит отметить, что много полезной информации можно получить из официальных источников: руководств пользователя, технического описания, информации по лицензированию, а также из открытой информации по отказу от ответственности для данного продукта. Найти информацию на домашней странице Cisco у меня не получилось, но в разделе уведомлений об авторских правах говорится, что продукт использует LZMA SDK 4.21.

Таким образом, нам известно, что прошивка, вероятно, упакована с помощью LZMA, нужно определить, как распаковать ее. Ключ –i в Binwalk при использовании во время сканирования позволяет отображать недействительные результаты, и возможно, это станет нашей зацепкой:

Я не смог найти хорошей документации по LZMA-заголовку. Есть неплохие ресурсы, вроде lzma-purejs Github, также можете просмотреть сигнатуры magic file binwalk (devttys0 сделал самую сложную работу за нас).

Offset Size Description
0 1 lc, lp and pb in encoded form
1 4 dictSize (little endian)
5 8 uncompressed size (little endian)

Загрузчик в начале flash области содержит всю необходимую для загрузки прошивки информацию. Для извлечения прошивки и последующего помещения ее в DRAM используется распаковщик.

Смещение 0x677 – отличный кандидат, так как оно расположено в начале файла, и заголовок, находящийся по нему, очень похож на искомый. 5D 00 00 00 01 определяет -8 уровень сжатия LZMA, и следующие 64 бита должны представлять собой размер несжатых данных (при порядке записи от младшего к старшему – little endian).

Ясно, что 64 байта, следующие за заголовком, (00 20 20 0E 3A 28 AB EF) не являются размером несжатых данных (2898643604054482944 байт). Они представляют размер сжатых данных, что не позволяет binwalk’у и 7zr распаковать их.

В данной ситуации нам просто нужно добавить несколько дополнительных байтов к заголовку, тогда 7zr сможет распознать и извлечь данные. Сейчас мы не знаем размер несжатых данных, но хорошая новость в том, что мы можем указать достаточно большое значение, благодаря чему 7zr сможет распаковать данные (несмотря на преждевременное достижение конца файла). Давайте укажем 268435456 байт (256 МБ), приведем их к формату little endian (00 00 00 10 00 00 00 00) и добивам это к изначальному LZMA-заголовку. Новый заголовок должен быть похожим на 5D 00 00 00 01 00 00 00 10 00 00 00 00 00 20 20…

Я не мог упустить возможность взглянуть на API у binwalk и написать простенький распаковщик lzma-unpacker.py:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

#!/usr/bin/python
 
import os, sys
from binwalk import Binwalk
 
def lzma_callback(offset, results):
    for result in results:
        if result['description'].startswith('LZMA compressed data, properties: 0x5D'):
            with open(sys.argv[1]) as f:
                f.seek(result['offset'])
                lzma_header = f.read(5)
                uncompressed_size = '\x00\x00\x00\x10\x00\x00\x00\x00'
                data = f.read()
                output = open(sys.argv[1]+'.lzma', 'w')
                output.write(lzma_header+uncompressed_size+data)
                f.close()
 
if __name__ == '__main__':
    nargs = len(sys.argv)
 
    if nargs != 2:
        print '\
  \nLZMA Unpacker: Extract LZMA sections from firmware images\n\
  \nTested with the following Cable Modems:\n\
  - Cisco DPC3925, DPC2434\n\
  - Motorola SB5100, SB5101, SVG6582, SVG1202\n\
  - Thomson ACG905, DCM425, DHG534, DHG544, DWG850, DWG874\n\
  - Webstar DPC2203\n\
  \nBernardo Rodrigues, http://w00tsec.blogspot.com\n\
  \nUsage: %s firmware_image.bin' % os.path.basename(sys.argv[0])+'\n'
 
    else:
        with Binwalk() as bw:
            try:
                with open(sys.argv[1], 'rb'):
                    bw.display.header()
                    bw.scan(sys.argv[1], callback=lzma_callback, show_invalid_results=True)
                    try:
                        with open(sys.argv[1]+'.lzma', 'rb'):
                            bw.extractor.add_rule('lzma:7z:7zr e -y %e')
                            bw.scan(sys.argv[1]+'.lzma', callback=bw.display.results)
                    except Exception:
                        print 'LZMA 0x5D signature not found'
                        exit
            except IOError:
                print 'File not found: '+sys.argv[1]

Код станет ненужным через пару дней, потому что, скорее всего, Binwalk включит выполняемые им действия в свой состав (возможно, через плагин).

Данные успешно извлечены, их размер составил 21982740 байт. Если бы мы заменили размер несжатых данных LZMA заголовка на данное значение в формате little endian (14 6E 4F 01 00 00 00 00), 7zr не жаловался бы на целостность файла.

В большинстве кабельных модемов Broadcom использовалась подобная схема сжатия, в том числе в модемах разных вендоров. Скрипт был протестирован и работает для следующих модемов:

- Cisco DPC3925, DPC2434
- Motorola SB5100, SB5101, SVG6582, SVG1202
- Thomson ACG905, DCM425, DHG534, DHG544, DWG850, DWG874
- Webstar DPC2203

Анализ прошивки.

Теперь, когда мы успешно распаковали прошивку, можно попытаться проделать пару интересных вещей:

- найти пароли по умолчанию

-найти бэкдоры

-провести пен-тестирование web приложения

- определить баги вашего устройства и отправить их NMAP

- найти похожие устройства с помощью scans.io

- отправить HD Moore’у копию прошивки и ждать CVE спама

Ваша приватность умирает красиво, но мы можем спасти её.

Присоединяйтесь к нам!