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

Обзор эксплойтов

Крис Касперски

Хакер, номер #103, стр. 040

Летняя жара, накрывшая добрую половину Европы вместе с Северным Кавказом и прилегающей к нему моей норой, была отмечена всплеском дыр в Windows CE, ростом уязвимостей в Горящем Лисе и традиционными дефектами в IE и MS Office. Но в целом интересных дыр очень мало. Настолько мало, что выбирать фактически не из чего. Жара плавит мозги, кондиционеры не справляются, и до осени на хакерском фронте наступает затишье.

Samba: множественные удаленные переполнения кучи

Brief

Samba – популярнейший открытый UNIX-клиент для «Сетей Microsoft», входящий в состав практически всех дистрибутивов и де-факто ставший стандартным клиентом. Хакеры уже давно ковыряли Samba на предмет наличия дыр. И вот наконец нашли. На свою голову. В конце апреля этого года четверо кодокопателей, пожелавших остаться неизвестными, обнаружили, что некоторые NDR-MS RPC-запросы срывают Samba крышу и высаживают ее на конкретное переполнение кучи с возможностью удаленного захвата управления. К этим запросам относятся: RFNPCNEX, DFSEnum, NetSetFileSecurity, LsarAddPrivilegesToAccount, LsarLookupSids/LsarLookupSids2 и некоторые другие. Вполне типичная ошибка: переданные данные копируются в буфер фиксированного размера без проверки их реальной длины. Разработчикам Sambа потребовалось всего три дня, чтобы вникнуть в ситуацию и выпустить первый патч, следом за ним последовали и другие. Дефектов оказалось больше, чем ожидалось, и работу удалось завершить только к 5 мая, а гриф секретности был снят лишь по прошествии десяти дней. А раз так, можно публиковать официальный пресс-релиз, тут же подхваченный многими ресурсами по безопасности, и в частности Security Focus'ом. Более подробную информацию можно найти на www.securityfocus.com/bid/23972.

Targets

Уязвимость подтверждена практически во всех версиях Sambа: 3.0.x; однако версия 3.0.25 вышла уже залатанной и потому неуязвима.

Exploit

Исходный текст боевого эксплойта, написанного на языке Руби и являющегося частью проекта Metasploit Framework, можно найти на Security Focus'e: www.securityfocus.com/data/vulnerabilities/exploits/23973-lsa_transnames_heap.rb.

Solution

Перейти на исправленную версию 3.0.25 или установить обновление безопасности, выпущенное поставщиком конкретного клона UNIX'а. Их список содержится на Security Focus'e: www.securityfocus.com/bid/24195/solution.

GDB: переполнение буфера

Brief

GDB, что расшифровывается как GNU Debugger, - основной (если не единственный) отладчик под UNIX, используемый кодокопателями для анализа вирусов, червей и прочих зловредных программ. Естественно, отладка потенциально опасных приложений всегда связана с огромным риском и, как правило, осуществляется на машине, на которой нет ничего ценного, такого, что было бы жалко потерять. Однако в любом правиле есть исключения. До сих пор считалось безопасным загружать файл в отладчик без его выполнения, используя GDB как дизассемблер. Однако хакер по кличке xwings опроверг это мнение, обнаружив ошибку переполнения в GDB, вызывающую Segmentation Fault при загрузке специальным образом подготовленных PE-файлов с искаженной структурой. Впрочем, корпорация Symantec, проанализировав ситуацию, по поводу последнего пункта выражает большие сомнения, подогревая интерес исследователей, находящихся как по одну, так и по другую сторону баррикады. Дефект локализован и находится в файле coffread.c, ответственном за парсинг COFF-файлов (а PE-файлы, как известно, являются разновидностью COFF). Отсутствие проверки длины копируемых данных вызывает классическое переполнение и рушит GDB со всеми отсюда вытекающими последствиями. Более подробную информацию можно найти в блоге http://blog.xwings.net/?p=71 или на Security Focus'е: www.securityfocus.com/bid/24291.

Target

Дыра обнаружена в версии 6.6 и в более старших. О ранних версиях ничего не известно, однако имеются все основания полагать, что они также уязвимы.

