Новости RuCTF Quals. Reversing. Разбор.

blackzert
, 5 марта 2009

Наверное, уже традиция со стороны организаторов CTF делать задания на восстановление логики работы программы по бинарику - ревёрсинг. Будь то либо образ, в котором один из сервисов "потерял" свои исходники, либо же набор квестов - реверсингу место всегда найдется. Так и организаторы RuCTF не обошли стороный эту область и подготовили непростые последовательности байтов ( вспомнить например stegano300 ;))

reversing100

Тут нам приготовили простенький бинарник под Win32. Смысл программы - запрос у пользователя пароля в виде небольшого окошечка, и, в случае если он был не верен - выход без всяких сообщений. Критерием правильности пароля служила хэш функция. Хэш брался от строки и результат сравнивался со значением 0xBB, и если равно - то строка верна и за неё можно получить 100 очков.

Вот логика хэша в синтексе языка C (он понятнее массам):

char hash(char* str){
    char al=0xff;
    for(int i=0;str[i];++i){
        al^=str[i];
        for(int j=0;j<8;++j){
            if (al&0x80){
                al<<=1;
                al^=0x31;
            }
            else {
                al<<=1;
            }
        }
    }
    return al;
}

Имея эту функцию и исходя из рассуждений, что значений у хэша всего 256, приходим к выводу, что атака грубой силой приведёт нас к успеху. Честно говоря, она к нему и привела.

Хотелось бы также отметить следующие рассуждения - число 0x80 предстявляет собой просто выставленный старший бит в 1 в байте. al&0x80 - означает проверку на то, выставлен ли этот бит или нет. Далее по аглоритму всегда делается сдвиг влево на 1, в результате чего мы теряем старший бит и получаем ноль в самом младшем. Если выставлен был старший бит, то al складывается по модулю 2 с 0x31 - получается, что устанавливается младший бит, если был выставлен старший. Таким образом мы точно можем вычислить какое значение было до сравнения... Ну, вот такие вот свойства у этого хэша.

reversing200

Не смотря на то, что мы так и не смогли до конца выполнить это задания, что-то мы всё таки сделали.

Предложена была динамическая библиотека dll и некотрое 16-ричное значение, именованное ключом. Длинна значения - 8байт, то есть 2 двойных слова. Открыв библиотеку в IDA Pro, мы начали анализировать всё в ней происходящее. Первым упала на взор таблица экспорта - экспортировались всего 2 функции - DllMain и DllEntryPoint. Собственно эти функции стандартны для dll, поэтом изучать их особого смысла не было - они лишь для инициализации. Стали смотреть метки в библиотеке. Их там было через чур. После просмотра графа, построенного идой, и анализа XREF'ов, выяснилось, что есть неименованные участки кода, вызывающие некие метки с непонятными аргументами. Эти участки кода и стали анализировать. Поняли что функции работают с учатками памяти, на которые указывают аргументы. Аргументами же функций "входа" (неименованная область кода, их было 2) являлись 3 значения - содержимое ecx,edx и один аргумент в стеке. А ключ мы имели из 2-х байт.. Теорию о том, чтобы положить значения ecx и edx данными значениями, а в стек кинуть ноль, так и не решили проверить - показалось не очень позитивным...

Также, попытки загрузить библиотеку через LoadLibrary не увенчивались успехом изза функции DllMain - она возвращала 0 вместо 1. правка одного байта программы дала возможность подгрузить библиотеку. Далее call на те функции.. но духу так и не хватило... 2 дня унесены вникуда...

reversing300

Задание: восстановить алгоритм работы программы.

С виду обычный PE, однако под дебагером выглядел уже не так обычно. Опкоды были просто не опкоды, а просто последовательность байт. Плюс ко всему 64битная архитектура. И винда упорно говорила что это не Win32 приложение (32 ж ничуть не 64 )) ). Проблестнула подсказка, что может это всётки x86? Я сел читать маны по PE заголовку. Выяснил, что если код и 32 битный, то соответсвенно надо выставить в заголовке 2 байта ( было не x86 а IA64). Далее магическое значение (подробнее - в заголовке оно называется magic) стояло в PE32+ что позваляло адресовать 64 битами память. Поставил PE32, чтобы согласовать с x86. Соответсвенно изза этого значения изменились и адреса позиционирования данных стека, кода, образа и прочие - они стали интерпертироваться не как 8 байтные а как 4 байтные. Естественно и байты сместились.. Всеравно ничего это не дало - одни db вместо нормальных команд. Была версия, что еще и адреса смещены и их расставить нужно. Или же код самомодифицируемый был и начало выполнения надо ставить на другой сегмент вообще... в общем рад познанию PE заголовка. Инетересен ответ к этому заданию. +)

Вот вроде бы и всё. Задание на 200 отняло кучу времени и не дало времени успеть чуточку дописать шелл для ctb400. абыдно... Спасибо, HackerDom +)) Респекты за игру!