Exploits review (выпуск 9)

Автор: (c)Крис Касперски ака мыщъх

После предновогодней лавины дыр, хлынувшей сквозь весь спектр программных и аппаратных продуктов, сотрясающие их словно неожиданно проснувшийся вулкан, считавшийся давно потухшим, в январе-феврале наступило ленивое затишье. Не считая очередной порции дыр в IE, Office и Mozille, никаких новых потрясений не последовало и счет открытых уязвимостей пошел на единицы, о самых интересных их которых мыщъх и собирается рассказать.

Удаленный BSOD на Intel 2200BG 802.11

brief

Очередная дыра в драйверах беспроводных устройств, обнаруженная хакером по имени Breno Silva Pinto из компании sekure.org, показывает, насколько еще сыры и небезопасны беспроводные технологии. Сценарий атаки вполне типичен: на жертву обрушивается мощный шквал "разобщенных" (disassociation) пакетов. Пакеты схватывает драйвер и складывает их в кучу для дальнейшей обработки, в процессе которой модифицируются глобальные (для драйвера) структуры данных, защищаемые критическими секциями и прочими средствами синхронизации, но... небрежно реализованная синхронизация (а когда она реализовалась иначе?) привела к серьезным дефектам и часть структур данных осталась незащищенной, в результате чего появилась угроза их разрушения - если в процессе обработки одного пакета приходит другой, структуры данных превращаются в мешанину и дальнейшее поведение драйвера становится непредсказуемым. Как правило, дело заканчивается Голубым Экраном Смерти (т.е. отказом в обслуживании). И, хотя существует возможность передать зловредный shell-код и захватить управление ЦП на уровне нулевого кольца, пока она остается только в теории. Подробности об уязвимости лежат на http://www.securityfocus.com/bid/22260;

targets

Уязвимость подтверждена в "родном" Intel-драйвере w29n51.sys версии 9.0.3.9, датированном 09/12/2005 и управляющим беспроводными устройствами, смонтированными на адаптерах типа Mini-PCI (см. рис. 1), часто встречающихся в ноутбуках и лаптопах. Другие версии драйвера не проверялись, но существуют достаточно веские основания утвердить, что подобные дыры есть и в них.

exploit

Исходный текст exploit'а, написанного все тем же Breno Silva Pinto (bsilva@secure.org) можно скачать с http://www.milw0rm.com/exploits/3224, а если он ("он" - сервер) лежит (убит, висит), то с http://www.securityfocus.com/data/vulnerabilities/exploits/22260.c;

solution

На момент написания этих строк, компания Intel не выпустила никакого обновления и даже не уведомила пользователей о грозящей им опасности, что вообще беспредел: www.intel.com/network/connectivity/products/wireless/prowireless_mobile.htm, а потому, единственным возможным решением становится отключение беспроводных устройств (исправить дефект синхронизации патчем двоичного файла нереально);

Mini-PCI плата

Рисунок 1. Mini-PCI плата с чипом Intel 2200BG 802.11, управляемым уязвимым драйвером.

Sun Java - переполнение буфера в библиотеке времени исполнения

brief

Java, изначально позиционируемая как абсолютно безопасная среда программирования, таковой, увы, не оказалась и от Java-аплетов можно ожидать всего, чего угодно (на них не только игры, но и вирусы пишут). Самое неприятное, что помимо изъянов в архитектуре безопасности, дефекты обнаруживаются и в самом фундаменте - компиляторе, библиотеке времени исполнения и т.д. Кодокопатель, работающий на компанию Zero Day Initiative (www.zerodayinitiative.com) наряду с TippingPoint (www.tippingpoint.com) - подразделением корпорации 3Com, "окучивающим" вопросы безопасности, обнаружил грубую ошибку в штатном gif-обработчике: если ширина валидного изображения выставлена в ноль, то библиотека времени исполнения выделяет указанное в заголовке количество байт, которое может и не совпадать с фактическим, в результате чего наступает классическое переполнение, допускающее возможность передачи управления на shell-код, содержащийся в этом же самом изображении. за подробностями обращайтесь к отчету компании Zero Day Initiative: http://www.zerodayinitiative.com/advisories/ZDI-07-005.html;

targets

