SEH на службе контрреволюции


Перехват управления


Перехват управления можно осуществить двояко (существует по меньшей мере два пути перехвата управления, рассмотрим их):

Путь первый: проанализируйте уязвимую программу и определите какой из обработчиков будет текущим на момент переполнения и где именно расположен его SEH-фрейм (учитывая, что адрес последнего может быть непостоянным и зависящим от множества трудно прогнозируемых обстоятельств, например, от рода и характера запросов, предшествующих переполнению). Теперь придумайте как переполнить буфер так, чтобы затереть handler, подменив содержащийся в нем указатель на адрес shell-кода. Значение поля prev не играет никакой роли (shell-код ведь не собирается на халяву возвращать таким трудом захваченное управление!).

Путь второй: зарегистрируйте свой собственный SEH-фрейм. Как же мы сможем что-то зарегистрировать в системе, если еще не перехватили управления? – воскликнете вы. Это, что, шутка?! А вот и нет! Указатель на текущего обработчика всегда содержится в одном и том же месте – в первом двойном слове TIB'а, лежащего по адресу fs:[00000000h] и псевдо-функцией poke его вполне реально перезаписать. Пусть вас не смущает наличие сегментного регистра FS – вся память, принадлежащая процессу, отображается на единое адресное пространство и до TIB'а можно дотянуться и через другие сегментные регистры, например, через тот же DS, используемый процессором по умолчанию. Естественно, при адресации через DS, TIB будет располагаться совсем по другому смещению и, чтобы его узнать, придется прибегнуть к услугам отладчика. Вы можете использовать soft-ice, Microsoft Kernel Debugger или любой другой отладчик по своему вкусу.

Сначала необходимо определить значение селектора, загруженного в регистр FS. В soft-ice за это отвечает команда "CPU" (если soft-ice настроен правильно, то все основные регистры автоматически отображаются в верхней части окна). Затем, просматривая таблицу глобальных дескрипторов, содержимое которой выводит команда "GDI", находим соответствующий ему базовый адрес.
Для первого потока процесса на всех NT-подобных системах он равен FFDFF00h, а все последующие потоки уменьшают его на 1000h, т. е. мы получаем ряд указателей вида: 7FFDE000h, 7FFDD000h, 7FFDC000h…

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

:cpu

Processor 00 Registers

----------------------

CS:EIP=0008:8046455B  SS:ESP=0010:8047381C

EAX=00000000  EBX=FFDFF000  ECX=FFDFF890  EDX=00000023

ESI=8046F870  EDI=8046F5E0  EBP=FFDFF800  EFL=00000246



DS=0023  ES=0023  FS=0030  GS=0000

:gdt

Sel.  Type      Base      Limit     DPL  Attributes

GDTbase=80036000  Limit=03FF

0008  Code32    00000000  FFFFFFFF  0    P   RE

0010  Data32    00000000  FFFFFFFF  0    P   RW

001B  Code32    00000000  FFFFFFFF  3    P   RE

0023  Data32    00000000  FFFFFFFF  3    P   RW

0028  TSS32     80295000  000020AB  0    P   B

0030  Data32    FFDFF000  00001FFF  0    P   RW

003B  Data32    00000000  00000FFF  3    P   RW

Листинг 6 определение адреса указателя на текущий SEH-фрейм

Обратите внимание, FFDFF000h – это не адрес текущего SEH-фрейма. Это – указатель на фрейм. Сам же фрейм должен быть сформирован непосредственно в shell-коде, а в FFDFx000h занесен указатель на него (см. рис. 1).

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


Содержание раздела