понедельник, мая 15, 2006

Комментарий к 1-й части статьи Ms-Rem-а 'Инжект как метод обхода фаерволлов...'

Недавно на сайте WASM.RU появилась 1-я часть статьи Ms-Rem'Инжект как метод обхода фаерволлов, жив или мертв?', посвященная методам "обхода" широко известного персонального файерволла Outpost Firewall PRO (далее Outpost FW). Моей первой реакцией на публикацию было недоумение и раздражение, связанные с тем, что, с одной стороны, этот материал не представляет никакой новизны (по крайней мере для тех, кто более-менее "знаком" с Outpost FW), а с другой - тем, что Ms-Rem представил исходные тексты эксплойтов, которые могут быть быстро перенесены в дешевые поделки трояно- и вирусо-писателей, что в конечном счете может неблагоприятно отразиться на пользователях этого продукта.

Вместе с тем, статья содержит ряд ошибок (или неточностей - кому как больше нравится). Оговорюсь сразу, что эти ошибки ни в коей мере не умаляют достоинств автора - ведь, как говорится, "не делает ошибок лишь тот, кто вообще ничего не делает!". В этом посте я опишу лишь несколько ошибок, которые сразу бросились мне в глаза при беглом прочтении. Есть, конечно, и другие неточности - часть из них я опущу в надежде, что вы и сами их найдете. :) Итак, прямо по тексту...

Ошибка 1
В самом начале статьи, в разделе "Outpost Firewall, или пример простой защиты", автор пишет: "Outpost отслеживает инжектинг путем перехвата ZwWriteVirtualMemory в SDT ntoskrnl...". Тут на самом деле две неточности. Первая (не очень существенная) состоит в том, что, конечно же, в SDT (т.е., в Service Descriptor Table, или, точнее, в KeServiceDescriptorTable) никто ничего не перехватывает, ибо там бессмысленно что-то перехватывать. В этом месте, видимо, подразумевалась таблица SSDT (т.е. System Service Dispatch Table, или KiServiceTable), в которой как раз и находятся адреса т.н. "системных сервисов", т.е. функций модуля ntoskrnl.exe с префиксами Nt, которые очень часто перехватываются всякими файерволлами, антивирусными программами, HIPS-ами и т.д. (более подробно см. в очень известной книге 'Undocumented Windows NT', выпущенной издательством M&T Books, текст которой также можно найти на сайте http://www.windowsitlibrary.com). Вторая же неточность (более существенная) состоит в том, что Outpost FW перехватывает не ZwWriteVirtualMemory, а вызов NtWriteVirtualMemory! Пусть вас не смущает то, что имена этих функций очень похожи (и даже более того - одна в конечном счете передает управление в другую) - между этими функциями есть ряд принципиальных различий, связанных со спецификой вызова системных сервисов в user и kernel mode. Не буду сейчас вдаваться в подробности по этому поводу - для тех, кто хочет более детально разобраться в этом вопросе, я рекомендую прочитать статью 'Nt vs. Zw - Clearing Confusion On The Native API' из журнала 'The NT Insider' (см. также на сайте http://www.osronline.com).

Ошибка 2
В следующем абзаце автор пишет: "Экспериментальным путем было установлено, что Outpost позволяет записать в память процесса не более 16 байт данных". Здесь тоже две неточности. Первая: на самом деле в подавляющем большинстве случаев (а, может быть, даже во всех без исключения случаях - этого я не проверял) Outpost FW позволяет записать в память контролируемого процесса любое (приемлемое) количество байт, однако лишь запись 15-ти байт (а не 16-ти, как написано в статье - и это вторая неточность) не вызывает срабатывания "защиты" Outpost FW и, соответственно, блокирования сетевого доступа для этого процесса. Для каждого процесса в системе Oupost FW ведет счетчик суммарно записанных в него байт (неважно каким процессом/процессами), поэтому, к примеру, такая хитрость, как запись 15 байт, потом запись еще 15 байт (например, из другого процесса) и т.д., не сработает, хотя, насколько мне помнится, на форуме WASM Phorum кое-кто из постоянно заявлюящих о своей "крутизне" (не хочу упоминать тут его ник - он и сам себя узнает!) утверждал, что таким образом можно решить "проблему" с защитой Outpost FW! :) Немного позднее я приведу кусочек из драйвера Outpost FW, где будет ясно видно, в каком конкретно месте идет контроль на эти 15 байт.

Ошибка 3
В разделе "Баги в Outpost" (если честно, то я не понял, зачем автор включил этот раздел в статью об инжекте - ведь к инжекту это вообще не имеет никакого отношения!) автор поместил дизассемблированный код из драйвера filtnt.sys, из которого, якобы, видно, что "всем процессам с именем svchost.exe разрешается запись в память других процессов во избежание ложных срабатываний защиты". На самом деле даже беглого взгляда на этот кусочек кода достаточно, чтобы понять, что ничего подобного из него не следует, несмотря даже на такую строку:
.text:00017C84            mov     edi, offset aSvchost_exe ; "SVCHOST.EXE"