Уязвимость обнаружена в SDK и JRE версий вплоть до 1.4.2 (включая более ранние) и JDK/JRE версии 5.0 с обновлением 9, а также в продуктах сторонних компаний, построенных на их основе, в частности, в Avaya Interactive Response версий 1.3 и 2.0;

exploit

Исходный код боевого exploit'а, созданного хакером по кличке luoluo (luoluonet@hotmail.com || luoluonet@126.com || luoluonet@yahoo.com) в тесной кооперации с членами команды Ph4nt0m Security Team (http://www.ph4nt0m.org), лежит на Security Focus'e: www.securityfocus.com/data/vulnerabilities/exploits/JvmGifVulPoc.java и несет на своем борту shell-код, запускающий calc.exe (см. рис. 2), однако после доработки "напильником" он будет запускать все, что угодно, в том числе и back-door.

solution

Компания Sun уже выпустила обновления для различных версий SDK и JRE, доступное по ссылке http://java.sun.com/javase/downloads/index_jdk5.jsp, с продуктами же сторонних компаний ситуация до сих пор остается туманной и неясной, однако судя по популярности Java, их число должно быть весьма велико, так что дерзайте - широкое поле для исследований открыто!!!

Фрагмент боевого exploit-а

Рисунок 2. Фрагмент боевого exploit'а от luoluo, запускающего "калькулятор".

uTorrent - Удаленное переполнение кучи

brief

