Microcorruption | Level: Cusco
Привет! Данная статья содержит решение на один из начальных уровней на платформе Microcorruption.
Что такое Microcorruption?
Это embedded CTF, в котором вам предоставляется отладчик и устройство (умный замок). Вам будут даны различные уровни задач, чтобы разблокировать устройство, найти уязвимости в коде.
Дебагер предоставляется прямо в браузере:

Секции дебагера:
Дизассемблер. Вывод ассемблер кода, который мы дебажим
Дамп памяти. Тут мы можем посмотреть что хранится в памяти
Состояние регистров. Выводится информация о значениях, которые хранятся в регистрах.
Дебаг консоль. Тут можем исполнять команды, которые предоставляет дебагер, например поставить breakpoint
I/O Console. Консоль, в которой отображается вывод программы.
pwn
Пролистав код, можно увидеть 3 интересные функции:
login. (Вызывается первой в функции Main)
unlock_door.
test_password_valid.

login
В функции login выводится приглашение ввода пароля и предупреждение, что пароли содержат от 8 до 16 символов (Это нужно запомнить).
Далее вызывается функция getsn, для получения ввода от юзера и вызывается функция test_password_valid. Далее у нас появляется ветвление. Если регистр r15 будет равен 0, то произойдет "прыжок" на login + 0x32, то есть на адрес 4532, где выводится строка, что пароль неправильный.
Чего нам нужно добиться? Сделать так, что бы r15 != 0 после выполнения функции test_password_valid.

test_password_valid
Большую часть кода можно пропустить и искать место, где r15 становится равен 0, это происходит на строке с адресом 4470. Но тут следует отметить, что 0 устанавливается не напрямую, а берется значение с отрицательным смещением в 4 байта от регистра r4.

Debug
Поставим брейкпоинт на test_password_valid и запустим b = break, c = continue.


В дампе сразу можно найти данные, которые я указал. (Стрелками показал начало и конец).

Через команду s (step) можно пошагово проходить по всей программе. Нам нужно дойти до адреса 4470, на котором регистру r15 присваивается значение с отрицательным смещением в 4 байта от регистра r4.
Регистр r4 = 43ec. Отнимаем 4 и получаем адрес 43e8, это и будет адрес, с которого будет браться значение.

Смотрим в дамп памяти, а по адресу 43e8 хранится 00. =(

Если посмотреть подробнее, то выхода из данной ситуации нет, либо я просто не нашел. Но обратите внимание на нули после нашего ввода. Если сложить количество байт нашего ввода + количество нулевых байтов = 16, вот тут то и вспоминанием о том, что пароли у нас от 8 до 16 символов. Но что если передать 17 символов?
Перезапускаем, даем на вход 17 символов (AAAAAAAAAAAAAAAAA) и смотрим что происходит.

Выглядит так, как будто мы что-то поломали. Если посмотреть в дамп памяти состояние регистров, мы можем найти увидеть кое-что интересное.


Мы вышли за выделенный нам буфер в 16 символов и записали один лишний байт, а если посмотреть в состояние регистров, то мы можем увидеть, что в регистр pc (program counter) помещаются следующие 2 байта! И так как мы переполнили всего на 1 байт, в регистр записалось 0041 (Почему обратном порядке можно посмотреть тут или загуглить про little-endian и big-endian),
Теперь когда мы это поняли, все что нам остается, это записать в регистр pc адрес вызова функции unlook_door.
Так как нам нужно передать адрес, то не забываем вводить данные в hex (поставить галочку Check here if entering hex encoded input) и перевернуть адрес.
Отдаем на вход вот такую строку: 414141414141414141414141414141412845. 41 - буква А, 2845 - адрес вызова функции unlook_door и получаем уведомление о том, что мы успешно открыли дверь.

Telegram: @whoamins
Telegram Channel: @helloSOC