Для тех, кто еще не понял, в чем дело, я уточню, что в аргументе arg_8 упомянутой автором "функции с адресом 0x00017B90" находится число записываемых в память процесса байт ("number of bytes to be written to the specified process"). Поместим снова небольшую часть этого кусочка кода с моим комментарием:
.text:00017C79            mov     ecx, [ebp+arg_8]         ; число записываемых в память процесса байт
.text:00017C7C cmp ecx, 4 ; == 4?
.text:00017C7F jnz short loc_17CA0 ; нет, дальнейшая проверка
.text:00017C81 lea esi, [esi+0Eh]
.text:00017C84 mov edi, offset aSvchost_exe ; "SVCHOST.EXE"
.text:00017C89 mov ecx, 18h ; 24 == длина unicode-строки "SVCHOST.EXE"
.text:00017C8E repe cmpsb
.text:00017C90 jnz short loc_17CA0

Действительный же код, который разрешает процессу svchost.exe запись в память других процессов, находится в драйвере filtnt.sys немного дальше (примерно в 150-ти байтах). Я приведу этот кусочек кода (это, естественно, дизассемблер немного другой версии драйвера, так что адресация и некоторые детали могут немного отличаться):
.text:00018B67 loc_18B67:
.text:00018B67 mov eax, [ebx+28h] ; счетчик числа байт, _уже_ записанных в память процесса
.text:00018B6A cmp eax, 10h ; >= 16? (это, кстати, и есть проверка на "те самые" 16 байт)
.text:00018B6D jnb short loc_18B88 ; да, тогда проверим на имя процесса "SVCHOST.EXE"
.text:00018B6F add eax, [ebp+arg8] ; добавим к счетчику число записываемых _сейчас_ байт
.text:00018B72 mov [ebx+28h], eax ; сохраним это значение
.text:00018B75 cmp eax, 10h ; полученная сумма >= 16?
.text:00018B78 jnb short loc_18B88 ; да, проверим на имя процесса "SVCHOST.EXE"
.text:00018B7A mov eax, 1 ; нет, т.е. общая сумма записанных в память процесса байт < 16
.text:00018B7F pop edi ; ... это значит все ОК, разрешить без ограничений
.text:00018B80 pop esi
.text:00018B81 pop ebx
.text:00018B82 mov esp, ebp
.text:00018B84 pop ebp
.text:00018B85 retn 10h
.text:00018B88 loc_18B88: ; а вот и "то самое" место, где имя процесса проверяется
.text:00018B88 mov ecx, [ebp+var_4] ; ... на "SVCHOST.EXE"!
.text:00018B8B mov edi, offset aSvchost_exe ; "SVCHOST.EXE"
.text:00018B90 mov esi, [ecx+0Ch]
.text:00018B93 mov ecx, 18h
.text:00018B98 lea esi, [esi+0Eh]
.text:00018B9B repe cmpsb
.text:00018B9D jnz short loc_18BAD
.text:00018B9F mov eax, 1 ; имя процесса "SVCHOST.EXE" - разрешить все без ограничений
.text:00018BA4 pop edi
.text:00018BA5 pop esi
.text:00018BA6 pop ebx
.text:00018BA7 mov esp, ebp
.text:00018BA9 pop ebp
.text:00018BAA retn 10h

Ошибка 4
Далее, в этом же разделе, автор пишет: "Дальнейшее изучение драйвера оутпоста позволило мне найти еще один баг в нем, видимо в целях отладки программисты писавшие оутпост сделали в драйвере вывод отладочных сообщений (точнее сообщения драйвер выводит не сам, а передает их службе), и в числе прочих сообщений там имеется дамп содержимого инжектируемого куска памяти" и приводит ассемблерный код эксплойта, от которого якобы "система упадет в синий экран". Так вот, опять же беглого взгляда достаточно, чтобы понять, что приведенный код не "уронит" систему! В чем же дело? Обратите внимание на следующую строку кода:
  invoke   WriteProcessMemory, esi, edi, 0, 10, 0

Мы видим, что здесь делается попытка записать в память процесса 10 (!) байт из буфера с адресом 0. Но, как мы помним, только запись 16 и более байт вызывает "реакцию" драйвера Outpost FW и, соответственно, выполнение упомянутого куска кода, который выводит "отладочное сообщение" - именно поэтому данный код никак не может вызвать BSOD! Но... не торопитесь пока делать выводы! Вы еще помните о суммарном счетчике числа байт, записываемых в память процесса, который ведет Outpost FW? Так вот, если данный эксплойт запустить на выполнение не однократно, а дважды (а при этом суммарный счетчик байт, т.е. 10 + 10, превысит пороговое значение в 15 байт!) - система успешно упадет! :) Упадет она, естественно, и с первого запуска эксплойта, если мы все же исправим ошибку и напишем:
  invoke   WriteProcessMemory, esi, edi, 0, 16, 0

Причем в данном случае можно даже не исправлять строку:
  invoke   VirtualAllocEx, esi, 0, 10, MEM_COMMIT+MEM_RESERVE, PAGE_EXECUTE_READWRITE

Почему так? Попробуйте догадаться сами! :)

Comments: Отправить комментарий



<< Home

This page is powered by Blogger. Isn't yours?