Лирическое отступление: всё описанное в данной статье производилось исключительно в образовательных целях, цели извлечения материальной выгоды не преследовалось, ни одного котика в процессе (надеюсь) не пострадало. Всё, что здесь описано вы повторяете на свой страх и риск.
КДПВ курильщика (для тех, у кого дорогой трафик)
Несколько лет в глухой деревне трудится, не покладая рук, этот неуловимый Джо сетевой промышленности. Выбор пал на него, благодаря поддержке единственно рабочего решения для данной местности, а именно CDMA 450 от местного оператора «Сотел» (аля SkyLink). В отличии от других роутеров/модемов для данного стандарта того времени он единственный позволил добиться устойчивой связи с помощью какой-то матери и направленной антенны. Но вот беда: сайт производителя (а возможно и он сам) исчез с горизонта этих наших интернетов в далёком 2011 году. Осталось лишь пафосное видео на YouTube и упоминания их продуктов у разномастных продавцов и операторов.
КДПВ для ни в чём не ограничивающих себя читателей, хотя какое уж тут привлечение внимания, если вы уже здесь.
Все последующие изображения кликабельны (кроме сказочного персонажа)
Мотивация
Вместе с сайтом и производителем покинули этот бренный мир и любые надежды на получение файлов прошивки и уж тем более открытия её исходных кодов, несмотря на требования GPL. Идея же получить более полный доступ к системе, чем это позволяет веб-интерфейс, появилась в голове давно и не давала покоя шаловливым рукам. А, благодаря вопросу на тостере от ув. Nomad1 и вопреки его совету выкинуть данное недоразумение сетевой промышленности, незамедлительно было приведено в исполнение. На самом деле спасибо этому читательу и за первое, и за второе, т.к. это был прям вызов, после которого я с криком «Слабоумие и отвага!» пошёл в неравный бой с корейской технологической машиной образца 2009 года.
Софт
Первым делом я начал изучать веб-интерфейс, а точнее его внутренний мир. Благодаря дыре в использованной версии встраиваемого веб-сервера GoAhead, получилось скачивать исходный код страниц, добавляя к основной ссылке "/". Например по ссылке http://192.168.200.1/html/log.asp открывался результат работы скрипта log.asp, а по http://192.168.200.1/html/log.asp/ — исходный файл скрипта log.asp. Небольшим скриптом на баше было вытащено всё, что хоть как-то упоминалось в скриптах, но после анализа добытого стало понятно, что этой информации явно не достаточно для взлома.
Благодаря другой уязвимости в том же GoAhead, можно было выполнить код при переполнении буфера, но для этого нужно было получить информацию об адресе, куда передавать управление, а в отсутствии доступа к системе стек вызовов при падении не получить.
Помимо 2-х уязвимостей в веб-сервере были найдены уязвимости в реализации uPnP сервера, которые приводили к переполнению буфера и выполнению кода, но их эксплуатация тоже требовала доступа к системе роутера.
Железо
Распрощавшись с надеждами на программный взлом, я перешёл к изучению железной части.
Железная часть роутера представляет из себя бутерброд из двух плат: модем и интерфейсы (сверху на фото) и процессорный блок (снизу на фото):
На обратной стороне процессорной части находится разъём mini-PCI в котором мирно покоится плата Wi-Fi:
Первичный осмотр пациента показал, что основными узлами данного устройства являются:
- Qualcomm MSM6801A — процессор модема
- Micrel KSZ8692PB — система на чипе (SoC) с сетью, PCI и другой полезной нагрузкой
Так как самую большую микросхему SoC мы выявили, нужно думать с какой стороны к ней подобраться. К сожалению, по какому-то нелепому совпадению, Micrel ушёл в закат также как и Vertex Wireless. Поиски хоть какой-то документации по данному чипу заводили в тупики на форумах, где инженера возмущались закрытости спецификаций и вообще на отсутствие документации в открытом доступе, на что милые менеджеры их приглашали обсудить это тет-а-тет. Но на помощь пришла The Wayback Machine, благодаря которой всё таки удалось завладеть документацией и прочими вкусностями для данного чипа.
UART
После изучения добытой документации стало понятно, что у нашего нового друга есть UART-интерфейсы в количестве 4-х штук, а также JTAG. Один из UART'ов скорее всего используется как отладочная консоль. Запустив терминал,
$ minicom -D /dev/ttyUSB0 -b 115200
я начал тыкать иглой, подключенной к конвертеру TTL-USB, в площадки отладочных точек на плате, периодически отправляя в перезагрузку роутер. И вот на очередной точке побежали в консоли заветные буковки… а на соседней буковки ответов. Это оказался UART для общения SoC с модемом. Теоретически лог обмена с модемом тоже представляет некоторый интерес, особенно учитывая отсутствие внятной документации на творение Qualcomm'а в свободном доступе, но у нас пока несколько другая цель.
Точки же UART'а отладочной консоли оказались с обратной стороны платы и закрывались второй платой «бутерброда», поэтому на их обнаружение ушло чуть больше времени.
Подпаиваемся к заветным контактам:
U-Boot 1.1.4 (November 6, 2008) DRAM: 64 MB Flash: 4 MB In: serial Out: serial Err: serial ## Booting image at 1c040000 ... Image Name: Kernel-Ramdisk-Image Image Type: ARM Linux Multi-File Image (uncompressed) Data Size: 3338960 Bytes = 3.2 MB Load Address: 00008000 Entry Point: 00008000 Contents: Image 0: 1609588 Bytes = 1.5 MB Image 1: 1729360 Bytes = 1.6 MB Verifying Checksum ... OK OK Relocate RAMDISK from 0x1c1c8fc0 to 0xc00000 by 0x1a6350 bytes Starting kernel ... Uncompressing Linux.......................................................................................................... done, booting the kernel. Linux version 2.6.23.17-Pegasus (gcc version 4.2.1) CPU: ARM922T [41029220] revision 0 (ARMv4T), cr=c0007177 Machine: Micrel Pegasus Memory policy: ECC disabled, Data cache writeback Pegasus ID=8692 SubID=00 Revision=02 Clocks: System 166 MHz, CPU 166 MHz, DDR 166 MHz, PCI 33 MHz, IPsec 50 MHz CPU0: D VIVT write-back cache CPU0: I cache: 8192 bytes, associativity 64, 32 byte lines, 4 sets CPU0: D cache: 8192 bytes, associativity 64, 32 byte lines, 4 sets Built 1 zonelists in Zone order. Total pages: 16256 Kernel command line: console=ttyAM0,115200 PID hash table entries: 256 (order: 8, 1024 bytes) console [ttyAM0] enabled Dentry cache hash table entries: 8192 (order: 3, 32768 bytes) Inode-cache hash table entries: 4096 (order: 2, 16384 bytes) Memory: 64MB = 64MB total Memory: 59756KB available (3028K code, 259K data, 128K init) Mount-cache hash table entries: 512 CPU: Testing write buffer coherency: ok NET: Registered protocol family 16 PCI: bus0: Fast back to back transfers disabled usbcore: registered new interface driver usbfs usbcore: registered new interface driver hub usbcore: registered new device driver usb NET: Registered protocol family 2 Time: pegasus clocksource has been installed. IP route cache hash table entries: 1024 (order: 0, 4096 bytes) TCP established hash table entries: 2048 (order: 2, 16384 bytes) TCP bind hash table entries: 2048 (order: 1, 8192 bytes) TCP: Hash tables configured (established 2048 bind 2048) TCP reno registered Freeing initrd memory: 1688K reset button handler is loaded NetWinder Floating Point Emulator V0.97 (double precision) NTFS driver 2.1.28 [Flags: R/O]. JFFS2 version 2.2. (NAND) �� 2001-2006 Red Hat, Inc. io scheduler noop registered io scheduler deadline registered (default) LED device driver is installed Serial: Micrel Pegasus UART driver version: 2.6.1.0 ttyAM0 at MMIO 0x1fffe000 (irq = 45) is a Pegasus ttyAM1 at MMIO 0x1fffe080 (irq = 49) is a Pegasus ttyAM2 at MMIO 0x1fffe100 (irq = 52) is a Pegasus ttyAM3 at MMIO 0x1fffe180 (irq = 55) is a Pegasus RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize PPP generic driver version 2.4.2 PPP Deflate Compression module registered PPP BSD Compression module registered IMQ starting with 2 devices... IMQ driver loaded successfully. Hooking IMQ after NAT on PREROUTING. Hooking IMQ before NAT on POSTROUTING. 30 = ffff ffff Micrel Pegasus 1.0.0 (Oct 7, 2008) physmap platform flash device: 00400000 at 1c000000 physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank Amd/Fujitsu Extended Query Table at 0x0040 physmap-flash.0: CFI does not contain boot bank location. Assuming top. number of CFI chips: 1 cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness. cmdlinepart partition parsing not available RedBoot partition parsing not available Using physmap partition information Creating 4 MTD partitions on "physmap-flash.0": 0x00000000-0x00030000 : "Boot Loader" 0x00030000-0x00040000 : "Loader Config" 0x00040000-0x003e0000 : "Linux RootFS" 0x003e0000-0x00400000 : "System Config" pegasus-ehci pegasus-ehci: Pegasus-EHCI pegasus-ehci pegasus-ehci: new USB bus registered, assigned bus number 1 pegasus-ehci pegasus-ehci: irq 8, io mem 0x1fffc000 pegasus-ehci pegasus-ehci: USB 0.0 started, EHCI 1.00, driver 10 Dec 2004 usb usb1: Product: Pegasus-EHCI usb usb1: Manufacturer: Linux 2.6.23.17-Pegasus ehci_hcd usb usb1: SerialNumber: KS8692 usb usb1: configuration #1 chosen from 1 choice hub 1-0:1.0: USB hub found hub 1-0:1.0: 2 ports detected pegasus-ohci pegasus-ohci: new USB bus registered, assigned bus number 2 pegasus-ohci pegasus-ohci: irq 9, io mem 0x1fffd000 usb usb2: Product: Pegasus-OHCI usb usb2: Manufacturer: Linux 2.6.23.17-Pegasus ohci_hcd usb usb2: SerialNumber: ks8692 usb usb2: configuration #1 chosen from 1 choice hub 2-0:1.0: USB hub found hub 2-0:1.0: 2 ports detected usbcore: registered new interface driver cdc_acm cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and ISDN adapters usbcore: registered new interface driver usbserial drivers/usb/serial/usb-serial.c: USB Serial support registered for generic usbcore: registered new interface driver usbserial_generic drivers/usb/serial/usb-serial.c: USB Serial Driver core Using Pegasus for AES algorithm. Using Pegasus for DES algorithm. u32 classifier Performance counters on nf_conntrack version 0.5.0 (1024 buckets, 4096 max) IPv4 over IPv4 tunneling driver GRE over IPv4 tunneling driver ip_tables: (C) 2000-2006 Netfilter Core Team TCP cubic registered NET: Registered protocol family 1 NET: Registered protocol family 17 NET: Registered protocol family 15 Bridge firewalling registered RAMDISK: Compressed image found at block 0 VFS: Mounted root (ext2 filesystem). Freeing init memory: 128K Setting hostname ... Mounting root fs rw ... Mounting other filesystems ... checksum f0d68bc4, tmp_checksum f0d68bc4 flash : Read from flash memory... sysconf read 0x40070000 Checksum is f0d68bc4 flash : Wrote to flash memory... br0: Dropping NETIF_F_UFO since no NETIF_F_HW_CSUM feature. device eth1 entered promiscuous mode time: 9628 ms usb 2-1: new full speed USB device using pegasus-ohci and address 2 usb 2-1: device descriptor read/64, error -62 usb 2-1: Product: Qualcomm CDMA Technologies MSM usb 2-1: Manufacturer: Qualcomm, Incorporated usb 2-1: configuration #1 chosen from 1 choice cdc_acm 2-1:1.0: ttyACM0: USB ACM device br0: port 1(eth1) entering learning state udhcpd (v0.9.9) started Unable to open /etc/config/udhcpd.leases for reading Unable to open /etc/config/udhcpd.assigned for reading br0: topology change detected, propagating br0: port 1(eth1) entering forwarding state =>ATcommand Start 3 >>>Send : AT$ROUTERBOOTDONE >>>Read : AT$ROUTERBOOTDONE=OK command count 0 >>>Send : AT$TIME >>>Read : AT$TIME=19800106000024 >>>Send : AT$PINSTAT >>>Send : AT$TIME Sun Jan 6 00:00:24 UTC 1980 command count 0 >>>Read : AT$DRC=0 cdmainfo.r_drc Null Rate >>>Read : AT$RF=007d,007d cdmainfo.r_rf = Rx1 007d cdmainfo.r_rf = Rx2 007d >>>Read : AT$CALLSTAT=0,0 cdmainfo.r_callstat = 1x Offline cdmainfo.r_callstat = EVDO Inactive >>>Read : AT$PINSTAT=NOCARD pinstat 3 command count 0 >>>Read : AT$TIME=19800106000024 command count 0 >>>Read : AT$EVDOINFO=0,0,0,0,0,-31,0,0,0 >>>Read : AT$CDMAINFO=0,0,0,0,0,0,0,-31,0,0,9,9 rmmod: nf_nat_dnsproxy: Unknown error -1074267480 create_sysconf_linux_module >>>Send : AT$DRC=OK >>>Send : AT$RF=OK >>>Send : AT$CALLSTAT=OK >>>Send : AT$EVDOINFO=OK Sysinit done >>>Send : AT$CDMAINFO=OK login: >>>Read : AT$BOOTDONE >>>Send : AT$BOOTDONE=OK >>>Read : AT$RUIMREADDONE=NOCARD pinstat 3 >>>Send : AT$RUIMREADDONE=OK
И вот мы попали в консоль, но система после загрузки просит авторизоваться и всякие там стандартные явки-пароли принимать наотрез отказывается, а загрузчик u-boot оказался собранным без возможности остановить загрузку и поуправлять ей. Путь последовательной консоли был для меня закрыт и я ушёл дальше… ну это, не считая дурацких попыток подбора пароля скриптом для minicom'а, которые были обречены на получение результата чуть позже, чем тот супер-компьютер скажет своё «42».
JTAG
Моё счастье, что все контакты JTAG-интерфейса чипа оказались крайними и были доступны для «прозвона» с использованием иглы:
Контакты JTAG на плате:
Однако собранный на коленке переходник из DB25-папы для LPT-порта, сопротивлений и соплей показал, что JTAG либо отключен, либо у кого-то кривые руки. Для второго варианта на небезызвестной торговой площадке поднебесной был заказан фабричный JTAG-переходник, но это долго. А в первом случае следует попробовать ввести SoC в какой-то тестовый режим с помощью игл, провода и тестовых точек, уходящих к ножкам TESTEN и TESTEN1.
Озарение
Но в этот момент в моей памяти всплыл старый хак, применяемый для принудительной прошивки всякого железа: вогнать железку в режим «сломанной прошивки», закорачивая ножки адреса на флешке с прошивкой. На нашей плате прошивка находится в микросхеме (Samsung K8P3215UQB www.bdtic.com/DataSheet/SAMSUNG/K8P3215UQB.pdf) под экраном рядом с процом.
Первые ножки данной микросхемы — это линии адреса и, закорачивая их, мы сможем нарушить вычитывание прошивки:
Так как нам хотелось бы попасть в меню u-boot'а, то шалить мы будем сразу после его загрузки в момент вычитывания остальной прошивки. Включаем роутер и после многозначительного моргания светодиодами и вывода на консоль текста:
U-Boot 1.1.4 (November 6, 2008) DRAM: 64 MB Flash: 4 MB In: serial Out: serial Err: serial
начинаем ласково коротить 1-2-3-4 ноги флешки отвёрткой, добиваясь заветного:
Bad Header Checksum ks8692pb >
Ну вот мы и добились расположения от несговорчивого загрузчика.
Загрузчик
Давайте посмотрим, что умеет этот ветеран:
autoscr — run script from memory
base — print or set address offset
bdinfo — print Board Info structure
boot — boot default, i.e., run 'bootcmd'
bootd — boot default, i.e., run 'bootcmd'
bootm — boot application image from memory
bootp — boot image via network using BootP/TFTP protocol
cmp — memory compare
coninfo — print console devices and information
cp — memory copy
cp — memory copy
crc32 — checksum calculation
dhcp — invoke DHCP client to obtain IP/boot params
echo — echo args to console
erase — erase FLASH memory
fatinfo — print information about filesystem
fatload — load binary file from a dos filesystem
fatls — list files in a directory (default /)
flinfo — print FLASH memory information
go — start application at address 'addr'
help — print online help
icrc32 — checksum calculation
iloop — infinite loop on address range
imd — i2c memory display
iminfo — print header information for application image
imls — list all images found in flash
imm — i2c memory modify (auto-incrementing)
imw — memory write (fill)
inm — memory modify (constant address)
iprobe — probe to discover valid I2C chip addresses
isf — i2s transmit waveform data file from memory address
isr — i2s receive waveform data to the memory address
isw — i2s transmit waveform data from memory address
itest — return true/false on integer compare
loadb — load binary file over serial line (kermit mode)
loads — load S-Record file over serial line
loady — load binary file over serial line (ymodem mode)
loop — infinite loop on address range
md — memory display
mdior register — read mdio register
mdiow register data — write mdio register
mii — MII utility commands
mm — memory modify (auto-incrementing)
mmcinit — init mmc card
mnand — copy to nand boot
mr — memory read and compare
mtest — simple RAM test
mw — memory write (fill)
nettest — network port load test
nfs — boot image via network using NFS protocol
nm — memory modify (constant address)
pci — list and access PCI Configuration Space
ping — send ICMP ECHO_REQUEST to network host
printenv- print environment variables
protect — enable or disable FLASH write protection
rarpboot- boot image via network using RARP/TFTP protocol
reset — Perform RESET of the CPU
run — run commands in an environment variable
saveenv — save environment variables to persistent storage
setenv — set environment variables
sleep — delay execution for some time
sspi — SPI utility commands
tftpboot- boot image via network using TFTP protocol
usb — USB sub-system
usbboot — boot from USB device
version — print monitor version
wait — wait for memory
Выглядит многообещающе, но на поверку оказывается, что часть команд не работает, не смотря на упоминание в help'е. В первую очередь хотелось бы знать как устроена адресация флешки:
Bank # 1: CFI conformant FLASH (16 x 16) Size: 4 MB in 78 Sectors Erase timeout 8192 ms, write timeout 1 ms, buffer write timeout 1 ms, buffer size 1 Sector Start Addresses: 1C000000 (RO) 1C002000 (RO) 1C004000 (RO) 1C006000 (RO) 1C008000 (RO) 1C00A000 (RO) 1C00C000 (RO) 1C00E000 (RO) 1C010000 (RO) 1C020000 (RO) 1C030000 (RO) 1C040000 1C050000 1C060000 1C070000 1C080000 1C090000 1C0A0000 1C0B0000 1C0C0000 1C0D0000 1C0E0000 1C0F0000 1C100000 1C110000 1C120000 1C130000 1C140000 1C150000 1C160000 1C170000 1C180000 1C190000 1C1A0000 1C1B0000 1C1C0000 1C1D0000 1C1E0000 1C1F0000 1C200000 1C210000 1C220000 1C230000 1C240000 1C250000 1C260000 1C270000 1C280000 1C290000 1C2A0000 1C2B0000 1C2C0000 1C2D0000 1C2E0000 1C2F0000 1C300000 1C310000 1C320000 1C330000 1C340000 1C350000 1C360000 1C370000 1C380000 1C390000 1C3A0000 1C3B0000 1C3C0000 1C3D0000 1C3E0000 1C3F0000 1C3F2000 1C3F4000 1C3F6000 1C3F8000 1C3FA000 1C3FC000 1C3FE000
Области помеченные "(RO)" — это сам загрузчик. Трогать его пока совсем не тянет, так что пробегаем мимо него и останавливаем свой взгляд на остальных диапазонах.
Долгие и мучительные попытки сдампить содержимое флешки в нормальном виде закончились ВНЕЗАПНО перезаписанным после рестарта проца флешем. Оказалось, что при каких-то неизвестных условиях загрузчик после закачки через tftp файла отправлял процессор в резет, после которого на флешке автоматически начиналось стирание диапазона, где лежат образа ядра и ramdisk'а, а на их место начинает записываться загруженное. В моём случае это был наспех собранный образ OpenWRT от Micrel'я для данной платформы, который к боевой прошивке имеет такое же отношение как сантехник к балетмейстеру. Пытался то я его загрузить в память, но вышеописанная особенность загрузчика привела к записи этого бреда во флеш. Спасло то, что во первых не затёрся загрузчик, а во вторых у меня рядом лежала такая же боевая железка. В последствии дамп с боевой был водружён на подбитый тестовый экземпляр, но тогда было совсем не до смеха и кирпичи валились на пол непрерывным потоком, пока я пытался взять себя в руки.
Т.к. загрузчик никуда не делся, а на месте прошивки было не пойми что, прерванное на полпути во время записи, процедура немного «облегчилась»: теперь не нужно было ласкать отвёрткой ноги флешки, чтоб выйти на «Bad Header Checksum».
На еле дышащем полутрупе был найден единственный способ сдампить флешку — это команда md (memory display), которая выводит указанный участок памяти прямо в консоль в виде шестнадцатиричного текста:
1c040000: 56190527 8e2b9359 cd32444b d0f23200 '..VY.+.KD2..2.. 1c040010: 00800000 00800000 6a1878c2 00040205 .........x.j.... 1c040020: 6e72654b 522d6c65 69646d61 492d6b73 Kernel-Ramdisk-I 1c040030: 6567616d 00000000 00000000 00000000 mage............ 1c040040: 748f1800 50631a00 00000000 e1a00000 ...t..cP........ 1c040050: e1a00000 e1a00000 e1a00000 e1a00000 ................ 1c040060: e1a00000 e1a00000 e1a00000 ea000002 ................ 1c040070: 016f2818 00000000 00188f74 e1a07001 .(o.....t....p.. 1c040080: e1a08002 e10f2000 e3120003 1a000001 ..... .......... 1c040090: e3a00017 ef123456 e10f2000 e38220c0 ....V4... ... .. 1c0400a0: e121f002 00000000 00000000 e28f00d0 ..!............. 1c0400b0: e890307e e0500001 0a00000a e0855000 ~0....P......P.. 1c0400c0: e0866000 e08cc000 e0822000 e0833000 .`....... ...0.. 1c0400d0: e08dd000 e5961000 e0811000 e4861004 ................ 1c0400e0: e156000c 3afffffa e3a00000 e4820004 ..V....:........ 1c0400f0: e4820004 e4820004 e4820004 e1520003 ..............R.
«Маловато будет!»
Оказывается кроме стартового адреса нужно ещё указывать второй параметр — размер.
Дамп
Для того, чтоб всё нажитое непосильным трудом не скрылось вместе с консолью minicom'а начинаем запись вывода в файл: нажимаем «Ctrl+a l» и подтверждаем имя файла, например стандартный «minicom.cap».
Нам нужен дамп области с 0x1c040000 по 0x1c3fffff (см. вывод flinfo). Получается блок размером 0x3c0000, но размер команда md (memory display) принимает не в байтах, а в 32-битных (4-байтовых) словах, таким образом нужное нам значение получается делением 0x3c0000 на 4 и равно 0xf0000. Вот что получается в итоге:
ks8692pb > md 1c040000 f0000
Уходим пить чай/кофе/со скуки, так как процедура вывода 3932160 байт в текстовом шестнадцатиричном виде в последовательную консоль — это печаль. После завершения процедуры слива нужно закрыть minicom (Ctrl+a x).
Копируем выхлоп minidump'а в файл с более осмысленным названием
$ cp ~/minicom.cap ./dump.hex
Придётся в него заглянуть и убрать лишние строки, которые были введены/выведены в minicom'е. В моём случае это одна строка в начале:
ks8692pb > md 1c040000 f0000
и одна в конце файла:
ks8692pb >
Конвертируем из текста в бинарные данные:
$ xxd -r -s-0x1c040000 dump.hex > dump.raw.bin
Смещение в -0x1c040000 необходимо, чтоб в итоговый файл не были записаны данные из диапазона 0x00000000-0x1c03ffff, которые xxd иначе посчитает пропавшими без вести и учтиво запишет в файл.
Выяснилось, что порядок байт в получившемся бинарнике не тот и пришлось искать решение как бы развернуть каждую четвёрку байт (32-битное слово). На просторах интернета быстро было найдено решение:
cat dump.raw.bin | perl -e 'while (sysread(STDIN,$d,4)){print pack("N",unpack("V",$d));}' > dump.bin
Вскрытие
Давайте посмотрим, что же у нас внутри дампа:
DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 uImage header, header size: 64 bytes, header CRC: 0x59932B8E, created: 2010-01-06 06:50:53, image size: 3338960 bytes, Data Address: 0x8000, Entry Point: 0x8000, data CRC: 0xC278186A, OS: Linux, CPU: ARM, image type: Multi-File Image, compression type: none, image name: "Kernel-Ramdisk-Image" 14476 0x388C gzip compressed data, maximum compression, from Unix, last modified: 2010-01-05 04:49:24 1609664 0x188FC0 gzip compressed data, has original file name: "ramdisk.img", from Unix, last modified: 2010-01-06 06:50:44
Интересно что, не смотря на маркировку на плате «2009-10-15», заводская прошивка имеет метку январь 2010 года. Видимо что-то «пошло не так» и готовую партия допиливали на ходу. Хорошо, что софт, а не железо… навесным монтажом.
Разделим нажитое на отдельные части:
заголовок
$ dd if=dump.bin of=uImageHeader ibs=1 count=14476
ядро (размер 1595188=1609664-14476)
$ dd if=dump.bin of=zImage ibs=1 skip=14476 count=1595188
образ ramdisk'а:
$ dd if=dump.bin of=initrd.gz ibs=1 skip=1609664 & gunzip initrd.gz
В последствии после редактирования ramdisk'а можно будет собрать всё обратно в одно целое командами:
$ cat uImageHeader > out.bin
$ cat zImage >> out.bin
$ gzip initrd & cat initrd.gz >> out.bin
Теперь нужно выяснить, что за файловая система используется:
$ sudo blkid -o value -s TYPE ./initrd
ext2
И примонтировать её куда нибудь для жестоких экспериментов:
$ mkdir rootfs
$ sudo mount -o loop -t ext2 ./initrd ./rootfs/
После недолгого изучения ФС находим:
$ sudo cat rootfs/etc/inittab
::sysinit:/etc/rc
::respawn:/bin/lgc_login
Первое, что приходит в голову — это «чего же тут захардкодили?»:
/lib/ld-uClibc.so.0 liblgc.so _DYNAMIC __dso_handle _init _fini _GLOBAL_OFFSET_TABLE_ printf fgets strlen libc.so.0 stdout getpass fflush abort stdin signal execlp __uClibc_main strcmp exit __data_start _edata __bss_start __bss_start__ _end __bss_end__ __end__ login: password: admin .admin. GCC: (GNU) 3.3.2 20031005 (Debian prerelease) GCC: (GNU) 2.95.4 20010319 (prerelease) GCC: (GNU) 2.95.4 20010319 (prerelease) GCC: (GNU) 2.95.4 20010319 (prerelease) GCC: (GNU) 3.3.2 20031005 (Debian prerelease) .shstrtab .interp .note.ABI-tag .hash .dynsym .dynstr .rel.dyn .rel.plt .init .text .fini .rodata .data .dynamic .ctors .dtors .got .sbss .bss .comment
Ну здесь то уж достаточно иметь глаза, чтоб разглядеть пару логин/пароль «admin/.admin.» намертво зашитую в коде. Не стану томить — авторизация в последовательной консоли с этими данными прошла успешно.
После более детального изучения ФС выяснилось, что можно запустить команду, вообще никак не авторизуясь, например telnetd:
$ wget --post-data "cmd_key=%24telnetd%3b" "http://192.168.200.1/goform/ping_showpopup"
Он запустится, начнёт принимать подключения… но, к сожалению, не сможет нас авторизовать. Но это уже совсем другая история.
Спасибо ув. Nomad1 за пинок под мой ленивый зад, добрым людям, предоставившим полумёртный образец для нечеловеческих экспериментов, моей жене и дочерям за терпение, а моему пятилетнему сыну за помощь в перезагрузки роутера и запуске команд на компьютере, когда у папы заканчивались конечности.
Автор: Евгений Исаев