Задание должно было решиться легко, но я столкнулся с проблемой, которую долго не мог решить. Открыв приложение в гидре можно увидеть, что доступен флаг debug, если в меню указать пункт 'D'. После включения флага, переходим в check_pass. Декомпилятор гидры выдал вот такой код. Ниже приведен код функции check_pass, и я решил, написать свой генератор кода, но генерировался совсем не тот код, который бы подошел.
Долго провозившись, я начал обдумывать другие решения. Что ещё может остаться в данном случае, чтобы попытаться решить задачу. Мне пришел верный вариант. Мы можем использовать эту же программу для генерации кода.
Итак, я зашел на сервер и дошел до места ввода пароля. Было указано время. [2024-04-13 11:18:51].
С помощью вот такого сишного кода я смог сгенерировать нужное время.
Почему я добавил к 11 ещё 5, это стало ясно далее, когда я попытался сгенерировать пароль. Уж пришлось так сделать, потому что время отставало на 5 часов. Запишем число, которое выдала утилита.
Что делаем дальше? Заходим с помощью отладчика с помощью radare2.
Переходим в функцию main, затем переход в режим просмотра и переход в функцию check_pass.
Я приведу пример простого дизассемблера, потому что так проще. Будет без картинок, но вы держитесь. Так тоже можно объяснить. Посмотрите на этот код.
Как мы видим, по адресу 0x122f мы записываем результат rax в локальную переменную. Тут то нам и нужно поменять значение rax. Но для начала переходим в режим просмотра отладчика.
Так мы поставили наш первый бряк на место в памяти. Осталось поставить бряк на место проверки пароля, чтобы посмотреть сгенерированный пароль.
Опять нажимаем ':' и ставим бряк на адрес 0x1374.
Далее пишем в отладчике
и начинает выполняться программа. Включаем отладку, чтобы удостовериться, что время такое как на сервере (тот самый сервер, который на codeby.games - мастер рандома). Затем переходим в вести пароль. бряк останавливает выполнение.
Записываем в rax новое значение. Если вы забыли, то в rax сейчас содержится время в секундах. Его мы меняем на то, что нам пишет утилита (та, которая генерирует число mktime из даты).
Теперь можем продолжить выполнение программы.
Далее он предлагает указать пароль. Пишем всякий вздор и нажимаем enter. Бряк останавливает нас на проверке. Отсюда мы достаем нашу строку.
Эта строка и есть пароль к серверу, которая завязана на времени. Время генерируется при каждом новом вызове функции, поэтому важно не затупить, а то придется несколько операций заново производить.
Всем спасибо.
C++:
void check_pass(void)
{
int iVar1;
tm *__tp;
char local_118 [88];
time_t local_c0;
char our_password [65];
char generated_password [65];
int index;
local_c0 = time((time_t *)0x0);
srand((uint)local_c0);
for (index = 0; index < 0x40; index = index + 1) {
iVar1 = rand();
generated_password[index] = (char)iVar1 + (char)(iVar1 / 0x1a) * -0x1a + 'A';
}
generated_password[64] = '\0';
if (is_debug == '\x01') {
__tp = gmtime(&local_c0);
strftime(local_118,0x50,"%Y-%m-%d %H:%M:%S",__tp);
printf(s_[%s]_-_LOG:_00102020,local_118);
puts("...ubuntu3.6_amd64");
printf("_IO_2_1_stdin_: %#lx\n",our_password._48_8_);
}
printf(s__:_0010206d);
fflush(stdout);
fgets(our_password,0x41,stdin);
iVar1 = strcmp(generated_password,our_password);
if (iVar1 == 0) {
give_me_data();
}
else {
puts(&DAT_0010208b);
}
return;
}
Долго провозившись, я начал обдумывать другие решения. Что ещё может остаться в данном случае, чтобы попытаться решить задачу. Мне пришел верный вариант. Мы можем использовать эту же программу для генерации кода.
Итак, я зашел на сервер и дошел до места ввода пароля. Было указано время. [2024-04-13 11:18:51].
С помощью вот такого сишного кода я смог сгенерировать нужное время.
C:
time_t t = time (0);
tm = gmtime (&t);
tm->tm_hour = 11 + 5;
tm->tm_min = 18;
tm->tm_sec = 51;
t = mktime (tm);
printf ("time: %s\n", t);
Почему я добавил к 11 ещё 5, это стало ясно далее, когда я попытался сгенерировать пароль. Уж пришлось так сделать, потому что время отставало на 5 часов. Запишем число, которое выдала утилита.
Что делаем дальше? Заходим с помощью отладчика с помощью radare2.
Bash:
r2 -d task.elf
Bash:
s main
V
листаем вниз и встречаем функцию check_pass.
Смотрим какое число справа от check_pass (у меня это было 2)
Нажимаем 2 и мы переходим в код этой функции.
Код:
;-- check_pass:
0x0000121a push rbp
0x0000121b mov rbp, rsp
0x0000121e sub rsp, 0x110
0x00001225 mov edi, 0
0x0000122a call sym.imp.time
0x0000122f mov qword [rbp - 0xb8], rax
0x00001236 mov rax, qword [rbp - 0xb8]
0x0000123d mov edi, eax
0x0000123f call sym.imp.srand
0x00001244 mov dword [rbp - 4], 0
┌─<0x0000124b eb38 jmp 0x1285
│ 0x0000124d e88efeffff call sym.imp.rand
Код:
V!!
нажимаем ':'
db 0x122f
Так мы поставили наш первый бряк на место в памяти. Осталось поставить бряк на место проверки пароля, чтобы посмотреть сгенерированный пароль.
Код:
0x00001363 488d9550ffff. lea rdx, [rbp - 0xb0]
0x0000136a 488d45a0 lea rax, [rbp - 0x60]
0x0000136e 4889d6 mov rsi, rdx
0x00001371 4889c7 mov rdi, rax
0x00001374 e817fdffff call sym.imp.strcmp
Код:
db 0x1374
Код:
dc
Записываем в rax новое значение. Если вы забыли, то в rax сейчас содержится время в секундах. Его мы меняем на то, что нам пишет утилита (та, которая генерирует число mktime из даты).
Код:
dr rax=0x.... <- здесь число в шестнадцатеричной системе счисления
Код:
dc
Код:
ps @rdi
Всем спасибо.