ИСП РАН
Содержание

Практический прием для фаззинг-тестирования: извлечение внутреннего API проекта

Введение

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

Начнем с проблемы: представим, что вы выбрали в качестве цели внутренний метод проекта. Вы хотите собрать обертку для этого метода, однако сталкиваетесь с тем, что у проекта нет библиотеки, экспортирующей данный метод, а самостоятельное добавление в обертку всех необходимых зависимостей, осознание порядка, параметров сборки и линковки кажутся избыточно сложными или у вас просто нет времени настолько погружаться в исходники проекта. Подход, который поможет решить данную проблему возможно не является самым изящным, однако на практике показал свою эффективность. Чтобы найти проекты, в которых использовался рассматриваемый нами подход достаточно перейти на github.com и в строке поиска ввести:


repo:google/oss-fuzz path:*.sh /(?-i)\bar\b/ AND /(?-i)\bmain\b/

1. Репозиторий OSS-Fuzz

Репозиторий OSS-Fuzz, в котором мы осуществляем поиск — это инфраструктурный проект Google, содержащий коллекцию проектов с уже интегрированными фаззинг-обвязками. Многие проекты в этом репозитории используют нестандартные решения для сборки оберток, экспорта внутренних функций и подготовки тестовых окружений.

В результатах поиска мы увидим 7 проектов в составе репозитория OSS-Fuzz, среди которых: clib, binutils, postgresql, kamailio, haproxy, dnsmasq, dng_sdk.

oss-fuzz

Давайте ознакомимся с данным приемом на практике. Чтобы не повторяться, рассмотрим пример с всем известной утилитой file.

sh
git clone https://github.com/file/file.git
cd file

2. Определяем функцию для фаззинг-тестирования и пишем обертку

Предположим, что, в учебных целях, нас заинтересовал метод file_private void setparam(const char *p), который определен в файле с точкой входа main() (https://github.com/file/file/blob/master/src/file.c), и мы бы хотели выполнить фаззинг-тестирование именно этой функции.

При сборке проекта данный символ не попадает в библиотеку, являющуюся движком утилиты - libmagic.so, этот символ находится в локальной (неэкспортируемой) text-секции исполняемого файла file.

sh
autoreconf -vif
export AFL_USE_ASAN=1 AFL_USE_UBSAN=1
export CC=afl-clang-fast
./configure --enable-static --enable-shared
make

nm ./src/.libs/libmagic.so | grep setparam
nm ./src/.libs/file | grep setparam

setparam

Мы написали простейшую обертку для этого метода setparam_fuzzer.c:

sh
#include <stdint.h>
#include "file.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void setparam(const char *);

int main(int argc, char **argv) {
	unsigned char input[1024];
	ssize_t len;
	
	len = read(STDIN_FILENO, input, sizeof(input) - 1);
	
	if (len <= 0) {
		return 0;
	}
	
	input[len] = '\0';
	
	setparam((const char *)input);
	
	return 0;
}

3. Проводим линковку и решаем возможные ошибки

И теперь сталкиваемся с задачей ее линковки с объектным файлом file.o, чтобы иметь возможность запускать фаззинг-тестирование.

sh
cd src
сp /path/to/setparam_fuzzer.c .
afl-clang-fast -c setparam_fuzzer.c -o setparam_fuzzer.o
afl-clang-fast setparam_fuzzer.o file.o -o fuzz_harness

Попробовав это сделать, мы столкнемся с ошибками:

1) multiple definition of main
2) undefined reference to setparam
3) undefined reference to ...

undef

4. Решаем возможные ошибки

Для решения этих проблем без погружения в исходники нам необходимо:

1) Заменить символ main в файле file.c, поскольку он нам более не нужен (точка входа будет в обертке, а в бинаре не может быть двух точек входа).

2) Переместить символ из неэкспортируемой секции в экспортируемую, убрав макроопределение file_private, за которым скрывается static.

sh
sed 's/main(/main2(/g' -i ./file.c

sed -i 's/^file_private void/void/' ./file.c

3) Выполнить пересборку всего проекта.

sh
cd ..
make clean
make

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

err

4) Собрать все объектные файлы в статическую библиотеку.

sh
cd src/
ar rcs libfilefuzz.a ./*.o

5) Собрать обертку.

sh
afl-clang-fast -c setparam_fuzzer.c -o setparam_fuzzer.o
afl-clang-fast setparam_fuzzer.o  -L. -lfilefuzz -o fuzz_harness

err-link

Мы видим, что при сборке возникла ошибка, т.к. мы забыли про линковку с зависимостями file, исправим это:

sh
afl-clang-fast setparam_fuzzer.o  -L. -lfilefuzz -lzstd -llzma -lbz2 -lz -o fuzz_harness

Попробуем запустить фаззинг-тестирование:

sh
mkdir in out
echo "1" > in/1
afl-fuzz -i ./in -o ./out -- ./fuzz_harness

fuzz

Заключение

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

Авторы:
Козачок Александр Васильевич, доктор технических наук доцент, заведующий лабораторией 12.2 ИСП РАН
Николаев Дмитрий Александрович, кандидат технических наук, научный сотрудник лаборатории 12.2 ИСП РАН

Ключевые слова

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