Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 124, АПРЕЛЬ 2009 г.

Имплантация Cisco. Модифицирование прошивки маршрутизатора

Евгений «ShadOS» Хабаров (shados@mail.ru)




Приветствую, дорогой друг! Сегодня мы будем дарить вторую молодость (а может даже и жизнь) старым маршрутизаторам Cisco, практически не нарушая лицензионного соглашения. Пусть этот хакерский метод достаточно прост, но от этого он не становится менее интересным. Имя ему – «бинарный патчинг».

Сразу к делу. Исходные данные следующие: старенькая кошка Cisco 2611 с двумя Ethernet-портами, 64 Мб RAM и 16 Мб на Flash. Это максимально возможные параметры, поддерживаемые платформой (читай – увеличить объем DRAM памяти и flash не получится из-за отсутствия в природе комплектующих больших объемов). Исходя из данных Cisco IOS Feature Navigator (tools.cisco.com/ITDIT/CFN/jsp/index.jsp), последней версией IOS для этого маршрутизатора является 12.3(26) – вполне естественно для столь старого продукта (End-of-Sale - апрель 2003, End-of-Life – апрель 2008). Хочется получить только все самое последнее и новое, а все самое новое и вкусное доступно только в версии 12.4 (точнее 12.4T).

Посыл номер два, или дополнительные исходные данные таковы: если внимательно следить за модельным рядом маршрутизаторов Cisco или просто ознакомиться с информацией о продуктах на официальном сайте, то можно обнаружить, что серия 2600 включает в себя, например, маршрутизаторы 2611XM. Отличается эта серия от своего предшественника незначительно:

  • Максимальный объем flash-памяти увеличен до 48 MB (в 2611 — 16 MB)
  • Максимальный объем SDRAM-памяти увеличен до 128 MB (в 2611 — 64 MB)
  • Интегрированные 10/100 Fast Ethernet порты (в 2611 — 10 Мбит/c Ethernet)

Для такой кошки Cisco IOS Feature Navigator сообщит, что последний IOS имеет версию 12.4(23). Системные требования для IOS 12.4(21) с набором Enterprise Base или Advanced Security составляют 128 MB DRAM и 32 MB flash. Конечно, у нас нет 128 MB памяти, но попытка не пытка, да и пропускная способность портов у нас невысокая. Это позволяет сделать предположение, что ОС можно запустить на моем устройстве. Осталось превратить теорию в практику.

Extended, или Что хотим получить

Идея проста - загнать бинарный образ операционной системы Cisco IOS 12.4(21) с набором фьючерсов Enterprise Base на старенький маршрутизатор 2611 с исходными данными, представленными выше. В дальнейшем – использовать как тестовый стенд, ибо 10-мегабитные интерфейсы ограничивают его применение в дикой природе, или, как говорится, in production. С тем же успехом устройство может надежно служить файрволом корпоративной сети взамен какого-нибудь PIX (если, конечно, достаточно пропускной способности в 10 Мбит), но тогда встает вопрос — а есть ли такой функционал, который может потребоваться в IOS 12.4, но которого нет в 12.3? За подсказкой вновь отправляю к Cisco IOS Feature Navigator (tools.cisco.com/ITDIT/CFN/Dispatch). Утилита сравнения образов тебе в помощь, но ответ, скорее всего, - «нет». Отсюда вывод — не стоит меня корить в малой практичности, так как изначально статья в большей степени исследовательская (just for fun).
У меня не возникло бы потребности писать статью, если бы не две небольших проблемы. О первой я уже упомянул — это объем DRAM памяти. К сожалению, я не повелитель паяльника и вольтметра, так что здесь поделать ничего не можем. Стоит только надеяться, что ОС не уйдет в core в самый ответственный момент из-за недостатка памяти. Вторая проблема, которая застигла меня врасплох – это размер самого образа IOS 12.4 и тот факт, что он не помещается на флеш объемом 16 МB. И неудивительно: файл образа – c2600-entbasek9-mz.124-9.T1.bin – который я взял для эксперимента, занимает 16,4 MB, то есть 17 257 364 байт. Даже если стереть флеш с опцией no-squeeze-reserve-space (командой erase /no-squeeze-reserve-space flash:), это нам не поможет. Хотя, в свое время, для образа c2600-ik9o3s3-mz.123-13.bin было решением проблемы (этот образ чуть меньше размера самой флеш, и для его загрузки требуется отформатировать ее с опцией, запрещающей резервировать свободное место).

