Pull to refresh
0

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

Reading time 5 min
Views 7.7K
Мы, дети 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!» на белый флаг и выдать долгожданные ключи!
Tags:
Hubs:
+22
Comments 5
Comments Comments 5

Articles

Information

Website
neobit.ru
Registered
Employees
51–100 employees
Location
Россия