Tartuga
Местный
- Регистрация
- 19.12.2019
- Сообщения
- 101
- Реакции
- 22
Ошибка форматирования строки стала известна еще в далеком 1989 году при работе по fuzz testing в Университете Висконсина. Но только лишь спустя 10 лет в 1999 году было обнаружено использование данной уязвимости в качестве вектора атака в ходе конференции по безопасности ProFTPD-демона Вашингтонского университета. Это привело к первой публикации данной уязвимости в сентябре 1999 года в списке Bugtraq. Но по настоящему массово данная уязвимость стала эксплуатироваться лишь в 2000 году. Было написано множество эксплоитов на базе форматирования строки. Ошибки обнаруживались как в больших популярных серверных приложениях, так и в простых утилитах.
*(Все примеры далее буду приводить на С)
Итак, форматирующая строка - простое представление строки ASCII контролируемым образом с использованием спецификаторов формата. Чтобы преобразовать типы данных в строке в представление String, используются такие функции, как printf , vprintf , scanf. Уязвимость форматирующих строк появляется несколькими способами. Вызов * printf () без спецификатора формата является опасным и может быть использован. Например, printf (input) можно использовать. Результат данного вызова позволяет злоумышленнику заглянуть в стек, тк входная строка будет использоваться в качестве спецификатора формата. Злоумышленник может заполнить входную строку спецификаторами формата и начать считывать значения стека, поскольку остальные параметры будут удалены из стека. В худшем случае эта уязвимость позволит злоумышленнику записать произвольное значение в память запущенной программы.
Проведение атаки:
Выводимое функцией количество символов будет храниться в адресе аргумента, следующего за самой строкой формата. Но в коде, имеющем уязвимость, злоумышленник может предоставить только одну строку (опустив второй аргумент функции printf). Функция printf возьмет очередное значение в стеке и использует его в качестве второго аргумента. Взломщик может также заставить функцию printf воспользоваться следующим значением в стеке, предоставив в качестве ввода, к примеру, такую форматирующую строку: %08x
Это означает, что printf выведет следующий аргумент в виде 8-разрядного шестнадцатеричного числа.
Рассмотрим далее на примере данного кода:
ТК printf имеет использует строку формата для определения количества аргументов, то злоумышленник может передать строку: %p%p%p%p%p%p%p%p%p%p%p%p%p%p%p
C 10 аргумента идет чередование - это введенные наши %p в стеке. Теперь мы можем передать наше значение. Передадим наше значение, добавив AAAA
Итак, мы передали 0x41414141 - 16-ю запись AAAA
Безопасность:
Во избежание подобных уязвимостей необходимо указывать строку формата как часть программы, а не как вход и сделать строку формата константой, если будет такая возможность.
*(Все примеры далее буду приводить на С)
Итак, форматирующая строка - простое представление строки ASCII контролируемым образом с использованием спецификаторов формата. Чтобы преобразовать типы данных в строке в представление String, используются такие функции, как printf , vprintf , scanf. Уязвимость форматирующих строк появляется несколькими способами. Вызов * printf () без спецификатора формата является опасным и может быть использован. Например, printf (input) можно использовать. Результат данного вызова позволяет злоумышленнику заглянуть в стек, тк входная строка будет использоваться в качестве спецификатора формата. Злоумышленник может заполнить входную строку спецификаторами формата и начать считывать значения стека, поскольку остальные параметры будут удалены из стека. В худшем случае эта уязвимость позволит злоумышленнику записать произвольное значение в память запущенной программы.
Проведение атаки:
Выводимое функцией количество символов будет храниться в адресе аргумента, следующего за самой строкой формата. Но в коде, имеющем уязвимость, злоумышленник может предоставить только одну строку (опустив второй аргумент функции printf). Функция printf возьмет очередное значение в стеке и использует его в качестве второго аргумента. Взломщик может также заставить функцию printf воспользоваться следующим значением в стеке, предоставив в качестве ввода, к примеру, такую форматирующую строку: %08x
Это означает, что printf выведет следующий аргумент в виде 8-разрядного шестнадцатеричного числа.
Рассмотрим далее на примере данного кода:
#include<stdio.h>
int main(int argc, char** argv)
{
char buffer[100];
strncpy(buffer, argv[1], 100);
// We are passing command line
// argument to printf
printf(buffer);
return 0;
}
ТК printf имеет использует строку формата для определения количества аргументов, то злоумышленник может передать строку: %p%p%p%p%p%p%p%p%p%p%p%p%p%p%p
Вот что получится:%p - внешнее представление указателя на недействительность printf будет печатать следующие 15 адресов в стеке, думая, что они являются его аргументами
$ ./a.out "%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p"
0xffffdddd 0x64 0xf7ec1289 0xffffdbdf 0xffffdbde (nil) 0xffffdcc4 0xffffdc64 (nil) 0x25207025 0x70252070 0x20702520 0x25207025 0x70252070 0x20702520
C 10 аргумента идет чередование - это введенные наши %p в стеке. Теперь мы можем передать наше значение. Передадим наше значение, добавив AAAA
$ ./a.out "AAAA%p%p%p%p%p%p%p%p%p%p%p"
AAAA0xffffdde8 0x64 0xf7ec1289 0xffffdbef 0xffffdbee (nil) 0xffffdcd4 0xffffdc74 (nil) 0x41414141
Итак, мы передали 0x41414141 - 16-ю запись AAAA
Безопасность:
Во избежание подобных уязвимостей необходимо указывать строку формата как часть программы, а не как вход и сделать строку формата константой, если будет такая возможность.