Plaid CTF 2013 (three-eyed-fish)

Решения

http://f00l.de/blog/plaid-ctf-2013-three_eyed_fish/ (Rup0rt)
http://blog.0kami.net/?p=6 (Okami)

http://broot.ca/blog/plaidctf-three-eyed-fish-binary-100 (Alex Weber)
А также видео от Alex Weber:
http://www.frequency.com/video/skspctf-plaidctf-aftermath-three-eyed/91963052/-/5-14792

Назад к списку заданий

Задание (binary)

image00.jpg

Подробное описание

Инструменты: виртуальная машина с х64 Linux на борту, IDA Pro.

Из условия задания вообще не понятно - какая наша реальная цель. Единственное, что доступна ссылка на загрузку файла. Скачиваем бинарный файл three_eyed_fish.

Проверяем, что за зверь…

fes@Linux64:~/Plaid13/Binary$ file ./three_eyed_fish
./three_eyed_fish: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped

.. 64-битный исполняемый файл Linux. Запускаем на исполнение:

fes@Linux64:~/Plaid13/Binary$ sudo ./three_eyed_fish

Программа ничего не выводит и выполняется какое-то время. Как выяснилось, при выполнении программы мигает светодиод на клавиатуре. Причем, мигание не равномерное, выделить какую-нибудь закономерность невозможно. Только есть видимая задержка между последовательностями перемигиваний. Что ж подошло время для strace. Работа strace заключается в перехвате и записи системных вызовов, выполненных процессом, а также полученных им сигналов.

fes@Linux64:~/Plaid13/Binary$ strace ./three_eyed_fish
………
ptrace(PTRACE_TRACEME, 0, 0, 0) = -1 EPERM (Operation not permitted)
- - - SIGSEGV (Segmentation fault) @ 0 (0) - - -
+++ killed by SIGSEGV (core dumped) +++

Программа не запустилась. Причиной тому является антиотладочный трюк - ptrace(PTRACE_TRACEME). Как правило, ptrace() используется некоторыми процессами для трассировки или отладки другого процесса. Однако, вызов функции ptrace() с флажком PTRACE_TRACEME совершает обратное действие - в этом случае, ptrace(PTRACE_TRACEME) используется как быстрый и простой способ обнаружить присутствие отладчика в текущем процессе. Функция возвращает не 0, если отладчик уже подключен, поэтому наша программа, обнаружив отладку, завершает процесс.

К счастью, есть известный и простой способ решить эту проблему: с помощью LD_PRELOAD, как описано, например, в этом блоге.
А можно и так: заменить вызов ptrace в коде на RETN-NOP. В дизассемблере находим последовательность байт, соответствующая вызову функции ptrace, и заменяем на опкод RETN и NOP.

list_z = [
"\xFF\x25\x02\x24\x20\x00", "\xC3\x90\x90\x90\x90\x90",
]
 
binary = open("three_eyed_fish", "rb").read()
binary = binary.replace(list_z[0],list_z[1])
 
open("three_eyed_fish_", "wb").write(binary)

Снова запускаем strace (полная трасса программы). На экран вывелось очень много вызовов usleep(), а еще ioctl() – с помощью него бинарник пытается включить и выключить на клавиатуре светодиод! Так все же, что же означает это мигание? Оказалось, таким образом, передавались символы азбуки Морзе!

ioctl(3, KDGETLED, 0x6f1010) = 0

включить светодиод
ioctl(3, KDSETLED, 0x4) = 0
задержка для «точки»
nanosleep({0, 250000000}, 0x4b32) = 0
выключить светодиод
ioctl(3, KDSETLED, 0) = 0
nanosleep({0, 250000000}, 0x4b32) = 0
ioctl(3, KDGETLED, 0x6f1030) = 0

включить светодиод
ioctl(3, KDSETLED, 0x4) = 0
задержка для «тире»
nanosleep({0, 250000000}, 0x4b32) = 0
nanosleep({0, 250000000}, 0x4b32) = 0
nanosleep({0, 250000000}, 0x4b32) = 0
выключить светодиод
ioctl(3, KDSETLED, 0) = 0

задержка для «разделителя символов»
nanosleep({0, 250000000}, 0x4b32) = 0
nanosleep({0, 250000000}, 0x4b32) = 0
nanosleep({0, 250000000}, 0x4b32) = 0

ioctl(3, KDGETLED, 0x6f1050) = 0
включить светодиод
ioctl(3, KDSETLED, 0x4) = 0
задержка для «тире»
nanosleep({0, 250000000}, 0x4b32) = 0
nanosleep({0, 250000000}, 0x4b32) = 0
nanosleep({0, 250000000}, 0x4b32) = 0
выключить светодиод
ioctl(3, KDSETLED, 0) = 0
nanosleep({0, 250000000}, 0x4b32) = 0
ioctl(3, KDGETLED, 0x6f1070) = 0
ioctl(3, KDSETLED, 0x4) = 0
nanosleep({0, 250000000}, 0x4b32) = 0

Если весь вывод strace обработать, то из символов азбуки Морзе получим текст:

#!/usr/bin/env python
on = "ioctl(3, KDSETLED, 0x4)";
off = "ioctl(3, KDSETLED, 0)";
sleep = "nanosleep({0, 250000000}";
 
f = open("trace.txt")
lines = [line.strip() for line in f]
f.close()
 
res = ""
state = "OFF";
timer = 0;
for li in lines:
    if li.find(on) >= 0:
        if state == "OFF":
            if timer == 3:
                res += "  "
            timer = 0
            state = "ON"
    if li.find(off) >= 0:
        if state == "ON":
            if timer == 1:
                res += "."
            elif timer == 3:
                res += "-"
        timer = 0
        state = "OFF"
    if li.find(sleep) >= 0:
        timer += 1
 
print("[+]Result = "+res)

Флаг:
and0u0didnt0even0need0an0arduino

Пока не указано иное, содержимое этой страницы распространяется по лицензии Creative Commons Attribution-ShareAlike 3.0 License