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.