CTF Codeby Games - PWN Цепи (writeup)

Всем привет.
Продолжаем продолжать.
Вариант решения таска.

По классике открываем IDA и смотрим main
IDA_main.png


Видим тут несколько функций (я переименовал функции, аргументы и пременные чтобы мне было удобно разбираться в алгоритме):
1. greeting - функция выводит свое приветствие. Ничего что может нам помочь нет.
2. enter_name - функция, принимающая пользовательский ввод. Может быть полезна, оставим на потом.
3. setting_current_position - функция устанавливающая + на карте. Ничего интересного тут нет.
4. moving - функция, принимающая от пльзователя AWSD и передвигает. В теории тут может быть выход за границу массива.

Просмотрев 2 интересные функции меня сильно заинтересовала enter_name
IDA_enter_name.PNG

и ее стек
IDA_enter_name_stack.PNG


Ага. Буфер размером 16 (0x10) байт, а читаем 256. BOF!
Посмотрев на функции, которые есть в бинаре не увидел ничего что поможет получить флаг, значит тут не просто ROP, а ret2libc. Значит надо ликать адреса в libc, получать эту саму libc, получать ее базу и получть шелл.

Для того, что бы ликнуть адреса нам нужно их напечатать, для этого у нас есть функции puts, write. Хорошо. Использовать буду puts, т.к. она проще, потому что там только один аргумент и передается он с помощью гаджета POP RDI
Адреса функций, которые беруться из Libc находятся в .got.
Также нам понадобится адрес функции enter_name, для того, что бы можно было заново эксплуатировать уязвимость. Таким образом считаем нагрузку для ROP, далее печатаем адрес функции из got, запомниаем его и ищем какая же у нас либа. Так как я ленивый и искать на libc.blukat.me мне было лень, то я автоматизировал это.

libc_leak.PNG

На скриншоте видно, как берутся гаджеты из бинаря, как формируется PADDING (то что всегда необходимо делать перед ROP), как происходит получение адресов функций из .got и их печать, как возвращаемся в enter_name.
И две функции, которые получают возможные libc по ликнутым адресам, скачивают первую либу и подгружают ее, что бы иметь возможность искать прямо в либе оффсеты system и /bin/sh, ну и посчитать базу libc.

НО, почему-то я не смог взять адрес enter_name из EXE.symbols/EXE.sym. Если кто-то знает почему он тут не взялся, расскажите, ооочень интересно.

Сам эксплоит выглядит вот так:
exploit.PNG


0. Предыдущие шаги + классический io = start()
1. Ликаем адреса и запоминаем их.
2. Пробуем получить либу в libc.blukat.me (оно почему-то сломалось =)). Если не получается, то ищем через Libc database. Если снова не получилось, то что-то не то, перестает эксплоит работать.
3. Получение оффсетов из либс и подсчет базы libc. Я сделал 2 раза, чтобы наверняка =)
4. Ищем /bin/sh\x00, почему именно так, потому что бывают /bin/sh без завершающего 0, что совсем не надо.
5. Ищем system для получения шелла.
6. Финальная нагрузка.
7. PWNED

Спасибо.
 

Exited3n

Red Team
10.05.2022
747
259
BIT
719
Всем привет.
Продолжаем продолжать.
Вариант решения таска.

По классике открываем IDA и смотрим main
Посмотреть вложение 75151

Видим тут несколько функций (я переименовал функции, аргументы и пременные чтобы мне было удобно разбираться в алгоритме):
1. greeting - функция выводит свое приветствие. Ничего что может нам помочь нет.
2. enter_name - функция, принимающая пользовательский ввод. Может быть полезна, оставим на потом.
3. setting_current_position - функция устанавливающая + на карте. Ничего интересного тут нет.
4. moving - функция, принимающая от пльзователя AWSD и передвигает. В теории тут может быть выход за границу массива.

Просмотрев 2 интересные функции меня сильно заинтересовала enter_name
Посмотреть вложение 75152
и ее стек
Посмотреть вложение 75153

Ага. Буфер размером 16 (0x10) байт, а читаем 256. BOF!
Посмотрев на функции, которые есть в бинаре не увидел ничего что поможет получить флаг, значит тут не просто ROP, а ret2libc. Значит надо ликать адреса в libc, получать эту саму libc, получать ее базу и получть шелл.

Для того, что бы ликнуть адреса нам нужно их напечатать, для этого у нас есть функции puts, write. Хорошо. Использовать буду puts, т.к. она проще, потому что там только один аргумент и передается он с помощью гаджета POP RDI
Адреса функций, которые беруться из Libc находятся в .got.
Также нам понадобится адрес функции enter_name, для того, что бы можно было заново эксплуатировать уязвимость. Таким образом считаем нагрузку для ROP, далее печатаем адрес функции из got, запомниаем его и ищем какая же у нас либа. Так как я ленивый и искать на libc.blukat.me мне было лень, то я автоматизировал это.

Посмотреть вложение 75154
На скриншоте видно, как берутся гаджеты из бинаря, как формируется PADDING (то что всегда необходимо делать перед ROP), как происходит получение адресов функций из .got и их печать, как возвращаемся в enter_name.
И две функции, которые получают возможные libc по ликнутым адресам, скачивают первую либу и подгружают ее, что бы иметь возможность искать прямо в либе оффсеты system и /bin/sh, ну и посчитать базу libc.

НО, почему-то я не смог взять адрес enter_name из EXE.symbols/EXE.sym. Если кто-то знает почему он тут не взялся, расскажите, ооочень интересно.

Сам эксплоит выглядит вот так:
Посмотреть вложение 75155

0. Предыдущие шаги + классический io = start()
1. Ликаем адреса и запоминаем их.
2. Пробуем получить либу в libc.blukat.me (оно почему-то сломалось =)). Если не получается, то ищем через Libc database. Если снова не получилось, то что-то не то, перестает эксплоит работать.
3. Получение оффсетов из либс и подсчет базы libc. Я сделал 2 раза, чтобы наверняка =)
4. Ищем /bin/sh\x00, почему именно так, потому что бывают /bin/sh без завершающего 0, что совсем не надо.
5. Ищем system для получения шелла.
6. Финальная нагрузка.
7. PWNED

Спасибо.
Ничего себе, первый раз в жизни увидел моржовый оператор
Ахтунг!
 
  • Нравится
Реакции: yetiraki
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!