Что делать? Бежать!

Решения здесь может быть два – либо грузиться с tftp, что не всегда удобно, либо же взломать образ так, чтобы размер стал меньше. Грубо говоря, перепаковать его (собственно, это и было отчасти сделано).

Посылом номер три стал эмулятор Dynamips. Причем он тут? Именно он натолкнул меня на мысль о перепаковке образа. Если взглянуть на раздел «How to use?» на официальном сайте проекта (www.ipflow.utc.fr/index.php/Cisco_7200_Simulator), то можно обнаружить, что эмулятор использует распакованные образы для ускорения загрузки:


<skipped>
To boot quickly, the preferred method is to decompress the IOS image with the "unzip" utility. It avoids to run the self-decompressing process in the emulator.
chris@portchris2:~/dynamips-0.2.5$ unzip -p c7200-advipservicesk9-mz.124-9.T.bin > image.bin
warning [c7200-advipservicesk9-mz.124-9.T.bin]: 27904 extra bytes at beginning or within zipfile
(attempting to process anyway)
chris@portchris2:~/dynamips-0.2.5$ file image.bin
image.bin: ELF 32-bit MSB executable, cisco 7200, version 1 (SYSV), statically linked, stripped
You can ignore the warning, unzip has just skipped the self-decompressing code at the beginning of the image.
Now, you can boot the imagе
<skipped>

Если есть запакованный образ, то можно попытаться использовать более оптимальные параметры сжатия, которые позволят поместить образ на флеш. Обращаю внимание на важную деталь — так как мы не собираемся переписывать самораспаковывающийся код, то есть заниматься дизассемблированием (да и ассемблер под 32-битные процессоры PowerPC я не знаю), то сам алгоритм сжатия менять мы не сможем. Самораспаковывающаяся часть просто не сможет распаковать архивы, сжатые другими методами. По поводу используемого в образе алгоритма сжатия – можно взглянуть вот сюда: Cisco IOS Configuration Fundamentals Configuration Guide, Release 12.4 - Loading and Managing System Images, пункт Image Naming Conventions. Поле «тип» в имени образа как раз отвечает за его характеристики:

  • f - The image runs from flash memory
  • m - The image runs from RAM
  • r - The image runs from ROM
  • l - The image is relocatable
  • z - The image is zip compressed
  • x -The image is mzip compressed

В нашем случае образ имеет тип mz – работает в памяти и запакован как раз в zip-архив. Убедиться в этом просто — большинство архиваторов (WinZIP, WinRAR, 7zip) с легкостью открывают его и распаковывают.

Упаковка

Не мудрствуя лукаво, пытаемся перепаковать архив заново с максимально возможной степенью сжатия. Сразу же отмечаем, что используемый метод — deflate и изменить его не получится. Я использовал четыре архиватора, чтобы сравнить их и получил такой результат:

7-zip 4.65 со следующими параметрами:

  • Формат архива — zip
  • Уровень сжатия — Ультра
  • Метод сжатия — Deflate
  • Размер словаря — 32КB
  • Размер слова — 258

В результате был получен архив: 15,7 MB (16 489 764 bytes). WinZIP 11.2 при использовании улучшенного метода Deflate выдал файл размером 16,0 MB (16 803 634 bytes). WinRAR 3.80 формат архива — zip с наилучшими параметрами сжатия: 16,3 MB (17131 353 bytes). PKZIP 9.00 от создателей формата совсем подвел, и по методу Deflate с максимальным сжатием произвел файл размером 16,3 MB (17 094 474 bytes).

