(Очень занимательное домашнее задание от препода =) ) Дана несколько запутанная программа. Преподователь вводит пароль, который студент не видит. После этого студент должен ввести свои варианты пароля и добиться вывода строки "You're COOl hacker" Количество попыток ограниченно(2 штуки). Требование: во время угадывания нельзя запускать дебаггеры, виртуальные машины и т.д. Просто для исследования программы можно использовать дизасм и дебаггер, hex редакторы нельзя использовать (препод все равно будет компилить прогу сам). (Решений несколько) Код программы: Code: #include <stdio.h> #include <stdlib.h> #define ARRAY_LENGTH 100 int main() { int flag; int i,j; char a_passwords[2][ARRAY_LENGTH]={"xxx","yyy"}; char *p_user = NULL; char *p_etalon =NULL; p_etalon=a_passwords[0]; p_user=a_passwords[1]; printf("Etalon password: "); fflush(stdout); scanf("%s",p_etalon); for (i=0; i<10000;i++) //что бы студент не видел, что было введено преподом { printf("\n"); } a_passwords[1][0]=&p_etalon-&p_user; for (j=2;j>0;j--) { printf("Password: "); fflush(stdout); scanf("%s",p_user); flag=0; for (i=0; i<ARRAY_LENGTH;i++) { flag=(p_etalon[i]!=p_user[i]); if ((p_etalon[i]==0) || (p_user[i]==0) || flag) break; } if (flag) { printf(p_user); printf(" - wrong pasword!\n"); } else { printf("\nYou're COOl hacker!!!\n"); exit(0); } } printf("You're looser!!!\n"); return 0; }
если отлад4ик можно юзать, то какие-проблемы? препод ввел серийнки. запустил ольку, приатта4ился, нашел код ввода проверки, отттрейсил сравнение, нашел буфер эталонного паса, ввел. все. 1 попытка, 100% результат
Отладчик можно использовать дома, что бы изучить структуру, того что скомпилировалось. Использовать инструменты во время проверки нельзя.
Вероятно, один из способов решения, это использовать ошибку форматной строки: Code: printf(p_user); Так-же нет никаких ограничений на длинну ввода в переменные, вероятно, это тоже можо как-то использовать. Например, если во время первого запроса на ввод пароля ввести более 122 символов, то исчезнет ограничение на 2-е попытки угадать пароль P.S. компилировал gcc на 64-битной системе upd: Вобщем, вот мой вариант решения данной задачи =) Code: Etalon password: 1234 [...] Password: <122 симола 'a'> <122 симола 'a'> - wrong pasword! Password: %c%c%c 1 - wrong pasword! Password: 1%c%c%c 1 2 - wrong pasword! Password: 12%c%c%c 12 3 - wrong pasword! Password: 123%c%c%c 123 4 - wrong pasword! Password: 1234%c%c%c 1234 - wrong pasword! Password: 1234 You're COOl hacker!!! Сообщая что пароль не верный, программа выводит следующий верный симол пароля(перед "- wrong pasword!"), таким образом, убрав ограничение на 2-е попытки (122 сивола 'a'), мы посимвольно подбираем верный пароль.
Особой сложности не имеет. Есть два способа обхода. 1) Системный. Часто все забывают, что типовой системный ввод обладает "историей". Достаточно во время ввода нажать кнопку вверх, последнее введённое значение будет подставлено. 2) Программный. В самом деле, внимательно смотрим на два куска кода. и Соответственно, значением a_passwords[1] можно переписать значение p_user, заставив программу сравнивать пользовательский пароль сам с собой. Проверим идею - вуа-ля, см. рисунок: С клавиатуры вводятся (через Alt+Num Цифра) три байта. В моём случае - с кодами 20, 255, 18 (0x12FF14). Путём анализа скомпилированного кода можно узнать значение для конкретного случая. Желтым выделена область, содержащая эталон пароля, красным - пользовательский, зелёным - ссылочные переменные. Возможно затереть только три байта первой ссылки (нулевой символ с клавиатуры ввести нельзя). Таким образом, просто узнав второй адрес, можно поместить его в кодах позади последовательности, буфер переполнится, значение затрётся, после ста проверок флаг всё равно будет нулевой. Пример данных, затирающих ссылку. Видно, что данные ссылок одинаковы. Именно это обстоятельство позволяет осуществить успешную атаку.
Тогда придётся активно осваивать gdb. Сейчас, к сожалению, ни одной завалящей консоли под рукой нет, проверить не на чем, как на обед пойду - гляну, что да как.
Проанализировав программы с разных компиляторов, пришел к выводу, что решения с затиранием числа попыток ввода и указателей (p_user, p_etalon) очень сильно зависят от компилятора и флагов компиляции. Например у меня на xp pro sp2 с компилером gcc, без оптимайза число попыток непосредственно загружалось в регистр в программе, а указатели находились до массива, так что эти способы не канали (хотя изменяя флаги компиляции можно было прийти к данным решениям). Тем не менее существует (на мой взгляд) достаточно универсальный способ нахождения пароля. Завтра я его выложу (после того как сдам работу преподу, конкуренция блин=) ), кто выложит до меня поставлю +15 (ибо способ достаточно сложен для нахождения), если будет найден ещё один универсальный способ поставлю +20. Дерзайте =)
Немного усовершенствовал =) Code: Etalon password: AAAABBBB [....] Password: %p:%p:%p:%p:%p:%p:%p:%p:%p:%p:%p:%p:%p 0xa:(nil):0x41:0x7f86618356f0:0xa:[B]0x7fff69875360[/B]:0x7fff698753c4:0x4242424241414141:(nil):(nil):(nil):(nil):(nil) - wrong pasword! Password: Получаем содержимое стэка через ошибку форматной строки. С помощюь gdb определяем, что 0x7fff69875360 указывает на Etalon password ( виден дальше в стэке - 0x4242424241414141 ), а т.к. это 6-й аргумент, то вытащить его из стэка можно с помошью спецификатора "%6$s": Code: Etalon password: qwertyzaq1234 [....] Password: %6$s qwertyzaq1234 - wrong pasword! Password: qwertyzaq1234 You're COOl hacker!!! Компилил gcc linux x86_64. Возможно в других систаемах/компиляторах вместо "%6$s" что-то другое будет. http://void.ru/content/760 - статья про format string error.
Да это и есть тот способ, работает и в unix под gcc, и в win под vs и borland, с инверсированным стеком и нет. Молодец +15 ЗЫ. Как оказалось, больше универсальных способов нет