Exploit

Демонстрационный эксплойт, срывающий башню GDB, но не содержащий в себе никакого shell-кода, лежит на www.xwings.net/private/advisory/gdbupx.tar. Он представляет собой обычный PE-файл. Только сначала его упаковали UPX, а потом оторвали заголовок от основного тела.

Solution

На данный момент заплатки отсутствуют; остается лишь порекомендовать не загружать в отладчик потенциально опасных файлов.

Yahoo! Messenger Webcam: переполнение буфера

Brief

В первых числах июня хакер Greg Linares из исследовательского центра eEye Digital Security и (независимо от него) сотрудник корпорации Yahoo! обнаружили две дыры в ActiveX-компоненте, входящем в состав Yahoo! Messenger Webcam. Дефективный код находится в динамических библиотеках ywcupl.dll и ywcvwr.dll (версии 2.0.1.4), обеспечивающих возможность обмена файлами между пользователями (служба Yahoo! Webcam Upload). В обоих случаях принятые данные копируются в локальный буфер длиной 1023 байта без проверки их актуальной длины. И если строка не вмещается в буфер, то наступает классическое стековое переполнение с возможностью удаленного захвата управления. Подробный технический отчет лежит на http://research.eeye.com/html/advisories/published/AD20070608.html.

Targets

Уязвимость подтверждена в следующих версиях Yahoo! Messenger: 4.0, 5.0, 5.0.1046, 5.0.1065, 5.0.1232, 5.5, 8.0, 8.0.0.863, 8.0.1, а также в Yahoo! Instant Messenger версии 3.5. Yahoo! Messenger версии 8.1 уже неуязвим.

Exploits

Исходный HTML-код простейшего эксплойта (с shell-кодом на борту) смотри на нашем DVD. Как видно, он вполне типичен для ActiveX-эксплойтов, подробно рассмотренных в предыдущем обзоре. Еще пара эксплойтов, написанных на Си, лежит на milw0rm'е: www.milw0rm.com/exploits/4052 (атака на динамическую библиотеку ywcvwr.dll), www.milw0rm.com/exploits/4053 (атака на динамическую библиотеку ywcupl.dll).

Solution

Производитель уже выпустил обновление, настоятельно предлагая пользователям скачать его, щелкнув по ссылке http://messenger.yahoo.com/security_update.php?id=060707.

Mozilla Firefox URLBar: удаленное выполнение кода

Brief

12 июня, как раз в самый разгул жары, хакер по кличке 0x00000000 (и «по совместительству» владелец одноименного ресурса www.0x000000.com) обнаружил дыру, затрагивающую все версии Горящего Лиса и приводящую к возможности удаленного захвата управления как на Windows-, так и на UNIX-платформах. Если в адресной строке браузера ввести URL, содержащий ноль, заданный через спецификатор знака процента (%00), то Лис запутается с определением типа файла: он может, например, решить, что имеет дело с pdf, в то время как это exe. Аналогичным образом обстоят дела и с обработкой тегов <A HREF=xxx>, размещенных на зловредной хакерской странице. Более подробную информацию можно найти в статье «Firefox Remote & Local Code Excution 0day» (www.0x000000.com/?i=333).

Targets

Уязвимость подтверждена практически во всех версиях Mozilla Firefox.

Exploit

HTML-код простейшего демонстрационного эксплойта, ориентированного на W2K, приведен ниже (под XP и Висту он работает ничуть не хуже, достаточно только скорректировать путь к исполняемому файлу).

HTML-код, заставляющий Горящего Лиса считать, что исполняемый файл «Калькулятора» является документом pdf

<A HREF=file:///C:/WINNT/System32/calc.exe%u0000.pdf>download</A>

Solution

Внимательно смотреть на подлинное расширение файла перед его открытием!

Full disclose

Сама по себе уязвимость еще не создает глобальный угрозы (так, мелкий дефект проектирования), но она очень хорошо подходит в качестве наглядного пособия для иллюстрации целого класса аналогичных дыр, вызванных смешенным стилем программирования с использованием строковых переменных разных типов.

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

