Данная статья является продолжением темы о взломе и заражении роутеров. На
сей раз у меня на операционном столе другая модель роутера, но пока той же
фирмы, D-Link 2500U. Описанное ниже куда интереснее, чем то, что было в
первом материале —
здесь представлен код Wake-up bindshell'a на Си для закрепления на
роутере, а также описан принцип распаковки прошивок Broadcom.
Сразу после написания первой статьи мне в лапы попал этот маршрутизатор, и
после беглого осмотра я понял, что внутреннее его устройство существенно
отличается от модели 500T и, следовательно, требует отдельного описания.
Изучение любого подобного устройства следует начать с поиска способов
коммуникации, в данном случае воспользуемся старым добрым сканером портов nmap:
$ nmap -A 192.168.1.1 Nmap scan report for 192.168.1.1 Host is up (0.026s latency). Not shown: 998 closed ports
PORT STATE SERVICE 23/tcp open telnet 80/tcp open http
Для меня останется загадкой, почему разработчики отдают предпочтение telnet
вместо ssh, ведь он куда более защищеннее... Ну да ладно, и на этом спасибо.
Проверим открытые UDP-порты, вероятно, есть что-то интересное:
Nmap scan report for 192.168.1.1 Host is up (0.00096s latency). Not shown: 997 closed ports
PORT STATE SERVICE 53/udp open domain 67/udp open|filtered dhcps 69/udp open|filtered tftp MAC Address: 00:26:5A:74:70:79 (D-Link)
Чутье не обмануло — сразу бросается в глаза tftp; уверен, что он используется
для прошивки, но не будем спешить, убедимся в этом позже. Приступаем к сбору
информации касательно строения операционной системы и телнетимся к роутеру:
$ telnet 192.168.1.1 Trying 192.168.1.1... Connected to 192.168.1.1. Escape character is '^]'. BCM96332 ADSL Router Login: admin Password: admin
Нет уже родного мне приветствия BusyBox, только это приветствие немного
отличалось. Через несколько мгновений до меня дошло, что BCM — это Broadcom! А
далее в названии идет тип платы (чипа), на которой построен маршрутизатор.
Изначально я опешил — shell урезан до безобразия... Сделано это, вероятно, для
того, чтобы такие как мы не лазили где не надо, но ведь, с другой стороны, такие
как мы пролезут везде. Команды cd, ls или dir напрочь отсутствуют, структуру
каталогов не узнаешь. Однако, в help`e вдруг засветился echo — он может выводить
список файлов/директорий, правда, без обозначения, где что
(директория/файл/символическая ссылка) находится, то есть будут выведены лишь
имена объектов. Замену ls нашли, а где же брать cd? В это время один из
тараканов в моей голове подсказал набрать sh, и... бинго! Появилось знакомое
приветствие BusyBox, и, мигом введя команду help, в выводе я обнаружил
потерянный cd! Совсем неясно, для чего сделано это безобразие — 2 shell'а... Но
теперь все готово, и, с горем пополам, наконец-то можно приступить к сбору
информации. Для начала осмотримся:
bin dev etc lib linuxrc mnt proc sbin usr var webs
Все стандартно, за исключением linuxrc (как оказалось позже, это BusyBox) и
webs (в этой директории содержатся файлы, относящиеся к веб-интерфейсу). Узнаем
версию GNU\Linux:
Linux version 2.6.8.1 (jenny@BS5) (gcc version 3.4.2)
Дистрибутив собран разработчиками. Слава Богу, здесь версия ядра 2.6, а это
значит, что у нас совершенно не будет проблем с написанием трояна (привычнее
ведь под 2.6 писать, чем под 2.4, тем более, если планируется что-то серьезное).
Далее версии прошивки и чипа:
MODEL=DSL-2500U VERSION=RU_1.50 BCM_VERSION=3.10L.01. Revision=5317 FSSTAMP=20090304211235
При автоматическом заражении обязательно требуется проверять этот файл на
соответствие версий, и при каких-либо отличиях прекращать инфицирование, иначе
роутер может зависнуть, и получится "ни себе, ни людям". На официальном
FTP-сервере лежит несколько вариантов прошивок для модели 2500U, каждая
соответствует нужной версии аппаратного обеспечения.
Следующее действие — просмотр информации об архитектуре:
system type : 96332 processor : 0 cpu model : BCM6338 V1.0 BogoMIPS : 239.20 wait instruction : no microsecond timers : yes tlb_entries : 32 extra interrupt vector : yes hardware watchpoint : no unaligned access : 8407352 VCED exceptions : not available VCEI exceptions : not available
Как мы видим, роутер построен на плате Broadcom 96338. Ее используют
множество производителей: Netgear, Asus и т.п., но с мелкими изменениями в
программном обеспечении (например, у одного из производителей вместо
веб-интерфейса панель управления находится в shell'e, но это совсем не страшно,
так как нормальный shell остался), так что описанное здесь можно применить и к
другим моделям. Построена эта плата на процессоре 280D MIPS, с тактовой частотой
более 200MHz (впрочем, это зависит от вольтажа). Сведения о памяти:
rootfs / rootfs rw 0 0 /dev/root / squashfs ro 0 0 /proc /proc proc rw,nodiratime 0 0 tmpfs /var tmpfs rw 0 0
dev: size erasesize name mtd0: 00153000 00001000 "Physically mapped flash"
MemTotal: 6108 kB MemFree: 428 kB ---8<---
Для организации файловой системы используется все та же SquashFs с патчем
LZMA, но уже второй версии, коэффициент сжатия у нее выше. Разработчики не стали
делить Flash-память на несколько блоков, ограничились одним, размер его —
всего-то 2 Мб. Оперативная память составляет 6 Мб, и забита она почти полностью.
Далее по плану список процессов. Разброса в управляющих программах в нем нет,
видна только одна — CFM (Common Firmware Manager), собственно, заведующая всем
программа. Telnet не показывает пароль к учетной записи, но найти его можно в
конфигурационном файле, о котором речь пойдет позже. Еще в списке процессов
присутствуют:
- pvc2684d — служит для обеспечения соединения, подробнее можно почитать в
описании технологии ADSL, ключевое слово PVC (Permanent Virtual Circuit).
- sntp — демон синхронизации времени.
- snmpd — демон, обеспечивающий удаленное управление по протоколу SNMP (Simple
Network Management Protocol).
- syslogd — демон, служащий для ведения системного лога. Очень, кстати,
удобная штука: есть перенаправление логов по сети, позволяет своевременно
принимать решения при возникновении проблем.
После детального осмотра системы о ней сложилось исключительно негативное
представление — собрана она очень небрежно, и в первую очередь убивают наповал
вещи вроде /dev/ac97 (AC97 относится к звуковым устройствам)...
Хирургическое вмешательство
Теперь переходим к делу. Вначале, я задумался: "А как же перепрошить данную
железку?". Нет ведь такой халявы, как в модели 500T: wget, большой объем
оперативной памяти... И как нельзя кстати вспомнился обнаруженный в самом начале
nmap'ом tftp-демон — именно он используется для прошивки. Пример общения с tftp,
все банально:
$ tftp tftp> connect 192.168.1.1 tftp> mode binary tftp> put firmware.img
Когда я начал думать о модификации прошивки, актуальными стали несколько
проблем:
- Старую прошивку сохранить нельзя, соответственно, если перешивать своей,
конфигурация сбросится до заводской, что весьма подозрительно.
- Прошивка поставляется одним файлом, поэтому придется разбираться в
формате файла и извлекать файловую систему.
Для начала следует разобраться в формате файла прошивки и научиться
распаковывать ее, чтобы далее модифицировать. Структуру можно подсмотреть в
файле bcmTag.h из состава исходного кода прошивки. Формат, по сути, прост, и
проблем с распаковкой не будет, можно будет спокойно обойтись программами из
состава GNU/Linux и SquashFs. Первые 265 байт занимает информация о прошивке,
адреса и размеры секций с загрузчиком, ядром и файловой системой а также их
контрольные суммы.
$ hexdump -C -n 256 firmware.img
Смещение файловой системы вычисляется так: размер bcmtag(256) + размер CFE(62380)
= 62636, а смещение конца файловой системы равно начало(62636) + размер файловой
системы(1474560).
$ hexdump -C -n 64 -s 62636 firmware.img
Видна сигнатура SquashFs — "sqsh", значит, мы на правильном пути. Вырезаем
образ файловой системы с помощью швейцарского ножа для файлов и образов — dd:
$ dd if=firmware.img of=fs.img bs=1 skip=62636 count=1474560
Все просто, если же что-то непонятно — man dd. Теперь распаковываем. Напомню,
здесь используется вторая версия файловой системы с патчем LZMA.
$ mkdir unpacked_fs $ usquashfs fs.img
Модифицируем как угодно, например, для теста я почти полностью перебрал
дистрибутив, поубивал ненужное, поменял telnet на ssh (он мне ближе по духу),
пересобрал BusyBox... Запаковываем обратно:
$ mksquashfs unpacked_fs modifed_fs.img -noappend
А вот теперь самое главное — конструирование нового файла прошивки. Нужно
вставить файловую систему обратно на свое место и исправить поля в заголовке.
Вырезаем из файла две части, до расположения файловой системы и после:
$ dd if=firmware.img of=before.img bs=1 count=62636 $ dd if=firmware.img of=after.img bs=1 skip=1537196
Смещение места за файловой системой равно началу файловой системы (62636) +
размер файловой системы (1474560). Далее составляем из этих файлов один:
$ mv before.img modifed_firmware.img $ dd if=modifed_fs.img of=modifed_firmware.img bs=1 seek=62636 $ dd if=after.img of=modifed_firmware.img bs=1 seek=1474560
Теперь следует поменять несколько полей в заголовке прошивки, а именно:
totalImageLen, rootfsLen, kernelAddress, imageValidationToken (второй dword) и
tagValidationToken. Вычисляются новые значения полей так.
- totalImageLen: du -b modifed_firmware.img.
- rootfsLen и imageValidationToken: cksum -b modifed_fs.img
- kernelAddress: oldKernelAddress + (modified_rootfsLen - old_rootfsLen).
И в самом конце, когда все поля изменены, tagValidationToken:
$ dd if=modifed_firmware.img of=modified_tag.img bs=1 count=256 $ cksum tag.img
Уф, наконец-то готово! В принципе, нет ничего сложного, главное в цифрах не
путаться, иначе роутер нормально не загрузится. Перед прошивкой все тщательно
проверяй, дабы потом не терять драгоценного времени на восстановление
получившегося "кирпича".
Это был обходной способ модификации, а ведь можно просто собрать свою
прошивку, внедрить туда троян, и перепрошивать ею взломанные маршрутизаторы.
Первоначально надлежит выкачать архив с исходными кодами с официального
FTP-сервера, потом распаковать его. Появятся еще два архива. Первый с
toolchain'ом (*uclibc_crosstools*), если он еще не имеется, то распаковываем в
корень своего GNU/Linux. Второй архив уже с исходным кодом, для него нужно
создать отдельную директорию:
$ mkdir dlink_firmware $ tar xvfz *consumer.tar.gz -C dlink_firmware
Далее запускаем скрипт consumer_install и компиляцию:
$ cd bcm_963xx_router $ make PROFILE=96332CG
Переменная PROFILE означает версию чипа, для которого следует собирать
прошивку. Более подробно можно подсмотреть в Compile.pdf на FTP в директории с
исходниками. Какой способ выбирать — решать тебе. Оба одинаково не представляют
собой ничего сложного, но в то же время отнимают одинаковые время и силу, так
что выбирай по духу. Но ведь осталась еще одна нерешенная проблема — сохранение
конфигурации роутера! Будет слишком подозрительно, если железка, с точки зрения
пользователя, сама собой сбросит настройки в заводские. После детального осмотра
роутера я нашел способ заполучить конфиг, и даже более того — способ зашить его
обратно. Таким образом, через веб-интерфейс он и будет получен:
$ wget http://admin:admin@192.168.1.1/backupsettings.conf
А запихнуть его обратно можно с помощью TFTP-клиента в оболочке роутера:
Прежде нужно поднять у себя TFTP-сервер, и в корень положить файл
backupsettings.conf. Ты уже знаешь, как это делать, по
первой статье :).
Показания к реанимации
При экспериментах с прошивкой неожиданно могут возникнуть проблемы, поэтому
нужно знать, как восстанавливать работоспособность этой модели. Способы те же,
что и в случае с 500Т, только реализации отличаются. В этой модели используется
загрузчик CFE (Common Firmware Environment), для перевода его в режим аварийного
восстановления следует зажать кнопку Reset и, не отпуская ее примерно 20 секунд,
включить устройство. Далее, зайдя на HTTP роутера, можно увидеть панель
восстановления. Если все совсем плохо (загрузчик отказывается работать), как
было описано в прошлой статье, не стоит отчаиваться, а стоит
воспользоваться JTAG-интерфейсом. Напоминаю, перепрошивка через интерфейс
внутрисхемной отладки — дело совсем не быстрое и подвержено сбоям (например, при
длинном кабеле), поэтому следует пользоваться им только в крайних случаях.
Синтез вируса
Мне очень нравятся подобные встраиваемые системы. Не надо думать, как обойти
больше AV-продуктов, как подольше закрепиться в системе. Тут нет таких проблем!
Ни о каких AV и речи нет, в системе можно закрепляться как угодно, хватает одной
строки в стартовом скрипте, чтобы запустить после перезагрузки мое творение.
Самый главный козырь — это факт, что весь трафик пользователя или сети находится
у меня в руках. Но все же, для более новых моделей следует применять способ
заражения исполняемых файлов, любой, самый простой. Единственное — следи за
endian, то есть порядком следования байтов: роутеры построены на различных
MIPS-процессорах, и, соответственно, у них различен порядок следования (big
endian, little endian).
Это более технологичный вариант, но не стоит забывать, что здесь царит GNU\Linux.
Можно применить старый трюк: внедрять в исходники стандартных программ свой код.
Я делал именно так: в начало кода, например, программы export (она запускается
при старте роутера, в скрипте /etc/init.d/rcS), добавил fork() и свой код трояна,
перекомпилировал и добавил в свою прошивку. В итоге, когда роутер стартует,
выполняется скрипт, далее запускается программа export (дабы установить
необходимые переменные окружения), он разветвляется, и троян начинает работать
отдельно от export.
Сейчас, как пример трояна и хорошего способа закрепиться на роутере, подойдет
bindshell. С его помощью можно в любой момент подключиться к железке и делать с
ней все что угодно. Выбрал я именно Wakeup-bindshell, чтобы оставаться
максимально скрытым. Для тех, кто не знает, принцип действия шелла таков:
изначально троян не открывает порт, а ждет специального ICMP-пакета (этот
протокол не использует порты, обработка идет на уровне IP), в котором
идентификатор(icmp.icmp_id) равен 0xDEAD (это знак, что пора открыть порт).
Сделано это для того, чтобы bindshell постоянно не светился с открытым портом,
ведь такой исследователь, как я, может нарваться на странный порт, а владелец
роутера сразу же прошьет железку заводской прошивкой. Наш алгоритм таков: пишем
программу, которая будет отправлять специализированный ICMP-запрос, затем творим
bindshell — в бесконечном цикле он будет ловить ICMP-запросы и проверять поле
icmp.icmp.id на соответствие с 0xDEAD. Если проверка прошла — открываем порт
(31337, конечно же). Сорцы биндшелла и wakeup ты можешь найти на
нашем DVD.
Вообще, из этих вещей можно и даже нужно растить нечто более серьезное.
Например, сделать код в виде LKM, использовать руткит-технологии, добавить
шифрование трафика... Все это необходимо, чтобы вырастить в будущем настоящий
ботнет из роутеров и прочих железячных устройств.
Показания к профилактике и лечению
Повторюсь еще раз — чтобы не стать жертвой, и не заметить неладное только
тогда, когда пропадут деньги с электронных счетов (а потом еще долго думать:
"Где же это я прокололся?", не обращая внимания на троянский роутер), меняй
пароли на более сложные. Не ленись, настраивай iptables (не зря он стоит во всех
устройствах). Но, вместе с тем, этого недостаточно. Допустим, ты настроил
iptables так, чтобы он пускал к панели управления (ssh) только с твоего
IP-адреса — это не спасет! Надеюсь, не была забыта идея, проскочившая в прошлой
статье, о заражении с компьютера пользователя. И сложный пароль может быть
подобран, особенно если его брутит троян, снабженный средствами размножения.
Приведу один довольно действенный, но иногда неоправданно сложный способ;
сработает он, только если есть возможность периодически сливать с роутера образы
файловой системы и ядра. Заключается прием в проверке хешей файлов, и сверке их
с эталоном (официальной прошивкой). Полностью весь образ проверять не следует,
ведь там могут быть файлы, которые изменяются (конфигурационный файл, например),
поэтому пишем программу, которая раз в неделю, например, сливает образы,
распаковывает и сверяет хеши исполняемых файлов и загрузочных скриптов.
Выписка
Я планирую и дальше писать на тему заражения встраиваемых систем, ведь,
согласись, это настоящий клад для исследователя, ботовода и троянописателя. С
каждым днем количество и разнообразие подобных железок только растет — не стоит
медлить, завоюем этот фронт раньше других!
|