exploits-review-0x003

exploits review III

крис касперски ака мыщъх, no-email

brief:18 апреля 2006 года обнаружилась дыра в процессорах AMD K7/K8 позволяющая одному процессору заглянуть внутрь сопроцессорного контекста другого процесса, что ведет к утечке данных и упрощает атаку на криптографические системы: www.securityfocus.com/bid/17600;

для быстрого переключения контекста Linux и BSD-системы используют пару команд fxsave/fxrstor, сохраняющих/восстанавливающих регистры сопроцессора в/из оперативной памяти. коварство fxrstor заключается в том, что она сохраняет указатель команд (FIP), указатель данных (DataPointer) и опкод последней инструкции _только_ в том случае, если бит ES (exceptionsummary) в статусном слове сопроцессора x87 установлен. при переключении контекста ось не обнуляет эти данные и они становятся доступны «посторонним» процессам: kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.16.9;

targets:строго говоря, это не ошибка, а документированная особенность процессоров AMD, на которую прежде никто не обращал внимания, поскольку с процессорами Intel в этом плане все ОК. уязвимость затрагивает _все_ LINUX и BSD системы, а, возможно, и Windows.

exploit:для реализации атаки exploit'а не требуется, достаточно просто выполнять команду fxsave в цикле, надеясь, поймать что-то интересное.

solutionразработчики LINIX/BSD уже выпустили патчи: securityfocus.com/bid/17600/solution, очищающее ES-бит и загружающие фиктивный double на стек сопроцессора. вот фрагмент заплатки для BSD:

staticdoubledummy = 0.0;

static fpu_clean_state()

{

u_short status;fnstsw(&status);

if (status&0x80) fnclex();

asm volatile(«ffree %%st(7);fld %0» : : «m» (dummy));

}

рисунок 1 значения EIP/RIP, FOP и DataPointer сохраняются только, если бит ES установлен

