→ RuCTF-2010: Histograph

| 3 Comments | No TrackBacks

Histograph... Сервис представляет из себя CGI-программу launch в виде ELF-бинарника. На вход принимает GET-параметры:
action - запрошенное действие, мини-программа на собственном языке в каталоге ./actions
arg - дополнительный параметр для определенных action'ов
in, out - имена входных и выходных файлов.

Флаги хранит в каталоге ./data в виде гистограмм-битмапов.

Соответственно, на каждый запрос подгружается нужная подпрограмма, и интерпретируется-выполняется.
Из полезных подпрограмм set (установить флаг - сгенерировать картинку по флагу), get (получить флаг-картинку), hint (типа подсказка).

Виртуальная машина представляет из себя 16-ти битный процессор с обычными командами типа MOV, PUSH, POP, CALL, RETN,... и необычными - печать значения переменной в консоль, читать / писать символ в файловый поток, system и т.д., всего 28 команд. Каждая команда - байт опкода + 1, 2 или 3 16-ти битных операнда. Зная это, несложно написать простой дизассемблер :)

Изучив подпрограмму get, можно узнать, что если запросить файл, состоящий из 111 и более букв o, можно выполнять произвольные команды, например, так:
launch?action=get&in=myfile&arg=echo 'Content-Type:text/plain\r\n';ls

Изучив hint, можно сделать
launch?action=hint&arg=3255
и получить подсказку в виде

struct registers{unsigned short ip;unsigned short sp;unsigned short bp;} reg;

enum opcodes{SET=0x0,MOV=0x1,ADD=0x2,SUB=0x3,MUL=0x4,
JMP=0x5,JE=0x6,JA=0x7,JB=0x8,CALL=0x9,RET=0xa,DIV=0xb,READ=0x10,WRITE=0x11,
PRINT=0x12,EXEC=0x13,PUSH=0x20,POP=0x21,ENTER=0x22,LEAVE=0x23,GETBP=0x24,PTR=0x25,MOVPTR=0x26,
END=0x30,DUMP=0x40,CONTTYPE=0x41,SHOWSHORT=0x42,GETSHORT=0x43};

Не знаю, как она поможет на этом этапе, когда дизассемблер уже написан.

Осталось 2 вопроса: как туда залить этот файл с oooo, чтобы потом получать список файлов-картинок, и как затем распознавать эти картинки. Вероятно, надо ковырять подпрограмму set. Собственно, проблема с картинками и заставила отступиться от сервиса во время игры.

Дизассемблер, launch, подпрограммы прилагаются.

UPD: Подпрограмма echo позволяет также создавать файлы, если указан параметр out. Таким образом, создать файл с ooo...ooo можно так:
launch?action=echo&out=myfile&arg=oooooo...ooo

UPD2: Генерация картинок, подпрограмма set.
0. Вывод заголовков битмапа в файл и stdout.
1. Вычисляется сумма по символам флага: Sum = flag[i] * (i + 1) mod 256, i =0,31
2. Флаг кодируется с учетом вычисленного значения Sum и таблицы, находящейся по смещению 0x04B3 в set:
index = (flag[i] + Sum) mod 256
flag[i] = table[index]
3. Формирование битмап-картинки.
Картинка представляет из себя изображение размера 500 x 300. По краям гистограммы белые поля, сама гистограмма расположена по x от 26 (0x1A) до 474 (0x1DA) и по y от 22 (0x16) до 278 (0x116).
Заполнение битмапа представляет собой два вложенных цикла по высоте и ширине картинки:
for (i = 0; i < 300; i++)
for (j =0; j < 500; j++)
draw(i,j)

Пиксели, координаты которых не попадают в границы гистограммы, выводятся белым. Оси гистограммы выводятся черным. Если же пиксель не попадает ни на оси, ни на поля, производится вычисление высоты рисуемого столбца гистограммы:
index2 = (j - 26 - 1) / 14
Так как значения j у нас в промежутке от 27 до 474, то index2 принимает значение от 0 до 31, как раз по длине флага.
Далее, вычисляется собственно высота: 278 - flag[index2]. Если полученное значение больше i (текущей отрисовываемой высоты битмапа), то заливаем белым, если равна - рисуем черную окантовку, и рисуем зеленым, если меньше.

Как высчитывать по картинке флаг. Определяем высоту столбца, вычитаем из 278. Получаем значение flag[index2]. Затем находим в таблице table это значение и запоминаем индекс index. Получаем 32 сравнения index = (flag[i] + Sum) mod 256 с двумя неизвестными flag[i] и Sum. Но для так как flag[31] = '=', вычисляем Sum и запросто решаем остальные уравнения.

Сервис сдался. Это было достаточно жестко.

UPD3: PoC - декодер картинок:
test-img : ABCDEFGHIJABCDEFGHIJABCDEFGHIJ1=
0087-4icm-7v79 : VIWW0KCUTYLFJ9TTQH05S0JX7V19WOJ=
Но почему-то не берет encrypted_src/default.

No TrackBacks

TrackBack URL: http://smokedchicken.org/m/mt-tb.cgi/29

3 Comments

Любопытно узнать какое решение предложит автор данного сервиса.

Жгете!!

Если интересно, то вот чекер к этому сервису - http://dl.dropbox.com/u/7603377/histobar.checker.pl - там можно поглядеть алгоритм проверки.

После квалификации defcon'а и 4-ёх часов реверса бинари-400 я понял что реверсить виртуальную машину трудно(правда там была виртуальная машина, исполняющая джавовский байткод). Очень помогает логировать команду и её параметры, привязывая скрипт дебагера к брейкпойнту, установленному на точку запуска очередной команды виртуальной машины.

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

Несмотря на то, что система команд машины была сделана максимально простой, сервис получился довольно сложным, как выяснилось.

About this Entry

This page contains a single entry by Павел Збицкий published on April 29, 2010 12:23 AM.

RuCTF-2010: SVN was the previous entry in this blog.

DC18: bin200 & bin300 is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.