Исторически сложилось так, что наибольшее распространение получил ASCIIZ-тип, представляющий собой последовательность байт с завершающим символом нуля на конце (называемым «термирующим символом», или «символом-терминатором»). В DEC- и x86-процессорах имеются специальные команды для их обработки, однако в целом производительность ASCIIZ-строк просто отвратительна. В частности, чтобы объединить две строки, необходимо последовательно прочитать все символы строки-приемника, найти символ нуля и дописать туда строку-источник. Байт за байтом. Обработку двойными и четверными словами (наиболее эффективную с точки зрения современных процессоров) ASCIIZ-строки, увы, не допускают, поскольку одной машинной командой невозможно выяснить, содержится ли в этом двойном/четверном слове нулевой байт или нет. То же самое относится и к операциям сравнения, определения длины строки и т.д. (еще можно вспомнить MS-DOS-строки, заканчивающиеся символом доллара и в настоящее время практически вышедшие из употребления).

Pascal-строки, хранящие в первом байте строки ее длину (за вычетом самого этого байта), намного более эффективны, поскольку допускают обработку двойными и четверными словами, а при объединении двух строк позиция дозаписи определяется всего за одно обращение к памяти. Самое главное: в отличие от ASCIIZ-строк, Pascal-строки могут содержать символ нуля, поскольку с их точки зрения он не является завершителем.

Однако максимально возможная длина Pascal-строки составляет всего 255 байт, что является серьезным недостатком. Потому в Delphi для хранения длины строки используется 16-битное поле (также называемое префиксом длины), увеличивающее предельный размер строк до 65,535 байт, которых в некоторых ситуациях оказывается недостаточно, и тогда приходится прибегать к Wide-Pascal строкам, отводящим под префикс длины аж 4 байта, что, естественно, снижает КПД, особенно на коротких строках.

Поскольку компиляторы уже давно перестали быть «вещью в себе» и активно взаимодействуют с внешним миром, они поневоле вынуждены считаться с его законами. Во внешнем мире ситуация такова, что системные вызовы UNIX'а, API-функции Windows и функции стандартной библиотеки Си используют ASCIIZ-строки. Попытка передачи им Pascal-строки в качестве параметра приводит к краху, поскольку функция трактует поле длины как рядовой символ и бежит вдоль строки до тех пор, пока не встретит терминатора, врезаясь в постороннюю область памяти, поскольку в Pascal-строках никакого терминатора нет.

Решение проблемы заключается в «гибридизации» обоих типов строк. В частности, MFC-строки содержат и термирующий символ нуля на конце, и префикс длины строки. Строковые операции внутри MFC-библиотеки всегда выполняются через префикс длины, благодаря чему строка может содержать сколько угодно нулей. При передаче строки в качестве аргумента функции, ожидающей ASCIIZ-тип, ей скармливается указатель на первый действительный символ строки, находящийся за префиксом длины, и фактическая длина строки оказывается равной расстоянию до первого терминатора. Налицо явное противоречие!

Ты спросишь, в чем, собственно, противоречие? А вот мы сейчас и покажем! Рассмотрим следующую MFC-строку, представляющую собой имя файла: «myfile.ext1\x00.ext2\x00», где первый \x00 – умышленно внедренный символ нуля, а второй – честный терминатор строки.

С точки зрения библиотеки MFC фальшивый терминатор является равноправным символом, и полная длина строки равна 17 байтам (16 эффективных байт плюс один настоящий терминатор). Как определить расширение файла? Поскольку операционные системы UNIX и Windows допускают присутствие точек внутри имени файла, а длина расширения не обязана всегда быть равной трем байтам, то, строго говоря, определить расширение файла в общем случае невозможно. Вот, например, kpnc.info – это что такое? Файл без расширения с точкой внутри или файл kpnc с расширением info? Оба варианта возможны, и единственной зацепкой являются общепринятые расширения типа ps, txt, html и т.д. Однако, как бы там ни было, разбор имени файла всегда необходимо начинать с его конца, сравнивая каждый байт с символом точки. Начинающие программисты часто допускают грубую ошибку, выполняя разбор с начала и трактуя первую же встретившуюся точку как границу между именем и расширением, в результате чего их «творения» тут же валятся на примерах типа kris.kaspersky.pdf.

