Реверс с AlexCTF 2017
Статья написана тиммейтом Revervand.
На прошедшем AlexCTF, категория ревёрса была представлена 5 не сложными заданиями, и довольно много команд решили её до конца(а точнее 99). Наша команда тоже решила все таски в это категории. Ниже приведён разбор каждого задания.
Реверс с AlexCTF 2017
Описание остутсвует, но названия задания намекает на то, что это подарок, значит скорей всего в бинарнике просто так лежит флаг.
Можно использовать команду “strings” в Linux, или просто открыть любох Hex-редактор и попробовать поискать по форме флага. К слову, часто первые задания на ревёрс в несложных CTF’ax выглядят именно так.
Флаг : AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}
RE2: C++ is awesome – 100 очков
Описание: They say C++ is complex, prove them wrong!
Нам дан бинарь под Линукс х86-64. Выгрузим в Ida, сразу посмотрим какие строки есть в программе, чтоб было проще понимать что где от нас требуется и что где вызывается.
По этим строкам можно понять, что мы вводим флаг, он как-то сверяется и если он верный, то его же мы можем использовать для ответа. То есть проверка флага происходит внутри программы. То есть либо флаг будет преобразовываться и сравниваться с каким-то уже высчитанным значением, либо просто будет сравниваться, без преобразования. Ещё обратим внимание на довольно подозрительную 1 строку, которая довольно длинная и содержит очень похожие символы флага, но конкретной формы не имеет. Уже здесь можно предполагать, что значения будут браться из этой строки и использоваться для проверки. Но давайте точно убедимся в этом.
Перейдём в сегмент данных где лежит наша первая строка и посмотрим по xref’у где она вызывается.
Нас перекинет на ещё один сегмент данных, где данная строка представлена как массив символов. Проделав тоже, что и в первый раз мы попадаем в функцию main(), в место некой проверки.
Данная проверка расположена в конце функции main(), не сложно заметить, что только при равенстве v11 и off_6020a0[dword_6020c0[v17]] происходит инкерементация счётчика и проверка продолжается, а если данные значения не будут равны произойдёт вызов ф-ии sub_400B56(), которая выдаёт сообщение о том, что вам надо быть успешнее в следующий раз, то есть мы провалились.
Конструкция off_6020A0[dword_6020C0[v17]] – довольно проста для понимания. Получаемое нами значение хранится в неком массиве off_6020A0, индекс значения зависит от значения в другом массиве – dword_6020c0, а его индекс – это счётчик, то есть мы последовательно берём значения из одного массива и используем их как индекс элемента в другом массиве. Всё довольно просто.
Итак нам нужно получить первый массив и второй, в первом как не сложно догадаться будут буквы нашего флага, а во втором индексы для первого. Впринципе первый массив у нас уже есть, эта та длинная строка, на которую мы обратили внимание в начале.
Massiv 1 = “L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t”
Massiv 2 = 5,54,101,7,39,38,45,1,3,0,13,86,1,3,101,3,45,22,2,21,3,101,0,41,68,68,1,68,43
Простейший скрипт на питоне(даже не скрипт а один цикл)
И получаем наш флаг ALEXCTF{W3_L0v3_C_W1th_CL45535}
RE3: Catalyst system – очков 150
Описание: CEO of catalyst systems decided to build his own log in system from scratch, he thought that it is so safe that no one can fool around with him!
Хотелось бы начать с того, что иногда задание решить проще, чем объяснить как ты это сделал, потому что иногда ты сам не можешь понять почему именно так ты сделал, а не иначе.
У нас есть ELF X86-64, смысл задания просто – нам нужно узнать логин и пароль, для того чтоб зарегистрироваться в системе, и потом система выдаст флаг. Перед тем, как писать решение, я посмотрел как решали все остальные и способов нашёл кучу, и вроде нигде(а может проглядел просто) не нашёл способ которым решал я. Наверное потому что он долгий и не очень приятный( по этому некоторые вещи в решение будут упрощены). Ну да хватит введения начнём.
Центром всего задания является разбор 5 функций(в других методах решения разбирали всего 1 или 2 функции). Первые три функции принимают только логин, последние две логин + пасс.
Итак начнём по порядку:
Sub_400C9A()
Выглядит она так:
Видно, что она возвращает другую функцию, которая вызывается с аргументом который является длинной нашего логина.
Здесь центром нашего внимания становится длинное условное выражение.
Полностью разбирать данное выражение у меня не было желания и я просто перекомпировал код и запустил его по значениями от 0 до 20(ну логин обычно маленький должен быть). Получил 2 числа при которых функция не выдаёт ошибку, это 8 и 12.
То есть длина логина равна 8 или 12.
Далее идёт функция проверки самого логина.
sub_400CDD() :
Мы видим что наш логин бьётся на 3 равные части, значит всё таки 12 символов. Далее эти части проходят некую валидацию. Ну я не долго думаю увидел здесь некую систему уравнений.
После решения получаем:
Мы получаем 3 части, которые представляют собой целочисленное представление 4 подряд идущих букв в логине. При чём если попытаться перевести эти числа из dec в ASCII, то получим первую букву из 4 идущих (я так и не понял почему). Опять же не особо долго думаю путём копирования части кода и небольшого дописывания своего, я реализовал перебор возможных комбинаций 4 букв и знаков и сверки их целочисленного значения с оригиналом. Если интересно то вот этот
По поводу красоты, скорости, оформления я особо не запаривался, потому что просто хотел решить задание. Таким вот нехитрым образом я получил все 3 части по 4 буквы и получил логин: catalyst_ceo (вообще по идеи не обязательно было получать логин, но об этом потом).
Итак, двигаем к 3 функции.
3 функция не особо интересная она просто ставит ограничения на символы логина, маленькие буквы и знак нижнего подчёркивания. Всё просто идём дальше.
Функция проверки пароля sub_400977() :
Итак мы подошли к самому интересному(нет) в нашем задание, это функция проверки пароля. Для начала идёт проверка, какие символы используются. Переведя все цифры в аски символы понимаем что в пароле может быть только A-Z,a-z,0-9.
Далее идёт расчёт srand() про него можно почитать тут: http://cppstudio.com/post/841/.
Итак, наш srand(), рассчитывается от суммы 3 чисел которые мы нашли при решение ситемы уравнений(то есть теперь понятно что можно было логин то и не искать и на числах остановиться). Копилирую примерно такую же программу и такой же srand() на винде например вы не получите верные rand() далее, и будете долго мучаться(как я, хотя может вы не такие глупые как я= ) ) . Так вот, надо компилировать на х86-64 Linux’е, но я на там просто получил все нужные 10 rand’ов.
Когда вы получили все 10 rand’ов можно уже приступать к поиску пароля. Вообще смысл проверки – простой, мы получаем некое число которое явл. представление 4 букв пароля( как с логином кароч), отнимаем от него некое рандомное число, и сравниваем с константой. То есть имею все рандомные числа, мы из констант получаем как раз таки наши нужные числа пароля и уже имеющейся от востановления логина программой можем востановить все наши 10 частей пароля.
Получаем пароль:
pass1st : sLSV
pass2st : pQ4v
pass3st : K3cG
pass4st : WyW8
pass5st : 6AiZ
pass6st : hggw
pass7st : LHBj
pass8st : mx9C
pass9st : RspV
pass10st : Gggj
password : sLSVpQ4vK3cGWyW86AiZhggwLHBjmx9CRspVGggj
На этом этапе уже можно было получить флаг, просто залогинившись в системе(но я ленивый, или криворукий , одно из двух), но я не стал так просто это делать. Я подумал, что флаг то мы получим от программы значит, где то есть какие то преобразования чего-то. Это сподвигло меня посмотреть последнюю функцию.
Итак функция выдачи флага, работает довольно просто сначало выдаётся форма, потом определённые значения из заданого массива ксорятся со строкой s, которой вроде как и нет нигде в этой функции кроме объявления(наверное лучи немного подвели), я просто посмотрел длину массива который ксорится и понял, что длина то его 40 символов, как и нашего пароля, вместо s[i] я подставлял символы пароля, а массив задан. Опять небольшой скрипт на питоне и флаг у нас в руках.
RE4:unVM me – очков 250
Описание: If I tell you what version of python I used .. where is the fun in that?
Задание сделал не я, а наш другой наш тиммейт – Corteso. Таск довольно простой, нам дан *.pyc файл, который довольно просто вытаскивается с помощью опенсорсной программы : EasyPythonDecompiler.
Вытащив файл мы получаем полный исходный код программы.
Очень не сложный код. Небольшой анализ позволяет нам понять что от введёного нами пароля берутся по 5 символов подряд от них высчитывается md5 хэш и сверяется с хэшами в таблице, нам просто нужно узнать от чего эти хэши и всё флаг у нас. Проблема могла возникнуть с 6 хэшем, в котором не хвататет одного символа(то есть его длина 31 а не 32), это решается путём дописывания 0 в начале, видимо декомпилер счёл 0 пустым байтом, но это не точно. Таск довольно простой и как мне кажется не стоит 250 очков ( по крайней мере его решили около 350 команд, а за 150 решили всего 200).
RE5: packed movement – очков 350
Описание: Being said that move instruction is enough to build a complete computer, anyway move on while you can.
Последний ревёрс, с которым справились 99 команд(что довльно странно, ибо он проще чем за 150, как мне кажется), наверное остальные просто испугались)
Итак перед нами ELF x86. При первой загрузке в Ida, видно что он запакован. Я сразу зашёл в Hex редактор, чтобы посмотреть может упаковщик оставил в заголовках своё название. Так и есть, и это обычный UPX.
Прелесть Upx в том, что он сам себя распаковывает. Распоковываем простой командой: upx.exe –d move
После распаковки опять загружаем в Ida. Особо понятней не стало, но уже лучше.
Проверим какие строки у нас есть.
Видим строку о неправильном флаге, давайте посмотрим где она вызывается.
Довольно удивительно, но вызывается она очень много раз, это может натолкнуть на мысль о том, что каждый символ проверяется отдельно и если он не правильный вызывается сообщение о неверном флаге, перейдём по первому вызову.
С первого взгляда ничего не понятно, но если глянуть другие вызовы , картина там будет примерно такая же. Пока не видно каких то сравнений и тем более не видно с чём оно происходит.
Пролистав листинг чуть выше я заметил довольно странную инструкцию. Mov R2, 41h, 41h – это аски символ буквы ‘A’ – которая является началом флага.
Не долго думая я нажал на R2 и посмотрел что с ним вообще происходит и где.
Не сложно увидеть что символы заносятся в R2 через одинаковые промежутки, и все эти символы – символы флага. Нехитрыми движениями получаем все аски коды и переводим их в символы и получаем флаг:
ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c}
- Автор: drakylar
- Комментарии: 0
- Просмотры: 6837