Популярность легендарного осла (клиента файлообменной сети eDonkey) начинает постепенно слабеть под агрессивным натиском файлообменной сети нового поколения - BitTorrnet (используемой в том числе и для легального распространения дистрибутивов некоторых клонов Linux'а и BSD), одним из клиентом которой и является программа uTorrent (http://www.utorrent.com/), внешний вид которой показан на рис. 3. В отличии от осла, носящего свой хвост всегда с собой, в сети BitTorrnet обмен варезом осуществляется через специальные torrent-файлы, которые в свою очередь распространяются через того же осла или web. Структура torrent-файлов (вместе с принципами работы самой сети) описана на http://en.wikipedia.org/wiki/BitTorrent. Ошибка, допущенная разработчиками uTorrent'а, вполне банальна - копируя данные из полей torrent-файла в динамически выделяемые блоки памяти, они полагаются на авось и никаких проверок не выполняют, в результате чего у хакеров появляется возможность через специальным образом сконструированный torrent-файл, захватывать управление узлами, на которых установлены клиенты uTorrent. уязвимость обнаружена компанией defsec (http://www.defacedsecurity.com), пославшей свой отчет на Security Focus, где ему был присвоен номер 22530: http://www.securityfocus.com/bid/22530/;

target

На данный момент уязвимость подтверждена в версии uTorrent 1.6, более ранние версии не проверялись, но судя по всему, они также уязвимы;

exploit

Исходный текст exploit'а можно нарыть на http://www.milw0rm.com/exploits/3296, ссылка на Security Focus'e - http://www.securityfocus.com/data/vulnerabilities/exploits/22533.c битая и выдает знаменитую ошибку 404;

solution

На момент написания этих строк разработчики uTorrent'а никак не отреагировали на сообщение об уязвимости и не выпустили никаких обновлений, поэтому лучшим решением будет отказ от использования uTorrent в пользу других клиентов;

Внешний вид программы uTorrent

Рисунок 3. Внешний вид программы uTorrent - уязвимого клиента файлообменной сети BitTorrent.

Full disclose - Linux Kernel: DoS при обработке ISO9660

brief

Легендарный хакер по кличке LMH (основавший не менее легендарный проект MOKB - Month of Kernel Bugs - http://projects.info-pull.com/mokb, lmh@info-pull.com), известный своими маньяческими замашками, в ноябре 2006 года изнасиловал ядро LINUX'а в особо зверской форме, подсунув ему садистским образом испорченный образ ISO9660 (основная файловая система лазерных дисков, поверх которой обычно "натянута" Джульетта, поддерживающая длинные имена и другие фишки), погрузивший ядро в состояние глубокой медитации, граничащей с нирваной, частным случаем которой является бесконечный цикл. В практическом плане это означает, что любой пользователь, обладающий правами монтирования дисков (или при задействованном автоматическом монтировании cd-rom) может устроить тотальный DoS, что не есть хорошо, особенно в случае сервера, для которого перезагрузка без правильного завершения работы зачастую сопровождается значительными потерями данных. Это довольно древняя ошибка (где мы, а где 2006 год?!), подробнее о которой можно прочитать на: http://projects.info-pull.com/mokb/MOKB-05-11-2006.html, но исправить ее удалось лишь 30 января 2007 года - http://rhn.redhat.com/errata/RHSA-2007-0014.html, так что количество уязвимых узлов достаточно велико. Поэтому прежде чем смонтировать iso-образ, полученный из ненадежных источников, следует как минимум сохранить все несохраненные данные;

targets

Дефект в ядре версии 2.6.18, более древние ядра не тестировались, однако есть все основания полагать, что данная ошибка присутствует и в них;

exploit

Испорченный iso-образ (сжатый архиватором bzip и занимающий всего 696 Кбайт) лежит на http://projects.info-pull.com/mokb/bug-files/MOKB-25-11-2006.img.bz2, чтобы его смонтировать без записи на CD-R/RW следует выполнить следующие команды:

$ bunzip2 MOKB-05-11-2006.iso.bz2
$ mount -t iso9660 -o loop MOKB-05-11-2006.iso /media/test
$ ls /media/test

solution

Патчи для RedHat можно скачать с http://rhn.redhat.com/errata/RHSA-2007-0014.html, а для SuSE - http://www.securityfocus.com/bid/20920/solution, что же касается остальных поставщиков, то они, похоже, не считают эту ошибку критической и не спешат выкладывать обновления;

Full disclose

История эта была бы очень смешной, ни будь она такой грустной. Файловая система - это фундамент любой оси, отвечающий за сохранность наших данных. Помимо архитектуры самой файловой системы необходимо иметь доброкачественный драйвер, сохраняющий работоспособность при любых разрушениях, в противном случае даже небольшой дефект может привести к потере всего дискового тома, размеры которого в наши дни измеряются сотнями гектар!

Исследовательская программа, развернутая LMH, обнаружила огромное количество ошибок в драйверах практически всех файловых систем - Linux: ex2/3fs, gfs2, ntfs, ReiserFS, FreeBSD/Solaris: UFS, Mac OS: HFS+ и т.д., что наводит на грустные размышления по поводу надежности того, на чем мы сидим. За подробностями обращайтесь к блогу "Kernel Fun - Kernel bugs and madness" (http://kernelfun.blogspot.com/search/label/fsfuzzer).

Изумительный блог

Рисунок 4. Изумительный блог "Kernel Fun", целиком и полностью посвященный разнообразным способам изнасилования ядра LINUX'а в особо извращенной форме.

Для экспериментов использовалась бесплатная утилита fsfuzzer (http://projects.info-pull.com/mokb/fsfuzzer-0.6-lmh.tgz), генерирующая испорченные образы различных файловых систем, на которых изучается реакция соответствующего драйвера. Кто-то может заметить, что драйвер вовсе не подписывался "переваривать" серьезные искажения базовых структур данных и что в реальной жизни такие разрушения практически никогда не возникают. На самом деле, драйвер файловой системы обязан сохранять работоспособность при любых разрушениях, "вытаскивая" максимум уцелевшей информации. Отказ монтировать разрушенный том вполне допустим (хотя и крайне нежелателен), а вот за выпадение в бесконечный цикл нужно расстреливать на месте без права переселения душ. Собственно говоря, этой статьей мыщъх хотел подтолкнуть своих сородичей-хакеров к активным действиям в отношении файловых систем, ведь чем больше ошибок будет выявлено в ходе садистских издевательств, тем меньше их останется в реальной жизни. К слову сказать, потеря данных под Linux - не редкость и мыщъху довольно часто приходится чинить испорченные дисковые тома в hex-редакторе (именно в hex-, а не в disk-, поскольку в Linux/BSD в отличии от Windows, с диском можно работать как с файлом и любой нормальный hex-редактор легко переварит /dev/xxx. ну вот сейчас кто-то встрянет и скажет, что и в Windows диск можно открывать функций CreateFile и работать с ним как с файлом. Теоретически (т.е. на концептуально-архитектурном уровне) безусловно да, но вот на житейски практическом ни хвоста подобного!!! Прежде всего, штатными средствами Windows нельзя демонтировать диск и соответствующую утилиту придется писать самостоятельно, во-вторых, методика работы с файлами и устройствами под Windows довольно существенно различается и hex-редактор просто не сможет работать с диском, если только такая возможность в него не закладывалась изначально). Ладно, все это лирика. Переходим к практике.

Разбираться, что именно искажено в образе, сгенерированном утилитой fsfuzzer - лениво и бесполезно, хотя желающие поковыряться могут это сделать при помощи комплекса утилит, прилагаемых к книге "Техника защиты лазерных дисков от копирования", которую (как и многие другие книги мыщъха) можно найти на недавно воздвигнутом им http-сервере, на данный момент представляющим собой простое зеркало ранее воздвигнутого ftp. Соответственно, адрес все тот же, а график работы варьируется в зависимости от обстоятельств. Короче, стучитесь и вам откроют. Только долбиться дятлом не надо, ладно? Вот и хорошо! А мы тем временем продолжим.

http://nezumi.org.ru

Рисунок 5. http://nezumi.org.ru - web-сервер, воздвигнутый посреди мыщъх'иной норы и открыто раздающий заначки всем желающим!

Будем плясать от печки, то есть от исходных текстов ядра, а точнее даже не всего ядра, а драйвера файловой системы ISO9660, которые можно найти, например, на http://lxr.linux.no/source/fs/isofs/ (хотя любой нормальный дистрибутив должен поставляться вместе с исходными текстами, так что можно обойтись и без интернета).

Исходные тексты ядра Linux

Рисунок 6. Исходные тексты ядра Linux'а в Интернете (полезны тем, кто Linux'а еще не имеет, но уже им интересуется).

Как именно локализовать ошибку в драйвере? В нашем случае это делается очень просто - монтируем испорченный образ, пытаемся войти в корневой каталог и... ядро разряжается пулеметной очередью грязных ругательств, выплевываемых в бесконечном цикле в файл /proc/kmsg (наверняка при этом использовались вращающиеся стволы с продувкой сжатым воздухом для лучшего охлаждения).

Короче, на ядрах семейства 2.6.х мы должны увидеть вот это:

__find_get_block_slow() failed. block=18446744073457893405, b_blocknr=4043309084
b_state=0x00000020, b_size=2048
device blocksize: 2048
__find_get_block_slow() failed. block=18446744073457893405, b_blocknr=4043309084
b_state=0x00000020, b_size=2048
device blocksize: 2048
__find_get_block_slow() failed. block=18446744073457893405, b_blocknr=4043309084
b_state=0x00000020, b_size=2048
device blocksize: 2048
__find_get_block_slow() failed. block=18446744073457893405, b_blocknr=4043309084
b_state=0x00000020, b_size=2048
device blocksize: 2048
__find_get_block_slow() failed. block=18446744073457893405, b_blocknr=4043309084
b_state=0x00000020, b_size=2048
device blocksize: 2048
__find_get_block_slow() failed. block=18446744073457893405, b_blocknr=4043309084
b_state=0x00000020, b_size=2048
device blocksize: 2048
__find_get_block_slow() failed. block=18446744073457893405, b_blocknr=4043309084
b_state=0x00000020, b_size=2048
device blocksize: 2048

Листинг 1. Сообщения, выплевываемые ядром в файл /proc/kmsg, при просмотре дефективного ISO9660-образа.

Кстати говоря, ядра семейства 2.4 ведут себя гораздо спокойнее (см. рис. 7), лаконично сообщая о невозможности монтажа испорченного образа из-за ошибки чтения i-node блока (см. листинг. 2).

Монтирование дефективного ISO9660

Рисунок 7. Монтирование дефективного ISO9660 образа под Linux-ядром версии 2.4.27.

<6>loop: loaded (max 8 devices)
<7>ISO 9660 Extensions: Microsoft Joliet Level 3
<6>attempt to access beyond end of device
<6>07:00: rw=0, want=3670074, limit=12698
<4>ISOFS: unable to read i-node block
<7>ISOFS: changing to secondary root

Листинг 2. Фрагмент файла /proc/kmsg - реакция ядра версии 2.4.27 на дефективный ISO9660 образ.

Таким образом, мы знаем, что ошибка сидит в 2.6.x ядре и сосредоточена где-то в окрестностях функции __find_get_block_slow(), имя которой ядро и выводит в /proc/kmsg, смотрим в исходные тексты:

386 __find_get_block_slow(struct block_device *bdev, sector_t block)
387 {
*** [skip] [skip] [skip] [skip] [skip] [skip] [skip]
402        spin_lock(&bd_mapping->private_lock);
403                if (!page_has_buffers(page))
404                        goto out_unlock;
405                head = page_buffers(page);
406                bh = head;
407                do {
408                        if (bh->b_blocknr == block) {
409                                ret = bh;
410                                get_bh(bh);
411                                goto out_unlock;
412                        }
413                        if (!buffer_mapped(bh))
414                                all_mapped = 0;       // <------<
415                        bh = bh->b_this_page;
416                } while (bh != head);
417
418        /* we might be here because some of the buffers on this page are
419        * not mapped. This is due to various races between
420        * file io on the block device and getblk. It gets dealt with
421        * elsewhere, don't buffer_error if we had some unmapped buffers
422        */

423        if (all_mapped) {
424                printk("__find_get_block_slow() failed. "
425                "block=%llu, b_blocknr=%llu\n",
426                        (unsigned long long)block,
427                        (unsigned long long)bh->b_blocknr);
428                        printk("b_state=0x%08lx, b_size=%zu\n",
429                                bh->b_state, bh->b_size);
430                        printk("device blocksize: %d\n", 1 << bd_inode->i_blkbits);
431        }
432 out_unlock:
433        spin_unlock(&bd_mapping->private_lock);
434        page_cache_release(page);
435 out:
436        return ret;
437 }

Листинг 3. Ключевой фрагмент функции __find_get_block_slow(), вызываемой в бесконечном цикле из ядра 2.6.х при чтении дефективного ISO9660-образа.

Сразу же ищем вызовы функции printk (записывающей ругательные сообщения в файл /proc/kmsg), находящиеся практически в самом конце __find_get_block_slow и предваренные следующим комментарием: "we might be here because some of the buffers on this page are not mapped. This is due to various races between file io on the block device and getblk. It gets dealt with elsewhere, don't buffer_error if we had some unmapped buffers" ("мы можем очутиться здесь, если один или несколько буферов на этой странице не были спроецированы в память, что случилось по причине "гонки потоков" на операциях ввода/вывода блочного устройства и функции getblk. если мы имеет несколько не спроецированных буферов, то ошибка находится черт знает где, но не в функции buffer_error").

Судя по комментарию, причина кроется в некорректно реализованной синхронизации потоков, что "подтверждается" отчетами, опубликованных целым рядом компаний специализирующихся на безопасности, неполный перечень ссылок на которые можно найти на http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-5757.

В действительности же все эти компании просто перепечатали исходный комментарий, не проводя никаких дополнительных исследований. Но комментарий - это не Коран и совсем не божественное откровение, в которое можно только верить, но нельзя проверить. Простейший эксперимент опровергает теорию гонки, поскольку ошибка проявляется как на однопроцессорных, так и на многопроцессорных системах и уж тем более странно, чтобы потоки гнались в этом месте.

Просматривая "заплатку" для ядра от Fabio M. Di Nitto (fabbione@ubuntu.com) мы видим следующий комментарий в diff-файле: http://security.ubuntu.com/ubuntu/pool/main/l/linux-source-2.6.12/linux-source-2.6.12_2.6.12-10.45.diff.gz:

+ * [SECURITY] Fix a bunch of range checks in ISO9660 fs:
+ - Add patch stolen-from-head_iso9660-flaws.dpatch.
+   (CAN-2005-0815)

Листинг 4. Комментарий в заплатке, исправляющей множественные ошибки в драйвере файловой системы ISO9660.

"Исправления множества проверок на принадлежность числа к диапазону в ISO9660 fs" - и никаких гонок потоков!!! Незалатанная версия драйвера файловой системы ISO9660 манипулировала ключевыми структурами данных, забывая о необходимости проверки корректности содержащихся в них значений. И вот - результат! Теперь этот недостаток исправлен и сами исправления настолько обширны, что здесь попросту не хватит места, чтобы привести даже небольшую часть из них. Да и какой смысл, когда каждый может заглянуть в diff-файл самостоятельно? Тем более, что проверки тривиальны и не несут в себе абсолютно ничего интересного. Обычные рутинные операции повседневных будней программиста. И вот в этих самых "буднях" концентрация ошибок достигает максимальной плотности на количество строк исходного текста. Что поделаешь - однообразная, унылая работа всегда рассеивает внимание...