При выполнении разбора средствами библиотеки MFC мы перемещаемся на символ, предшествующий подлинному терминатору, и, двигаясь влево, выкусываем расширение «.ext2», которое и отображаем на экране с самодовольным похрюкиванием (или без похрюкивания), сопоставляя с файлом соответствующее ему приложение.

А вот если попробовать открыть этот файл с помощью стандартной библиотеки языка Си или передать его какой-нибудь API-функции операционной системы, то произойдет следующее: компилятор отбросит префикс длины и возвратит указатель на первый действительный символ строки (в данном случае это символ m). Двигаясь вправо, API-функция будет перебирать содержимое строки до тех пор, пока не встретится с нулевым символом, которым здесь является фальшивый терминатор, расположенный сразу за концом «.ext1», трактуемым как расширение имени файла. Остальная часть строки будет отброшена, что не покажется удивительным, если вспомнить, что API-функции работают с ASCIIZ-типом и подлинной длины строки не могут знать в принципе! Как следствие, произойдет подмена типов, и пользователь, уверенный, что он открывает безобидный документ, на самом деле запустит исполняемый файл. Впрочем, тут возможны варианты, затрудняющие реализацию атаки. В частности, если уязвимое приложение самостоятельно сопоставляет тип файла с обрабатывающим его приложением, то при попытке открытия myfile.exe\x00.pdf запустится Acrobat Reader и попробует открыть myfile.exe. Это у него, естественно, не получится, и вместо захвата управления мы словим ругательство Acrobat'а по поводу неправильного формата файла. А вот если файл открывается API-функциями ShellExecute/ShellExecuteEx, то сопоставление типа и расширения ложится на плечи операционной системы и она послушно запускает myfile.exe, причем уязвимое приложение находится в полной уверенности, что это безобидный pdf, высвечивая его иконку, вводящую неискушенного пользователя в заблуждение.

В UNIX-подобных системах проблема стоит еще более остро. Расширения в них играют сугубо вспомогательную роль, и тип файла, как правило, определяется по его содержимому. Правда, исполняемые файлы должны иметь соответствующий атрибут (а пользователю, работающему с уязвимым приложением, еще необходимо обладать правами его установки), в противном случае атака не состоится.

Наконец, запускать можно только файлы, уже находящиеся на локальном диске жертвы, что существенно ограничивает поле деятельности атакующих. Однако можно пойти на хитрость: сначала дать пользователю скачать файл с подложным расширением на диск, а потом запустить его, ну или подождать, пока тот не сделает это самостоятельно. Допустим, жертва видит ссылку total.com mander-manual.pdf и думает, что это описание к Total Commander'у, сохраняя его на диск, но вместо этого сохраняется только total.com (ведь имена файлов нулей содержать не могут). Если жертва не попытается открыть файл сразу же после окончания скачки, а вернется к нему спустя некоторое время, то есть шанс, что, обнаружив в папке Download (название, разумеется, условно) файл total.com, она запустит его! Не секрет, что большинство пользователей сначала качают все подряд, а потом начинают разгребать скачанное, запуская файлы один за другим.

Анализ приложений, написанных на DELPHI, MFC и других языках/библиотеках, использующих гибридный строковый тип, выявляет большое количество потенциальных дыр, одна из которых была обнаружена в ранних версиях популярного почтового клиента The Bat!

Поиск уязвимых программ даже не требует их дизассемблирования. Достаточно просто методично внедрять нулевые символы в имена файлов (и в прочие параметры, передаваемые API-функциями операционной системы) и смотреть, что из этого получается. Некоторые приложения позволяют внедрять нулевые символы легальными средствами (например, %00 в URL'е), но подавляющее большинство остальных так просто не проведешь. Их приходится хачить путем внедрения терминаторов непосредственно в сетевые пакеты или искать другие способы.

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

Содержание