Ошибка типа «переполнение буфера»

Локализация ошибки в программе. Построение диаграммы стека уязвимой функции. Построение контрольного примера, демонстрирующего наличие уязвимости. Построение эксплоита с шелл-кодом.

Образ виртуальной машины
Персональный вариант
Для получения персонального варианта необходимо войти в систему.
Постановка задачи

Задание посвящено анализу и эксплуатации уязвимости типа «Переполнение буфера» в программе на языке Си. Персональный вариант задания включает две уязвимые программы, для каждой из которых необходимо выполнить последовательность действий, в конечном счёте приводящих к построению полноценного эксплоита с шелл-кодом.

Подготовка к выполнению задания

Выполните следующую последовательность действий для подготовки к выполнению задания.

  1. Скачайте и разверните образ виртуальной машины и запустите его в ПО Oracle VirtualBox.
  2. Войдите в гостевую Linux-систему с именем пользователя student без пароля. В гостевой системе уже отключена рандомизация адресного пространства (ASLR), а также установлены все необходимые для выполнения задания программы. При необходимости вы можете установить дополнительные программы с помощью пакетного менеджера apt, а также настроить под себя окружение.

    Чтобы исключить изменение адресов объектов в стеке, не рекомендуется обновлять ядро Linux, а также стандартную библиотеку libc.

  3. Изнутри виртуальной машины скачайте архив с персональным вариантом при помощи утилиты wget и распакуйте его в каталог /home/student, например:

    $ wget https://caiscourse.ru/assets/assignment_variants/01/03C357EA.zip
    $ unzip 03C357EA.zip
    $ chmod +x 01 02

    Архив содержит две уязвимые программы: 01 и 02, а также их исходные коды 01.c и 02.c. Ключи, с которыми были собраны программы, а также значение константы BUFFER_SIZE, вам неизвестны.
  4. Для запуска программ используйте скрипты 01.sh, 01-gdb.sh, 02.sh, 02-gdb.sh. Скрипты принимают в качестве аргумента имя файла, которое будет передано уязвимой программе. Примеры использования:

    $ ./01.sh my-input-file
    $ ./02-gdb.sh my-input-file

    Скрипты необходимы для того, чтобы обеспечить одинаковую конфигурацию стека как под отладчиком, так и без него.

Подзадачи

Для каждого из предложенных примеров необходимо решить четыре подзадачи. Подзадачи решаются в произвольном порядке.

Подзадача 1: минимальная длина ввода для перезаписи адреса возврата

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

Обратите внимание, что программа может аварийно завершаться даже в том случае, когда адрес возврата ещё не перезаписан.

Подзадача 2: диаграмма стека уязвимой функции

В рамках данной подзадачи необходимо определить адреса следующих объектов в фрейме уязвимой функции: сохранённого адреса возврата, «канарейки» (в примере 2), перезаписываемого указателя на функцию (в примере 2) и адреса уязвимого буфера.

Подзадача 3: передача управления на другую функцию

В рамках данной подзадачи необходимо подготовить входной файл, который, при подаче его уязимой программе, реализует переполнение буфера и изменяет поведение программы так, чтобы управление оказалось передано на функцию success.

Входной файл не должен превышать по размеру 2 KiB.

Показателем успешного выполнения данной подзадачи является выдача уязвимой программой сообщения:

$ ./01.sh my-input-file
Congratulations! You have successfully diverted control to another function.
Now try to craft shellcode.

Подзадача 4: эксплуатация с шелл-кодом

Данная подзадача является завершающей. Необходимо подготовить входной файл, который, при подаче его уязвимой программе, реализует переполнение буфера и изменяет поведение программы так, чтобы она запустила командный интерпретатор /bin/sh.

Входной файл не должен превышать по размеру 2 KiB.

Показателем успешного выполнения данной подзадачи является запуск командной оболочки вместо завершения работы уязвимой программы.

Рекомендуется (но не обязательно) использовать 30-байтовый шелл-код следующего содержания:

48 31 D2 48 BB 2F 2F 62 69 6E 2F 73 68 48 C1 EB 08 53 48 89 E7 50 57 48 89 E6 B0 3B 0F 05

Необходимые инструменты и полезные команды

Для выполнения задания следует использовать инструменты gdb (через скрипты-обёртки), nm (для получения адресов функций), objdump (для дизассемблирования текста программы).

Для формирования входного файла можно пользоваться командами echo, tr, head, либо любым удобным языком программирования. Примеры полезных команд для формирования файла приведены далее:

$ # Дописать в конец файла три байта 48 31 D2
$ echo -ne "\x48\x31\xD2" >> my-input-file
$ # Дописать в конец файла 200 случайных алфавитно-цифровых байтов
$ tr -dc A-Za-z0-9 < /dev/urandom | head -c 200 >> my-input-file

Извлечение файлов изнутри виртуальной машины

Подзадачи 3 и 4 предполагают сдачу файлов, которые готовятся внутри виртуальной машины. Чтобы извлечь эти файлы, пользуйтесь возможностью создания разделяемых каталогов (shared folders) в VirtualBox.

Система оценивания
Подзадача Баллы
Пример 1 Минимальная длина ввода для перезаписи адреса возврата 1
Диаграмма стека уязвимой функции 2
Передача управления на другую функцию 3
Эксплуатация с шелл-кодом 4
Пример 2 Минимальная длина ввода для перезаписи адреса возврата 1
Диаграмма стека уязвимой функции 2
Передача управления на другую функцию 3
Эксплуатация с шелл-кодом 4
Всего 20