Надо пройти все проверки, чтобы приложение отобразило флаг.
Бинари:
Solution
Посмотрю инфу о файле:
Info:
File name: /spbctf_rev/task3/task3
Size: 7628
File type: ELF32
String: ELF(386)
Extension: elf
Operation system: Ubuntu Linux(16.04.4,ABI: 2.6.32)
Architecture: 386
Mode: 32-bit
Type: EXEC
Endianness: LE
Закидываю бинарь в Binary Ninja. Угадайте, что я иду смотреть?) Правильно, функцию main)
int32_t main(int32_t argc, char** argv, char** envp) {
void* const __return_addr_1 = __return_addr
int32_t* var_c = &argc
char** argv_1 = argv
void* gsbase
int32_t eax_1 = *(gsbase + 0x14)
FILE* fp = fopen(filename: "Hello1", mode: "r")
int32_t result
if (fp != 0)
void buf
fgets(&buf, n: 0xff, fp)
fclose(fp)
FILE* fp_1 = fopen(filename: "Hello2", mode: "r")
if (fp_1 != 0)
void buf_1
fgets(buf: &buf_1, n: 0xff, fp: fp_1)
fclose(fp: fp_1)
if (check(&buf, &buf_1) == 0)
if (check2(&buf) == 0)
printf(format: "Flag{%s}\n", &buf)
result = 0
else
puts(str: "Nope")
result = 1
else
puts(str: "NOT AGAIN!")
result = 3
else
puts(str: "NOOOOO")
result = 5
if (eax_1 == *(gsbase + 0x14))
return result
__stack_chk_fail()
noreturn
}
Сперва обратил внимание на данный кусок кода:
FILE* fp = fopen(filename: "Hello1", mode: "r")
int32_t result
if (fp != 0)
void buf
fgets(&buf, n: 0xff, fp)
fclose(fp)
FILE* fp_1 = fopen(filename: "Hello2", mode: "r")
if (fp_1 != 0)
void buf_1
fgets(buf: &buf_1, n: 0xff, fp: fp_1)
fclose(fp: fp_1)
В нем открывается 2 файла для чтения — Hello1 и Hello2. В buf и buf_1 происходит чтение их содержимого. Значит для решения лабы нужно будет создать эти файлы.
Далее нужно разобрать функции check и check2. Начну рассматривать их по порядку:
int32_t check(char* arg1, char* arg2) {
size_t len1 = strnlen(arg1, 256);
size_t len2 = strnlen(arg2, 256);
if (len1 != len2)
return -1;
int32_t var_18_1 = 0;
int32_t i = 0;
while (true)
{
if (i >= len1)
return 0;
if (arg1[i] != arg2[((len2 - 1) - i)])
break;
i += 1;
}
return -1;
}
После пары переименований и преобразований становится ясно, что строки должны быть одинаковой длины, а также что в Hello1 хранится прямое представление строки, а в Hello2 — перевернутая строка.
Перейду к check2:
int32_t check2(char* arg1) {
if (strnlen(arg1, 256) != 8)
return -1;
if (*(uint8_t*)arg1 != arg1[6])
return -1;
if (arg1[2] != arg1[3])
return -1;
if (arg1[3] != arg1[7])
return -1;
if (arg1[1] != 'f')
return -1;
if (arg1[7] != 's')
return -1;
if (*(uint8_t*)arg1 != 'z')
return -1;
if ((((int32_t)arg1[5]) - ((int32_t)arg1[4])) != 8)
return -1;
if (arg1[5] == 'i')
return 0;
return -1;
}
Такс… Давайте разбираться:
if (strnlen(arg1, 256) != 8)
return -1;
Значит длина строки — 8.
if (*(uint8_t*)arg1 != arg1[6])
return -1;
if (arg1[2] != arg1[3])
return -1;
if (arg1[3] != arg1[7])
return -1;
Группы элементов 0 и 6, а также 2, 3, 7 — совпадают.
if (arg1[1] != 'f')
return -1;
if (arg1[7] != 's')
return -1;
if (*(uint8_t*)arg1 != 'z')
return -1;
if ((((int32_t)arg1[5]) - ((int32_t)arg1[4])) != 8)
return -1;
if (arg1[5] == 'i')
return 0;
1 элемент — f, 7 — s, 0 — z, 5 — i.
Ну а 4 элемент меньше 5 на 8.
Представим ключ:
zfssaizs
Создам файлы:

Запущу бинарь:
root@6a23fdb0da11:/rev# ./task3
Flag{zfssaizs}