Новости RuCTFe .::. Simple .::.

blackzert
, 13 ноября 2009

Итак, собрались. Собрались в 8 местного в 203 аудитории. Потихоньку, помаленьку, набралась целая аудитория. Пришлось даже принести лишний стол и расположить его в коридоре. Вместе с некоторой частью медведей, вай-фай точкой и ноутбуками.

Спустя два часа болтовни и подготовок... Организаторы отложили игру на час и был еще один час болтовни и подготовок. =)

Начало. Расшифровываем, включаем.. и.. Чертовщина какая-то - "Что тут делает android sdk?" (c) Alebastr. "Запустите xinit, там андроид" (c) knst. "Ох ты, а они еще один сервис выкинули, ссылка в мирке." (c) Progressor. Именно последняя цитата имела значение на следующие часы для меня. Так как php не предвиделось на образе КПК, я взялся за реверсинг.

Итак, в архиве был бинарик и Makefile, повествующий об установке сервиса. Бинарик в IDA Pro, и, о Боже, это ARM. Google подсказывает доку. Два-Три часа изучения, и.. я знаю немного об этой архитектуре :) Итак, еще час, и мы восстановили всю логику сервиса, еще один.. и.. чтото еще мы поняли. :) У людей он был в дауне, а по рассылке написали, что надо перенаправить порты с виртуального устройства на реальную ось, через час другой после начала игры. Видать не все читали, и напоминать им через irc не хотелось - мы еще не нашли как таскать флаги..

Итак, что же делал сервис? открывал порт, ждал коннекта, спускал новую нить на каждое принятое соединение, и обрабатывал. От клиента считывались 52 байта и ни больше ни меньше. Если меньше - соединение было разорвано, и можно не обрабатывать клиента. Итак, далее было следующее - 52 байта разбивались на 13 четырех байтовых групп, каждая из которых заменялись согласно некоторой функции f. То есть,

long* x=client_info; for (int i=0;i<13;i++) x[i]=f(x[i]);

Первая группа означала команду - сохранить или вернуть флаг. Итак, если они равнялись 0xcafebabe, то это означало сохранить флаг с идентификатором, равным следущим 4 группам, а флаг - последним 8. Хранились они в секции .bss. Были две глобальные переменных - указатель на таблицу - void* table и int count. Каждый флаг с идентификатором ложился по адресу table + 58*count, count=(count+1)%128. Как мы можем понять, сервис в состоянии хранить всего 128 флагов, причем он даже не смотрит на идентификаторы, просто складывает флаг за флагом. Итак, то, что мы делали в конце игры, и что принесло нам 100% по защите - каждую минуту или около того, складывали по 128 флагов в сервисы 5-ти команд - Siths, squareroots, ENOFLAGS, 0ldEur0pe и еще кто-то :) у них были корапты, у нас апы. Кстати ENOFLAGS в конце игры не смогли из-за этого навариться на этом сервисе. Очевидно, что его надо было переписать и увеличить число хранимых флагов. Причём я даже не вижу смысла использовать андроид для этого ;)

Далее, если первые 4 байта == 0xbabecafe, остальные 16 байт идентификатор, флаг по которому надо вернуть. Сервис начинает "ходить" по памяти и проверять по 16 байт функцией memcmp, чтобы найти идентификатор. Если он его не находит, возвращает самый первый флаг в таблице. Это надо было пофиксить как минимум сменой одного байта :) Если находит, возвращает флаг. Но. Как он возвращает. Все, что он возвращает, он меняет функцией g. топишь long* x=client_info; for (int i=0;i<13;i++) x[i]=g(x[i]);

причом g!=f^(-1). а жаль.

Ну и наконец, еще одна дырка в сервисе. Если первая группа равна 0xbabebabe, то сервис возвращает все идентификаторы, которые есть в данный момент, только пройдясь по нима функцией g.. Итак, надо обратить f, чтобы знать, что отправлять. Надо обратить g, чтобы прочитать, чтоже нам написал сервис... Или можно обратить f*g. Тогда получим исходное значение , подействовав f, найдем g^-1.

В общем обратить не смогли, поэтому всего 80 баллов за адвизори, вот и все что поимели мы с него... ну и конечно 100% по защите :)

Вот так прошла для меня эта ночь.. И я все голову ломаю - как же обратить их.... =)

Итак, вот как выглядели функции, описанные выше:

unsigned long f(unsigned long r0){
unsigned long r1,r2,r3;
r1=r0>>16;
r2=r1-0x399a;
r2^=r0;
r2<<=16;
r2>>=16; // r2&=0xffff;
r3=r2-0x459a;
r1=r1^r3;
r1<<=16;
r1>>=16;
r0=r1+0x70fb;
r0^=r2;
r0<<=16;
r0>>=16;
r3=r0-0x2520;
r3^=r1;
r0|=(r3<<16);
return r0;
}
unsigned long g(unsigned long r0){
unsigned long r1,r2,r3,r12;
r3=0xb896;
r1=r0>>16;
r12=r1*r3;
r12^=r0;
r12<<=16;
r3=r12>>16;
r2=r3<<13;
r2=r2-(r3<<2);
r2=r2-r3;
r2=r2<<3;
r2=r2+r3;
r2=r2^r1;
r2<<=16;
r3=r2>>16;
r0=r3<<9;
r0=r0-(r3<<7);
r0=r0-r3;
r1=r0<<4;
r0+=r1;
r0^=(r12>>16);
r1=0x4520;
r0<<=16;
r0>>=16;
r3=r0*r1;
r3^=r2>>16;
r0|=r3<<16;
return r0;
}