brief:JariKirma — один из разработчиков FreeBSD — обратил внимание, что на AMDx86-64 непривилегированный пользователь может получить непосредственный доступ к оборудованию с прикладного уровня. это объясняется тем, что x86-64 имеет два механизма разделения привилегий: код, исполняющий на уровне ядра, имеет доступ ко всем портам ввода/вывода и обычно является «посредником» между железом и user-mode, что не всегда удобно, поэтому, процессор поддерживает специальную карту, позволяющую «открыть» часть портов, разрешив к ним доступ с прикладного уровня (подобная карта имеется у Intel'а, но там она по умолчанию заблокирована)

суть в том, что вплоть до FreeBSD/amd64 5.4-RELEASE эта таблица инициализировалась _неправильно_ образуя огромную дыру в системе безопасности. злоумышленник (или некорректно работающий код) может вызывать отказ в обслуживании, разрушать или похищать информацию и т. д., подробнее об этом можно прочитать на: www.security.freebsd.org/advisories/FreeBSD-SA-05:03.amd64.asc.

targets:уязвимость затрагивает только операционную систему FreeBSD версии 5.4 или ниже, работающую на платформе AMDx86-64. на все остальные системы эта дыра не распространяется;

exploit:для реализации данной уязвимости exploit не требуется, достаточно установить обработчик исключений и последовательно перебрать все порты, определяя какие из них доступны на запись/чтение, а какие нет.

solutionсуществует несколько решений этой проблемы: например, обновить систему до версии 5-STABLE или наложить заплатку, которую можно скачать с сервера ftp://ftp.FreeBSD.org/pub/FreeBSD/CERT/patches/SA-05:03/amd64.patch, после чего перекомпилировать ядро.

exploits-review-0x003_image_1.jpg

рисунок 2 AMD-64 собственной персоной

brief:8 августа 2006 года сразу два специалиста ReedArvin из Canaudit, Inc и MattMiller из LeviathanSecurityGroup обратили внимание на то, что процесс winlogon.exe (ответственный за регистрацию пользователей в системе, блокировку компьютера и т. д.) начинает поиск динамических библиотек с домашнего каталога пользователя и только потом переходит к системному каталогу Windows, поэтому любой пользователь может легко повысить свои привилегии до SYSTEM, если положит в свой домашний каталог «заряженную» DLL. удаленная атака легко реализуется через зловредную web-страничку, запрашивающую имя пользователя и пароль. IE их высылает автоматически и, если компьютер допускает удаленные подключения (что характерно для серверов), злоумышленнику достаточно закинуть DLL в HOME, выйти из системы и войти еще раз. подробности тут: www.microsoft.com/technet/security/Bulletin/MS06-051.mspx__; targets:уязвимости подвержены: Windows 2000, XP SP1, XP SP 2, Server 2003 и Server 2003 SP1. exploits:для реализации данной атаки exploit не требуется. solutionMicrosoft уже выпустила заплатки для всех уязвимых системы, выложив их на download-сервер. если же, по каким-то причинам он недоступен, можно воспользоваться альтернативным решением, задействовав режим безопасного поиска динамических библиотек. для этого необходимо запустить редактор реестра (regedt32.exe), открыть следующую ветвь реестра HKLM\SYSTEM\CurrentControlSet\ Control\SessionManager и добавить значение «SafeDllSearchMode» типа DWORD, установленное в 1, после чего перезагрузить машину. рисунок 3 процесс winlogon.exe по умолчанию ищет динамические библиотеки в домашней директории пользователя ===== full disclose
Microsoft Remix: илиноваядырав RPC ===== brief:за Microsoft уже закрепилась устойчивая репутации компании, никогда не исправляющий крупные ошибки с первого раза. вот и сейчас, когда эпидемия MSBLAST еще свежа в памяти (и мутированные черви до сих пор бродят по Сети), в RPC (RemoteProcedureCall – механизм удаленного вызова процедур) обнаружилась новая ошибка переполнения, допускающая удаленную засылку shell-кода с захватом управления на правах SYSTEM. мы не знаем, кто первый обнаружил ошибку, но 8 августа 2006 года Американское Общество US‑CERT (UnitedStatesComputerEmergencyReadinessTeam) и Калифорнийский Институт SANS (SysAdmin, Audit, Network, Security) практически одновременно выслали свои раппорты в Microsoft. публичный пресс-релиз (www.kb.cert.org/vuls/id/650769) не раскрывал никаких технических деталей, но несмотря на это, 10 августа уже появился рабочий exploit, являющийся частью проекта MetasploitFramework:
www.metasploit.com__.

Microsoft присвоила уязвимости критический уровень безопасности и в тот же день выпустила бюллетень MS06-040: microsoft.com/technet/security/Bulletin/MS06-040.mspx.

exploits-review-0x003_image_3.jpg

Рисунок 4 стартовыйэкран Metasploit Framework

targets:Microsoft занесла в список уязвимых систем Windows 2000, XP SP1, XP SP2, Server 2003 и Server 2003 SP1, в то время как создатели MetasploitFrameworkexploit'а претендовали на «поддержку»: NT 4.0, Windows 2000 SP0-SP4, XP SP0-SP1, подчеркивая что удаленное выполнение shell-кода на XP SP2/Windows 2003 SP1 невозможно и максимум, что можно устроить это — отказ в обслуживании. неудачная атака вызывает перезагрузку Windows 2000 и остановку всех SMB-сервисов на XP. парни из MicrosoftSecurityResponseCenterBlog провели свое собственное расследование и выяснили, что удаленное выполнение кода возможно _только_ на Windows 2000 и XP SP 1. им не удалось атаковать ни XP SP 2, ни Server 2003, ни Server 2003 SP 1: blogs.technet.com/msrc/archive/2006/08/11/446078.aspx (однако следует помнить, что между «не удалось атаковать» и «атаковать невозможно» огромная разница!).

рисунок 5 блог команды Security Response Center

exploit:готовый exploit (написанный на языке Perl) можно свободно скачать по адресам: http://metasploit.com/projects/Framework/exploits.html#netapi_ms06_040 и http://milw0rm.com/exploits/2162;

Рисунок 6 exploit MS Windows NetpIsRemote() Remote Overflow насайте MilwOrm

solutionMicrosoft уже выпустила заплатки для большинства своих систем, доступные через службу Windows Update, однако, при желании можно обойтись и без них: достаточно заблокировать SMB-трафик из внешней Сети, для чего необходимо закрыть два TCP порта — 139 и 445 (однако, это сделает невозможность работу приложений, работающих через SMB).

рисунок 7 тянем заплатку с сервера Microsoft

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

на базе RPC построены многие системные сервисы и, в частности, SMB (ServerMessageBlock), реализующий именованные каналы (namedpipes) и использующий PRC в качестве транспорта. в свою очередь, SMB используется для удаленного доступа к файлам, папкам и принтерам.

и все бы ничего, но в функции NetpIsRemote(), сосредоточенной в библиотеке NetApi32.DLL допущена ошибка контроля границ, приводящая к традиционному стековому переполнению, с возможностью подмены адреса возврата. на системах с активным DEP, предотвращающим выполнение кода в неисполняемых областях памяти, приходится хитрить, атакуя жертву по одному из сценариев, описанных в статье «переполнение буфера на системах с неисполняемым стеком», которую можно найти на прилагаемом к журналу диске или скачать с мыщъх'ого ftp://nezumi.org.ru (напоминаю, что сервер установлен на рабочей машине и потому доступен не все время, а только тогда, когда мыщъх шевелит хвостом).

Рисунок 8 мыщъх'иный ftp на раздаче

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

загружаем библиотеку NetApi32.DLL в IDA Pro и начинаем исследовать функцию NetpIsRemote(), пытаясь «глазами» найти место, в котором происходит переполнение, в первую очередь обращающая внимания на циклы, копирующие блоки памяти (типа mov ecx,[eax]/mov [ebx],eax/add eax,4) или вызовы функций memcpy(), memmove(), strcpy(), wcscpy() и т. д.

функция NetpIsRemote() выглядит обманчиво маленькой, но если присмотреться повнимательнее, можно обнаружить множество условных переходов, ведущий на CHUNK'и (то есть, на ее продолжение), совокупный объем которых довольно велик и затруднителен для анализа.

рисунок 9 обольстительно короткая NetpIsRemote()

беглый поиск обнаруживает пару подозрительных функций wcscpy() и wcscat(), однако, wcscpy() отпадает сразу, поскольку копирует строку фиксированной длинны, жестко прошитую внутри NetApi32.DLL, а wcscat() восходит к функции I_NetNameCanonicalize(), перспективы переполнения которой на данном этапе исследований весьма туманны и неясны (см. листинг. 1).

7CD25C24leaeax,[ebp+var_20C]

7CD25C2Apushesi

7CD25C2Bpusheax

7CD25C2Cmoveax,[ebp+arg_4]

7CD25C2Fpushdword ptr [eax+4]

7CD25C32pushedi

7CD25C33callI_NetNameCanonicalize

7CD25C38cmp[ebp+var_4],edi

7CD25C3Bjzloc_7CD25C48

7CD25C3Dmoveax,[ebp+arg_C]

7CD25C40leaebx,[ebp+var_20C]

7CD25C6Epushasc_7CD17CF4

7CD25C73push[ebp+arg_C]

7CD25C76callds:imp_wcscpy 7CD25C7Cpopecx 7CD25C7Dpopecx 7CD25C7Epushebx 7CD25C7Fpush[ebp+arg_C] 7CD25C82callds:imp_wcscat

Листинг 1 дизассемблерный фрагмент NetpIsRemote() с потенциально опасными функциями wcscpy() и wcscat()

но ведь в нашем распоряжении есть готовая заплатка! давайте, чтобы не блуждать впотьмах, просто сравним дизассемблерные листинги функции NetpIsRemote() до и после обновления — все изменения станут сразу очевидны!

скачиваем заплатку с официального сервера Microsoft (для моей Windows 2000 SP4 это download.microsoft.com/download/9f06d3f3-87d0-445d-8a41-d2ffef9a40ba/windows2000-kb921883-x86-rus.exe), представляющую собой обыкновенный самораспаковывающийся cab-архив. в прошлом ревю мы показывали как извлечь его содержимое с помощью hiew'а, однако, есть и более короткий путь — достаточно «скормить» исполняемый файл rar'у и все упакованные файлы предстанут перед нашими глазами!

Рисунок 10 распаковка пакета обновления с помощью rar'a

извлекаем из архива NetApi32.DLL, переименовываем ее, например, в NetApi32-new.DLL и загружаем в дизассемблер. какие различия между старой и новой версией NetpIsRemote() мы увидим? в первую очередь это гнусная выходка компилятора, инвертировавшего условные переходы, в результате чего ветви программы поменялись местами:

JNZ branch_AJZ branch_B

breanch_Bbreanch_A

Листинг 2 инверсия ветвей в старой и новой версиях NetApi32.DLL

непонятно? что ж, покажем это на конкретном примере:

7CD17AF3cmp eax, edi7CD230FFcmp eax, edi

7CD17AF5mov [ebp+var_4], edi7CD23101mov [ebp+var_4],edi

7CD17AF8jnz loc_7CD25BB47CD23104jz loc_7CD23150

7CD17AFE loc_7CD17AFE:7CD23106mov cx, [eax]

7CD17AFEcmp [ebp+arg_C],edi7CD23109cmp cx, di

7CD17B01jz loc_7CD17B0D7CD2310Cjz loc_7CD23150

7CD17B03test [ebp+arg_10], 1

7CD17B07jnz loc_7CD25C027CD23150 loc_7CD23150:

7CD23150cmp [ebp+arg_8], edi

7CD25BB4 loc_7CD25BB4:7CD23153jz loc_7CD23212

7CD25BB4mov cx, [eax]7CD23159test [ebp+arg_10], 1

7CD25BB7cmp cx, di7CD2315Djz loc_7CD23212

7CD25BBAjz loc_7CD17AFE7CD23163mov ebx, [ebp+arg_8]

Листинг 3 конкретный пример инверсии ветвей, слева показана старя версия NetApi32.DLL, слева — новая. красным цветом выделена ветвь А, синим — B

приведенный фрагмент функции NetpIsRemote() идентичен в обоих версиях, но порядок машинных команд поменялся местами, ослепляя большинство анализаторов типа fc.exe и wnindiff, которыми мы пользовались ранее. как же быть? а вот как! берем блок A из строй версии NetApi32.DLL и ищем похожий на него блок в NetApi32-new.DLL, затем добиваемся, чтобы первые строки блоках в обоих окнах дизассемблера совпадали (что легко осуществляется мышью или курсорными клавишами). теперь начинаем быстро переключаться с одного окна дизассемблера на другое по <ALT‑TAB>, при этом, несовпадающие строки начинают интенсивно мерцать, выдавая различия с головой (аналогичным образом астрономы ищут и новые звезды — т.е. звезды меняющий свой блеск — попеременно проецируя на экран несколько слайдов снятых в разное время они смотрят — не начнет ли какая точка ритмично мигать. способ древний как мамонт, но очень надежный).

действуя таким образом, мы довольно быстро найдем «линую» функцию wcslen(), которой не было ранее и которая контролирует длину строки перед копированием:

7CD25C2Cmov eax, [ebp+arg_4]7CD2318D mov eax,[ebp+arg_0]

7CD25C2Fpush dword ptr [eax+4]7CD23190 push dword ptr [eax+4]

7CD25C32push edi7CD23193 push edi

7CD25C33call I_NetNameCanonicalize7CD23194 call I_NetNameCanonicaliz

7CD25C38cmp [ebp+var_4],edi7CD23199 cmp [ebp+var_4],edi

7CD25C3Bjz loc_7CD25C487CD2319C jz loc_7CD231A9

7CD25C3Dmov eax, [ebp+arg_C]7CD2319E mov eax, [ebp+arg_8]

7CD25C40lea ebx, [ebp+var_20C]7CD231A1 lea ebx, [ebp+var_20C]

7CD25C46jmp loc_7CD25C607CD231A7 jmp loc_7CD231C1

7CD25C60 loc_7CD25C60:7CD231C1 loc_7CD231C1:

7CD25C60mov ecx, [ebp+arg_8]7CD231C1 mov ecx, [ebp+arg_4]

7CD25C63neg eax7CD231C4 neg eax

7CD25C65sbb eax, eax7CD231C6 sbb eax, eax

7CD25C67cmp [ebp+arg_C],edi7CD231C8 cmp [ebp+arg_8],edi

7CD25C6Amov [ecx],eax7CD231CB mov [ecx],eax

7CD25C6Cjz loc_7CD25C8A7CD231CD jz loc_7CD23208

7CD231CF push ebx

7CD231D0 call ds:imp_wcslen 7CD231D6 add eax, 3 7CD231D9 pop ecx 7CD231DA cmp [ebp+arg_C], eax 7CD231DD jnb short loc_7CD231EC … 7CD231EC loc_7CD231EC: 7CD25C6Epush asc_7CD17CF47CD231EC push asc_7CD11744 7CD25C73push [ebp+arg_C]7CD231F1 push [ebp+arg_8] 7CD25C76call ds:imp_wcscpy7CD231F4 call ds:imp_wcscpy 7CD25C7Cpop ecx7CD231FA pop ecx 7CD25C7Dpop ecx7CD231FB pop ecx 7CD25C7Epush ebx7CD231FC push ebx 7CD25C7Fpush [ebp+arg_C]7CD231FD push [ebp+arg_8] 7CD25C82call ds:imp_wcscat7CD23200 call ds:imp_wcscat Листинг 4 старая (слева) и новая (справа) версии NetpIsRemote() ага! вот она! точнее оно! переполнение буфера в смысле! между функциями I_NetNameCanonicalize() и wcscpy()/wcscat() в обновленной версии NetApi32.DLL внедрен вызов wcslen(), проверяющий размер строки, возращенный I_NetNameCanonicalize()** перед его копированием в… блок памяти, переданнй по указателю через аргумент функции (arg_C в старой и arg_8 в новой версии). сама же I_NetNameCanonicalize() так же принимает на «грудь» указатель, извлекаемый структуры, переданной NetpIsRemote() в качестве аргумента. все это создает крайне благоприятные условия для реализации атаки и засылки shell-кода. достаточно «всего лишь» передать слишком длинную строку функци I_NetNameCanonicalize() вместе с указателем на крошечный буфер, неспособный вместить «канонизированное» имя. локальный exploit пишется без проблем — ведь функция NetpIsRemote() экспортируется и все, что нам нужно — это восстановить его прототип. однако, локальный exploit – не слишком-то полезная штука, гораздо больший интерес вызывают удаленные exploit'ы. можем ли мы использовать эту уязвимость для атаки, и если да, то как? переходим в начало функции NetpIsRemote() и, нажав <ALT-V> [view], <O> [opensub-view], <O> [crossreferences], смотрим по перекрестным ссылкам — какие функции ее вызывают. большинство функций семейства I_*() доступны через SMBRemoteAPIs, т. е. их можно вызывать удаленно по RPC-протоколу, инкапсулированному в SMB. подобнее об этом можно прочитать на форуме immunitysec'а в сообщении известного хакера H D Moore'а: lists.immunitysec.com/pipermail/dailydave/2006-August/003400.html, а в MSDN можно найти готовый пример реализации Bloodhound'а Parser DLL for SMB Remote APIs, расположенный в файле REMAPI.C и основанный на функции CreateProtocol(), описанной в windowssdk.msdn.microsoft.com/en-us/library/ms707941.aspx__. рисунок 11 СreateProtocol() на MSDN основная ценность REMAPI.C заключается в том, что имена I_*() функций (совпадающих с именами команд SMB протокола) в нем перечислены «прямым текстом». фактически это единственный источник информации, который у нас только есть. рисунок 12 REMAPIC.C – основной источник информации по SMB командам просматривая список перекрестных ссылок, необходимо отобрать функции, присутствующие в файле REMAPI.C: I_NetPathType(), I_NetNameValidate(), I_NetNameCanonicalize(), I_NetNameCompare() и I_NetPathCompare(). рисунок 13 добываем список перекрестных ссылок на NetpIsRemote() теперь необходимо проанализировать дизассемблерный листинг каждой из них и найти хотя бы одну функцию, передающую NetpIsRemote() свой собственный аргумент вместе с указателем на локальный буфер фиксированного размера. как ни смешно, но этой функцией оказывается… I_NetNameCanonicalize(). нет, этонеошибка! I_NetNameCanonicalize() вызывает NetpIsRemote(), а NetpIsRemote() вызывает I_NetNameCanonicalize(), вот такая, значит ### блядь ### рекурсия у нас получается. руки бы поотрывать тем кто это писал (вместе с хвостом)! но довольно эмоций! ниже приведен дизассемблерный фрагмент I_NetNameCanonicalize() в котором и происходит переполнение. 7CD1F980 loc_7CD1F980:; CODE XREF: I_NetNameCanonicalize+A4↑j 7CD1F982push104h; размер буфера(?) 7CD1F987leaeax,[ebp+var_230]; указатель на… 7CD1F98Dpusheax; …локальный буфер. 7CD1F98Eleaeax,[ebp+var_20]; указатель на другой… 7CD1F991pusheax; …локальный буфер 7CD1F992push[ebp+arg_0]; аргумент функции 7CD1F995callNetpIsRemote; вызов уязвимой функции Листинг 5 вот где происходит переполнение таким образом, все, что нам нужно — это вызвать функцию I_NetNameCanonicalize(), так же являющуюся командой протокола SMB и передать ей слишком длинную строку, вызывающую срыв стека, с подменой адреса возврата, что легко осуществляется из любой точки Сети, если, конечно, внешний SMB-трафик не отсекается брандмауэром. проблема в том, что I_NetNameCanonicalize() ни хрена не документирована и ее прототип неизвестен. кое-какую информацию удается нарыть в файле netapi32.inc, входящем в состав ассемблера MASM, но она слишком малоинформативна. I_NetNameCanonicalize PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD Листинг 6 прототип I_NetNameCanonicalize() к счастью, у нас есть BloodhoundParser, заботливо предоставленный Microsoft, позволяющий сниффить сеть и декодировать пролетающий SMB-команды. аргументы, правда, не декодируются, но об их назначении нетрудно догадаться и самостоятельно. еще можно дизассемблировать I_NetNameCanonicalize(), разобравшись какие аргументы она ожидает. это рутинная и неинтересная работа, к тому же уже проделанная авторами metasploit exploit'а, так что не будем повторяться, а лучше позаимствуем готовый «движок» и адоптируем его для собственных нужд.