Расшифровка функций

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

После этого вызывается callFunction с вводом функции в качестве аргумента.

callFunction отображает часть памяти, копирует функцию, переданную в качестве аргумента, в память, а затем вызывает функцию decryptFuncntion, которая выполняет побитовые операции не со всеми байтами один за другим. При расшифровке он также проверяет наличие 6 инструкций nop подряд с помощью strncmp. Когда он находит 6 инструкций nop, он начинает искать 0xc3, который является инструкцией ret. Как только он находит инструкцию ret, функция полностью расшифровывается, а затем вызывается функция.

Оглядываясь назад на указатели функций, мы видим, что другие функции также зашифрованы таким же образом. Я написал скрипт binaryninja для расшифровки всех функций. Скрипт реализует decryptFunction на python и запускает его на зашифрованных функциях, чтобы мы могли их проанализировать.

Уязвимость

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

Функция charHistogram принимает строку и выводит, сколько раз встречается каждый байт. Он отслеживает количество, беря байт, используя его в качестве индекса в массиве, а затем увеличивая это место на 1.

Проблема в том, что размер массива составляет всего 0x80 байт, поэтому он выходит за пределы, если вы укажете ему \x80 или выше.

Эксплуатация

Отправка \x98 увеличивает первый байт адреса возврата. В поисках подходящего места для возврата я заметил, что callFunction, функция, используемая для вызова зашифрованных функций, помещает адрес моего ввода на вершину стека, поэтому адрес моего ввода идет сразу после адреса возврата charHistogram.

Я выполнил команду readelf -l fuzzy, чтобы проверить, отключен ли NX. Значение флагов GNU_STACK установлено в RWE, что означает, что стек доступен для чтения, записи и выполнения, другими словами, NX отключен. Так что все, что мне нужно сделать, это перейти к некоторому шеллкоду.

Я решил поместить шелл-код в буфер, который содержит нашу опцию меню, так как не было необходимости в его обработке charHistogram. Я изменил адрес возврата charHistogram на инструкцию ret и изменил адрес своего ввода, чтобы он указывал на мой шелл-код, и получил шелл.