В рамках курса CS безопасности моему классу была поручена эксплуатация уязвимости, чтобы выполнить проверку пароля с использованием переполнения стека/буфера. Код с уязвимостью выглядит следующим образом:Переполнение буфера на основе стека - вызов в C с использованием scanf с ограниченным доступом
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/md5.h>
int main(int argc, char **argv) {
char correct_hash[16] = {
0xd0, 0xf9, 0x19, 0x94, 0x4a, 0xf3, 0x10, 0x92,
0x32, 0x98, 0x11, 0x8c, 0x33, 0x27, 0x91, 0xeb
};
char password[16];
printf("Insert your password: ");
scanf("%29s", password);
MD5(password, strlen(password), password);
if (memcmp(password, correct_hash, 16) == 0) {
printf("Correct Password!\n");
} else {
printf("Wrong Password, sorry!\n");
}
return 0;
}
Я понимаю, классический «стек-сокрушительный» принцип (я думаю), и существует явная уязвимость переполнения здесь, где первые 14 байт correct_hash
массива может перезаписывать, вводя пароль длиной более 15 символов при появлении запроса. Однако я не понимаю, как использовать это, чтобы пройти проверку memcmp
, выполнив вызов. Некоторые из вещей, которые я обнаружил/попытки:
Установка
password
быть эквивалентcorrect_hash
не работает, так какpassword
получает хэшируется с помощьюMD5()
(установка два равных невозможно в любом случае, так какscanf
будет вставьте точно один уникальный символ ASCIINUL
в 30 доступных ему пространств, что означает, что два массива никогда не могут быть эквивалентными.NUL
символов, кроме того (насколько мне известно) не могут быть вставлены в середине строкиscanf
).Перезапись максимальное число байтов с
scanf
(который всегда будет добавлятьNUL
символ) означает, что последние 3 байтаcorrect_hash
всегда будет0x00 0x91 0xeb
. Попытка случайным образом генерировать 16-символьный пароль, который затем хэшируется чем-то с этими последними 3 байтами/символами (разумно легко вычислить, учитывая использование MD5), не работает, однако, из-за использованияstrlen(password)
(что даст значение вместо того, чтобы что-то удобное, как 16, за счет только окончания отсчета длины при попадании символаNUL
) в звонокMD5()
. Это означает, что вместо хэширования 16-символьного пароля для получения ожидаемого результата вызовMD5()
будет содержать 16 символов изpassword
, за которым следуют 13 символов отcorrect_hash
, производя другое окончательное хешированное значение.- Чтобы обойти эту проблему, я считаю, можно было бы найти строку 29 символов (назовем его S), где первые 16 символов S хэша в строку R, состоящего из последних 13 символов S, а затем
0x00 0x91 0xeb
. Я не уверен, насколько жизнеспособно найти это через случайный MD5-хэш-расчет, но это не представляет моих шансов.
- Чтобы обойти эту проблему, я считаю, можно было бы найти строку 29 символов (назовем его S), где первые 16 символов S хэша в строку R, состоящего из последних 13 символов S, а затем
Некоторые примечания (упомянутые в приведенных выше объяснений):
scanf
ограничена нанизывать на 29 символов, но добавит в ASCIINUL
характер, что позволяет в общей сложности 30 символов (16 из массивpassword
, 14 из массиваcorrect_hash
) для перезаписывания.ASCII
NUL
символы не могут быть введены черезscanf
такstrlen(password)
в вызовеMD5()
(если максимальная длина пароля используется) будет 29.
Так что вопрос здесь, как еще я мог идти об этом? Я пропустил что-то чрезвычайно очевидное? Является ли случайное поколение жизнеспособным решением или даже единственным решением?
Решение должно использовать переполнение буфера (в противном случае я полагаю, что мог бы сделать что-то вроде preload a memcmp
, который всегда возвращает 0), и должен исполняться как сценарий оболочки (если это имеет какое-либо значение).
Суть дела заключается в том, что scanf с радостью примет нулевой байт как часть строки и не будет рассматривать его как пробел (таким образом, не перестанет считывать дальнейшие байты в строку). С этой информацией ваша задача должна быть простой. – Ctx
'char password [16]; ... scanf («% 29s», пароль); 'не использует уязвимость. Это намеренно создает одно. –
@Ctx: это правда, но ввод 'NUL' байт из терминала нелегкий. – chqrlie