Гремлины и ELFийская магия: а что, если ELF-файл — это контейнер?

    Мы, дети 90-х, любим добавить в задания NeoQUEST что-нибудь олдскульное. В этом году нам вспомнились гремлины, и мы добавили их в легенду одного из заданий соревнования «Очной ставки» NeoQUEST-2017.

    Однако, под внешне забавной легендой скрывается вполне себе реальная практическая задача: а что, если привычные ELF-файлы — не просто исполняемые файлы, а контейнеры, открыть которые нам предстоит? Для этого придется испытать довольно-таки обширные возможности objcopy и освежить в памяти организацию ELF-файла.

    Чтобы вычислить подозрительные секции, необходимо представлять секционный и сегментный состав типичного ELF. Помимо этого, конечно, пригодится и опыт — например, общение с firmware embedded-систем вполне может подсказать подходящие идеи!

    Думаете, готовы на 100%? Уверены, что гремлинам удастся вас удивить спрятанными архивами, попорченными таблицами символов, а также аудиофайлами, которые зазвучат только в руках умелого мастера! Под катом — исходники к заданию и прохождение, чтобы каждый читатель Хабра мог собственноручно попробовать пройти задание!

    Исходные данные к заданию


    Легенда к заданию выглядела так:

    Прибыв на место, мы обнаружили, что на базе полнейший хаос и разруха. Все это устроила парочка местных аборигенов, очень похожих на гремлинов из известного земного фильма. Один из них явно был главным в этой небольшой банде, более крупный, наглый и разговорчивый:
    — Hehehehehehe, we had ate your message! Had ate this stupid gremlin! And will eat you!
    Второй, мельче и скромнее, держался позади своего товарища и периодически выкрикивал:
    — The Gremlins Are Coming!

    Похоже, эти паршивцы не только устроили хаос и разруху, повредили оставленное нам сообщение, но еще и товарища своего слопали…

    Исходные данные — три файла: greik, straip и message.

    Исходя из легенды, понимаем, что самый важный файл — message, и нужно его прослушать. Но, само собой, он не работает (иначе в чем смысл задания?). Если запустить его, получим следующую информацию:

    Sorry, but i'm lost my prepare section...

    Чтобы починить наше сообщение, надо «распотрошить» двух гремлинов, которые всё
    «погрызли», в том числе, и своего товарища. Запустим каждый файл. После ./greik увидим:

    The Gremlins Are Coming! (оригинальная цитата из фильма, между прочим!)

    После ./straip:

    Hehehehehehe, we had ate your message! Had ate this stupid gremlin! And will eat you!

    То есть, всё то, что описано в легенде. Раз эти гремлины съели всё необходимое для прохождения задания, нужно посмотреть, что у них внутри! Применим утилиту readelf на оба файла. Нас будут интересовать только секции файла и информация о них, поэтому необходимо использовать флаги -SW. В результате получим для straip:


    Обратим внимание на секцию 28, stomach (желудок!). Сдампим ее. Для этого можно
    воспользоваться либо утилитой dd, высчитав все необходимые смещения, либо утилитой objcopy следующим образом:

     objcopy -O binary --only-section=.stomach --set-section-flags .stomach=alloc straip stomach
    

    Аналогичные действия произведем для файла greik. Выдача readelf -SW:


    Дампим секции 28 и 29 (.first_stuff и .second_stuff):

    objcopy -O binary --only-section=.first_stuff --set-section-flags .first_stuff=alloc greik first_stuff
    objcopy -O binary --only-section=.second_stuff --set-section-flags  .second_stuff=alloc greik second_stuff
    

    Посмотрим, что же мы тут наизвлекали. Для этого используем утилиту file для каждого из извлеченных файлов. В результате получим:

    stomach: Zip archive data, at least v2.0 to extract
    first_stuff: data
    second_stuff: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped


    Разархивируем stomach и, используя утилиту file, посмотрим, что за файлы мы получили:

    sec1: data
    piece2: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
    key1: ASCII text


    Ура, получили промежуточный ключ key1 («ISCJcPhB33cAvq9F9YkaZyU91SfwSObn»)! Остальные файлы необходимы для дальнейшего решения задачи. Исходный файл message сообщал, что у него потеряны секции, и из архива мы извлекли файл с именем sec1.

    Применим утилиту readelf на message:


    Видим, что имеется секция .extract (16) размером 0x50 (80). Также у нас есть один из извлеченных из гремлинов файлов размером 0x50 — first_stuff. Восстановим эту секцию:

    objcopy --update-section .prepare=first_stuff message
    

    Снова запустим message:

    Preparing data for extract…
    Preparing data successful
    Sorry, but i'm lost my extract section...


    Ему не хватает еще одной секции. По аналогии с предыдущей секцией восстанавливаем и эту:

    objcopy --update-section .extract=sec1 message
    

    Снова запускаем message:

    Preparing data for extract…
    Preparing data successful
    Extracting key data…
    Extracting complete successful


    Все выполнилось. В результате получили аудио-файл message.mp3. Однако, если попытаться его прослушать, мы услышим лишь тишину, потому что данные нулевые. Вспомним, что straip
    говорил нам, что они сожрали еще одного гремлина, и у нас осталось два неиспользованных файла в формате ELF.

    Запуск их не даст ничего, кроме ошибки:

    Failed to execute process './second_stuff'. Reason:
    exec: Exec format error
    The file './second_stuff' is marked as an executable but could not be run by the operating system.


    Это все потому, что эти объектники необходимо слинковать друг с другом:

    gcc second_stuff piece2 -o gremlin
    

    В результате получим:

    piece2: In function `main':
    gizmo.c:(.text+0x5b): warning: the `gets' function is dangerous and should not be used.
    gizmo.c:(.text+0x86): undefined reference to `get_back_function'
    collect2: error: ld returned 1 exit status


    И снова все не так, как должно быть! Используем утилиту readelf на наши «куски» гремлина, но на этот раз посмотрим таблицу символов (ключ -s). Для second_stuff:


    Для piece2:


    Видим, что в одном из них есть наша функция get_back_function, на которую ругался компилятор, а во втором есть некая функция с именем «a4f922hjd9843jd». Переименуем ее в get_back_function:

    objcopy --redefine-sym a4f922hjd9843jd=get_back_function second_stuff
    

    Попробуем повторить сборку файла:

    gcc second_stuff piece2 -o gremlin
    

    piece2: In function `main':
    gizmo.c:(.text+0x5b): warning: the `gets' function is dangerous and should not be used.


    Как видим, теперь все хорошо. Запускаем gremlin:

    Hello… I tried saved your message, but forgot my name… Remember my name, plese and I can get back part of your
    >>


    Парниша вроде неплохой: пытался спасти наше сообщение, за что и пострадал. Готов все нам вернуть, да вот только своё имя забыл. Имя его Gizmo (оригинальное имя хорошего гремлина из фильма). Это можно увидеть как еще в процессе сборки, так и в любом HEX-редакторе в самом начале как исходных объектников, так и самого файла gremlin.

    Введем его имя (с большой буквы, конечно!), ииии…

    Hello… I tried saved your message, but forgot my name… Remember my name, please and I can get back part of your
    >> Gizmo
    Yes, yes! It's my name! Get back your part of file!


    В результате получим еще один файл data_section. Легко догадаться, что и его мы запихиваем в исходный файл message:

    objcopy --update-section .key=data_section message
    

    Эту секцию .key можно было заметить еще когда мы исследовали утилитой readelf файл message. Во-первых, имя у нее говорящее, во-вторых, размер совпадает с тем, что вернул нам Gizmo.

    Запустив файл message еще раз, мы уже получим нормальное сообщение, которое можно
    прослушать. Там сказано, что нам необходимо взять md5-хэш от этого файла и это будет ключом. Берём md5 и получаем ключ: 65935b0ae91b566c14c8b584ee8cf85d.

    Happy End!


    Оказывается, ELF-файл может быть далеко не просто исполняемым файлом, а контейнером для чего-либо. Это задание можно было пройти, выполнив реверс бинарников, но не реверсом единым сильны специалисты по инфобезу!

    В данном варианте прохождения достаточно нескольких нехитрых манипуляций — и ELF-ский пазл успешно сложен, секции и таблицы символов восстановлены, архивы распакованы, а нашим гремлинам не остается ничего, кроме как сменить внушительное «The Gremlins Are Coming!» на белый флаг и выдать долгожданные ключи!
    НеоБИТ
    Company

    Comments 5

      0

      Очень интересная статья! Не думал, что "эльфы" имеют столько возможностей.

        0

        На эльфах держится Objective-C объектная надстройка.

          0
          Большое спасибо! Старались! :)
          0
          Интересная задачка. Спасибо за ее публикацию.
            0
            Вам спасибо за отзыв) Будем писать еще!

          Only users with full accounts can post comments. Log in, please.