Order Of Six Angles

Main Logo

Х.Р.А.М Сатаны

Home | RU | Translations | Art | Feed.xml

20 March 2020

tags: windows - defence

Механизмы защиты Windows от эксплуатации уязвимостей. Часть 1.

Intro

В этой серии статей мы поговорим о механизмах защиты от эксплуатациии уязвимостей в Windows.

Начать копать эту тему, меня подтолкнула новость, о новой технологии защиты от ROP, которая будет реализована в новых процессорах Intel на уровне железа, но уже реализованной в Windows 10 в софтварном виде. О ней позже, в следующих частях.

Методы предотвращения эксплуатации делятся на защиту уровня ОС и защиту на уровне компилятора.

Compile based - то что встраивает компилятор

OS based - защита самой Windows, не зависящая от того, как вы собрали свою программу

Hardware based - защита на уровне процессора

Buffer security check

Переполнение буфера используется в эксплоитах, для перезаписи адреса возврата из функции, что позволяет перенаправить выполнение на свой вредоносный код.

Советую прочитать мою статью Классический buffer overflow и создание шеллкода вручную, чтобы понимать детали.

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

Buffer security check - это compile based защита компилятора Microsoft C/C++. Представлена она в виде ключа компиляции /GS, который включен по дефолту. Компилятор сам определяет функции в вашей программе, которые могут быть подвержены переполнению буфера и защищает их.

Давайте посмотрим, в чем она заключается. Для этого я написал простенькую программу, которая пишет в 64 байтный буфер 128 байт из файла.

int main()
{
	unsigned char buf[64];
	FILE *fp = fopen("crash_file", "r");
	fread(buf, 1, 128, fp);
	return 0;
}

Скомпилировал оба варианта, с ключом /GS и /GS- (отключает защиту). Откроем в IDA и посмотрим, что получилось.

Наглядно видим разницу - некое значение security cookie записывается в начале функции и проверяется в конце (__security_check_cookie()). Разберем построчно

mov eax, __security_cookie ; Записываем в регистр eax значение security cookie
xor eax, ebp ; Добавляем рандом в значение
mov [ebp + var_4], eax ; Кладем на стек, после ebp

Проверка security cookie

mov ecx, [ebp + var_4] ; Кладем в регистр ecx значение security cookie
xor ecx, ebp ; Восстанавливаем изначальное значение
call __security_check_cookie(x) ; Проверяем

Стек теперь выглядит вот так

Если вы выйдете за границы буфера, то затрете security cookie и после проверки не произойдет переход по адресу возврата, что является сутью эксплуатации переполнением буфера. При этом, программа мгновенно завершится. Изучим, что же такое security cookie. Ниже код в самом начале нашей программы

  1. security cookie сравнивается со стандартным значением 0x0BB40E64E
  2. test - это побитовый AND. Результат security cookie AND 0x0FFFF0000 должен равняться нулю

Если одно из этих условий выполняется, то начинается генерация настоящего security cookie. Выглядит она вот так

Здесь вызываются функции

  1. GetSystemTimeAsFileTime - текущая дата и время
  2. GetCurrentThreadId - id потока
  3. GetCurrentProcessId - id процесса
  4. QueryPerformanceCounter - это тот же timestamp, но с повышенной точностью

Результаты функций ксорятся, вот и готово security cookie.

Теперь рассмотрим проверку по завершению функции

Если помните, ранее в регистр ecx мы положили восстановленное значение security cookie. В конце мы просто сравниваем с изначальным значением и если оно изменилось то завершаем процесс

Важный момент - любая программа скомпилированная, с помощью Microsoft C/C++ компилятора, начинает свое выполнение не с вашей main() функции, а с функций инициализации C Runtime. Именно там генерируется security cookie. Но если вы компилируете с флагом /ENTRY и явно указываете с какой функции начинать свою программу, то эту процедуру вы пропускаете и должны сами вручную вызывать функцию генерации security cookie. Если вы этого не сделаете, то как вы уже видели, оно примет стандартное значение, а значит злоумышленник в своем эксплоите захардкодит его и пройдет проверку.

Outro

Как видите, все довольно тривиально. Я и сам до этого момента не погружался в детали этой защиты. Можно сказать, что мы сделали это вместе!)

На этом первая часть завершена, всем спасибо!

Вверх