Итогом моего небольшого сравнительного тестирования стал выбор для экспериментов архива, как нетрудно догадаться, созданного 7zip.

Теория (интеграции нового архива)

Далее требуется сей архив поместить вместо оригинального образа. Чтобы проделать это, нам понадобится шестнадцатеричный редактор типа WinHex, HT Editor или hview. Я предпочитаю WinHex, но понадобится еще и HT, чуть позже объясню почему.

Как ты можешь видеть на скриншоте, бинарный образ IOS, скорее всего, есть не что иное, как исполняемый файл в формате ELF (Executable and Linkable Formate). ELF-формат является основным исполняемым файлом в *nix-like системах, поэтому неудивительно встретить его здесь. По ELF-формату существует четкая спецификация, последняя версия которой 1.2, однако для наших целей будет достаточно, например, заголовочного файла из состава libc - elf.h. Обычный бинарный ELF-файл представляет собой структуру вида:

ELF Header
Program Header Table (optional)
Section 1
Section 2

Section n
Section Header Table

Не углубляясь в описание (и дабы не повторяться), отправляю тебя к спецификации. Так как весь процесс исследования я проводил в MS Windows, то пришлось искать замену утилите readelf из состава binutils. Подходящим вариантом оказался шестнадцатеричный редактор HT (hte.sf.net), который умеет читать и модифицировать структуры данных исполняемых файлов ELF. При попытке открыть подопытный образ c2600-entbasek9-mz.124-9.T1.bin, HT сразу меня обругал, что и привлекло мое внимание. Обратимся к elf.h. Структура данных, отвечающая за ELF-заголовок, выглядит так:

