Задание Strings (main):
Sometimes just by running strings on binary you can figure out something useful. Too bad that it is not the case
Сразу открываем в дизассемблере (у меня IDA). Стоит сказать, что я рефактнул некоторые моменты для понимания логики.
// есть параметр? ./main FLAG\nif ( count != 2 )\n\tgoto WRONG;\n\t\n// длина 60\t\nif ( strlen(param[1]) != 60 )\n\tgoto WRONG;\n\t\n// начинается с BL\t\nif ( param[1] != 'BL' )\n\tgoto WRONG;\n\t\n// и иметь фигурные скобки\t\nif ( param[1][2] != '{' )\n\tgoto WRONG;\nif ( param[1][59] != '}' )\n\tgoto WRONG;\n// итого: BL{........................................................} \n \nparam_len = strlen(param[1]);\n// дешифруем только то, что в фигурных скобках\ndecrypt(param[1] + 3, param_len - 4, result, 0x3F);\n\n// сравниваем результат\nif ( !strcmp(result, "LB{1_t0old_y0u_5trings_w0ont_h33lp}") )\n{\n\tputs("Correct!");\n\treturn 0;\n}\nelse\n{\n\tWRONG:\n\tputs("Wrong!");\n\treturn 0;\n}
В main нужно предоставить 60 символьный флаг, и тогда пойдет дешифровка:
./main BL{........................................................}
Смотрим decrypt с комментариями:
// цикл на всю длинну флага\nfor ( i = 0; i < length; ++i )\n{\n\tresult = 0;\n\t// берем по 8 символов\n\tfor ( j = 0; j <= 7; ++j )\n\t{\n\t\t// умножение на 32\n\t\t// в ассемблере это shl [rbp+result], 5\n\t\t// что оказалось более понятнее\n\t\t// ибо это смещение на 5 бит влево\n\t\t// v7 = result << 5\n\t\tv7 = 32 * result;\n\t\t// эта функция ниже\n\t\tchar = char_convert((unsigned int)*(char *)(j + 8 * i + a1));\n\t\tif ( char < 0 )\n\t\t\treturn -1;\n\t\t// здесь так же в ассемблере более понятнее\n\t\t// or [rbp+result], rax\n\t\t// добавляем к результату\n\t\t// по сути v7 - это result\n\t\t// result |= char;\n\t\t// оставил оригинал для наглядности\n\t\tresult = char | v7;\n\t}\n\t// перемещаем получившиеся байты к итоговому результату\n\tfor ( k = 0; k <= 4; ++k )\n\t{\n\t\t*(_BYTE *)(5 * i - k + 4 + a3) = result;\n\t\tresult >>= 8;\n\t}\n}
Что такое char_convert?
// ( char > '@' && char <= 'Z' )\nif ( char > 64 && char <= 90 )\n\treturn 96 - a1; // 6-31\n// ( char > '1' && char <= '7' )\nif ( char > 49 && char <= 55 )\n\treturn a1 - 50; // 0-5\nif ( char == 61 )\n\treturn 0;\nreturn -1;
Идет проверка каждого символа, и если подходит по параметрам, то происходит вычисление.
На выходе максимум может быть 31 - это в двоичном представлении: 11111.
Пять бит. Это те самые пять бит, которые присоединяются к результату, сразу после смещения на теже пять бит.
SHL << 5 нагляднее показывает, чем умножение на 32. С другой стороны, это новые знания.
Далее по коду видно, что входные 8 байт (символов) превращаются в 5 байт (символов) на выходе.
Тоесть, в decrypt приходит 56 байт, делим на 8 и умножаем на 5, получаем на выходе 35 байт.
Это как раз длина строки сравнения LB{1_t0old_y0u_5trings_w0ont_h33lp}
Итого:
Для примера первая часть: LB{1_ = 100110001000010011110110011000101011111. Не забываем добавлять слева 0 до размера 40.
Получается WO3YJTVA. И т.д.
Флаг: LB{WO3YJTVARPHZBE56UCDM2CVAZKFY6FURTCGKBCGPSCIYXIEXZTGJHD5C}
P.S. Естественно все это было вскопе с дебаггером. Сейчас в Windows дебажить Linux софт в разы проще. WSL не заменимая вещь в этом. Ставим Ubuntu (или), в нем gdbserver, вешаем его на порт, и погнали...