typedef struct {
Elf_Char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;

В нашем случае поле e_machine имеет значение 0x002b или 43, что соответствует процессору SPARC v9:

#define EM_SPARCV9 43 /* SPARC v9 64-bit */

Но нам известно, что маршрутизатор 2611 использует процессор Motorolla MPC860, значит, поле должно иметь значение 0x0014, – что соответствует:

#define EM_PPC 20 /* PowerPC */

Скорее всего, это простейшая защита от дизассемблирования образа. Нам это не сильно помешает. С помощью F6 открываем режим просмотра elf/header. Из него становятся известны следующие подробности:

  • elf header size 0x34
  • program header entry size 0x20
  • program header count 1
  • section header entry size 0x28
  • section header count 6

Что, в сумме, дает размер 52+32+6*40=324 или 0x144, то есть, в файле всего 6 секций (соответственно, 6 заголовков секций) и 1 заголовок программы. Вероятнее всего, одна из секций предназначена для хранения архива с исполняемым образом IOS. Эту секцию можно вычислить либо по размеру (логично, что ее размер должен быть максимальным), либо по типу секции. Заголовок таблицы секций можно просмотреть, нажав <F6> и выбрав elf/section headers, но для начала обратимся к описанию секции:

typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;

Поле sh_type и будет отвечать за искомый тип. К сожалению, здесь меня ждал облом, – большинство секций имело тип SHT_PROGBITS, предназначенный для секций, значение которых определяется самой программой. Однако четвертая секция имела тип, отличный от предыдущих, и значение 0x00000007 (секция предназначена для каких-то программных заметок). Первая (нулевая) секция также имеет отличный от предыдущих тип (SHT_NULL). Исходя из этого, ясно, что она пустая и ни с чем не ассоциирована. В итоге, приходится искать секцию с максимальным размером (поле sh_size). Это – секция за номером пять, ее размер 0x1070e7c или 17239676 байт. Вернемся к hex-виду (<F6> - hex) и перейдем по смещению (поле sh_offset) с помощью <F5>.

Что же мы здесь видим? Где наш архив, который должен начинаться с сигнатуры PK, а точнее, если следовать спецификации PKZIP-формата (pkware.com/documents/casestudies/APPNOTE.TXT), – с 0x04034b50 в обратном порядке? Как ни странно, эта сигнатура обнаруживается на 22 байта позже. А если хорошо присмотреться, то отказывается, что сразу за значением 0xFEEDFACE идет размер распакованного образа 0x02AED904. Внимательно поискав в Сети, можно наткнуться на информацию из книги Cisco Networks Hacking Exposed издательства McGraw Hill/Osborne.

Наши русские парни Andrew A. Vladimirov, Konstantin V. Gavrilenko, Janis N. Vizulis and Andrei A. Mikhailovsky еще в 2006 году занимались разработкой бинарного патчинга IOS 12.3(6). Им удалось выяснить, что после магического значения 0xFEEDFACE идут последовательно uncompressed image size, compressed image size, compressed image checksum, uncompressed image checksum. Товарищам также стало известно, что алгоритм вычисления контрольной суммы представляет собой модифицированный алгоритм контрольной суммы в интернете. К счастью, нам не придется ничего вычислять — проверено на практике, что маршрутизатор сам скажет, какое значение должно иметь это поле, если, конечно, подсчитанная контрольная сумма и записанная в соответствующем поле не совпадут:

Error : compressed image checksum is incorrect 0xB99D8823
Expected a checksum of 0xF6F69877

*** System received a Software forced crash ***
signal= 0x17, code= 0x5, context= 0x800805f0
PC = 0x0, Vector = 0x0, SP = 0x0

Практика (интеграции нового архива)

Перейдем к активным действиям. Для начала вырезаем из файла старую четвертую секцию, содержащую zip-архив, – за исключением 20 байт, начиная с магического значения 0xFEEDFACE до сигнатуры zip (то есть, со смещения 0x44F8 по смещение 0x1075360 + 0x44F8). Затем по смещению 0x44F8 вставляем новый архив.
Соединим всю известную нам информацию воедино. Размер старой секции (№5), содержащей архив с образом IOS, загружаемым в память, – 0x1070e7c или 17239676 (включая 20 байт с 0xFEEDFACE по 0x504B0304). Размер новой секции, содержащей архив, – 0xFB9D38 или 16489784 (включая те же 20 байт). Разница между старым и новым значением составит 0xB7158 — 749912. То есть, смещение четвертой секции, физически расположенной в файле после пятой секции, требуется изменить с 0x1075360 на 0xFBE208! Старые значения после магической записи 0xFEEDFACE:

unpacked image size: 0x02AED904 45013252
packed image size: 0x01070E66 17239654 (разница с размером 5й секции - на 22 байта меньше)
packed image checksum: 0xB58BE139
unpacked image checksum: 0xA29D4F6E
затем идет сигнатура: 0x504B0304

Новые значения после магической записи 0xFEEDFACE:

unpacked image size: 0x02AED904 (остался тот же)
packed image size: 0x00FB9D22 16489762 (разница с размером 5й секции - на 22 байта меньше)
packed image checksum: нам неизвестна и можно заменить на что-нибудь приметное, типа 0x48000000
unpacked image checksum: 0xA29D4F6E (остался тот же)

Новую контрольную сумму, как я уже говорил, сообщит сам маршрутизатор. После всех манипуляций конечный образ был получен, но его размер меня не впечатлил. По сравнению с изначальным размером 16,4 MB (17257364 bytes) я получил всего лишь 15,7 MB (16507472 bytes). Разница, которую я уже посчитал выше, составила 749912 байт. Конечно, это позволит загрузить образ на flash, но, скорее всего, придется применять опцию /no-squeeze-reserve-space. Когда при копировании маршрутизатор запросит повторное стирание flash, подтверждать действие не нужно.

Естественно, такая ситуация была бы только в том случае, если образ был бы сформирован правильно. Поэтому я не стал спешить и для загрузки образа зашел в режим rommon по Ctrl+Break. И – со своего компьютера загрузил образ по tftp напрямую в RAM:

rommon 1>tftpdnld -r

После загрузки маршрутизатор я сказал:

TFTP flash copy: Error, image size (16507470) mismatches netsize (16507472).

Оказалось, что при редактировании размера 5й секции я ошибся на 2 байта (те самые 20 байт с 0xFEEDFACE + 2). После второй попытки загрузки выяснилось, что контрольная сумма запакованного образа — 0xB0257B0D:

Error : compressed image checksum is incorrect 0xB99D8823
Expected a checksum of 0x48000000

*** System received a Software forced crash ***
signal= 0x17, code= 0x5, context= 0x800805f0
PC = 0x0, Vector = 0x0, SP = 0x0

Корректируем соответствующее поле после 0xFEEDFACE (загружаем файл в HT по <F3>, переходим по смещению с помощью <F5> и редактируем по <F4>, не забывая сохраняться по <F2>). Затем снова грузимся.

rommon 4>reset -s

Дальше все нормально, однако затем IOS вываливается и отказывается работать по причине недостатка памяти:

Никогда не сдавайся

Я не расстроился и решил взяться за другой образ — c2600-advsecurityk9-mz.124-21.bin. После аналогичных манипуляций с байтами, даже при использовании 128-битного слова в 7zip, размер составил 15947076 (против изначальных 16635336), что позволило загрузить его во flash. Помимо прочего, этот образ уже не ругался на недостаток памяти RAM и прекрасно чувствовал себя на этой платформе:

router#show version
Cisco IOS Software, C2600 Software (C2600-ADVSECURITYK9-M), Version 12.4(21), RELEASE SOFTWARE (fc1)

<skiped>

router#show memory summary
Head Total(b) Used(b) Free(b) Lowest(b) Largest(b)
Processor 82A44240 20244772 8718640 11526132 10171028 10098348
I/O 3CA3400 3525632 1650536 1875096 1875096 1875068

<skiped>

router#show flash:

System flash directory:
File Length Name/status
1 15947076 c2600-advsecurityk9-mz.124-21-shad-pk.bin
[15947140 bytes used, 830072 available, 16777212 total]
16384K bytes of processor board System flash (Read/Write)

Остается еще одна небольшая проблема. Если запустить проверку:

router#verify flash:c2600-advsecurityk9-mz.124-21-shad-pk.bin

– маршрутизатор обругает нас, сообщив, что Embedded hash и Calculated hash не совпадают. Исправить это очень просто — 16 байт контрольной суммы находится в самом конце бинарного файла образа.

После исправления маршрутизатор сообщает, что контрольная сумма успешно подсчитана и совпадает:

Embedded Hash MD5 : 3DD2C6591FF4F033425147DE4540F9CD
Computed Hash MD5 : 3DD2C6591FF4F033425147DE4540F9CD
CCO Hash MD5 : 79020945BDFE2A354E012C8303136360

Embedded hash verification successful.
File system hash verification successful.

Логическое заключение

Новый образ готов и правильно сформирован. Усвоив эту статью, ты получишь опыт:

  1. по формату PKZIP;
  2. по формату исполняемых файлов ELF;
  3. по внутреннему устройству образов Cisco IOS;
  4. по работе в режиме rommon маршрутизатора.

Кроме того, готов задел для дальнейших извращений над маршрутизаторами. Для общего развития можно поковырять распакованные образы в IDA, изучить вирусы в *nix-like системах, чтобы проинфицировать образ своим бекдором, ну и собственно, написать бекдор. A мои изыскания здесь успешно заканчиваются. Все вопросы, пожелания и, в особенности, идеи, мой дорогой друг, я готов получить по электронной почте. С радостью отвечу и помогу по мере сил. Удачи в бинарном патчинге... и не только.

Содержание
ttfb: 7.9889297485352 ms