Яндекс.Метрика

    Песочница

    Исследуем защиту на основе сертификатов (utm5)

    Эта статья не повествует о том как сделать кряк или кейген. Здесь будет простое исследование защиты достаточно дорогого программного продукта.

    Так сложилось, что выбор пал на utm5.
    Целью являлось понять какой метод защиты использует данный программный продукт, тем более что этот комплекс программ есть как под windows так и под linux/freebsd.
    Я взял unix версию, т. к. это был первый опыт исследования программ не под windows.
    А пользоваться мы будем всё той же IDA, запущенной из под wine.

    Допустим что utm5 у нас загружен, имеется демо-ключ, всё настроено и работает. Ну что же, приступим:

    Берем ядро системы(utm5_core) и скармливаем его IDA. Попьем чаёк и вернемся к компу, где IDA радостно сообщит что полностью проанализировала файл.

    Смотрим файл reg.sql, и приходим к выводу что лицензию ядро системы считывает из mysql.
    Внимательно посмотрев на данные, решаем что нас интересуют поля «hash1, hash2, data».

    Делаем поиск строчки hash1 в strings, находим:
    image

    Отлично, это запрос в БД, так что идем туда, где используется эта строка, т. е. в UTM::DBAccess::get_license_info (такие названия есть только в unix-версии, в windows-версии таких удобств нету, только абстрактные названия функций)

    Покрутившись туда-сюда в UTM::DBAccess::get_license_info, видим что тут считываются данные из таблицы, и в конце возвращаются либо что всё хорошо, либо что всё плохо:

    image

    Поэтому идем на уровень выше, в main+ABC:

    image

    И натыкаемся на очень интересную вещь — «CirtificationCenterImpl»:

    image

    В UTM::CertificationCenterImpl::instance(void) нет ничего интересного, поэтому войдем в UTM::CertificationCenterImpl::init и посмотрим, что может быть интересного внутри:

    image

    Мы видим "_d2i_X509" и "_X509_get_pubkey". Быстрый поиск приводит нас к тому, что это функции нужны для работы с X.509.

    А теперь обратим внимание, какие данные попадают в _d2i_X509.

    Как раз чуть выше мы видим две функции — «UTM::HiddenData::get_data(void)» и «UTM::HiddenData::size(void)»

    Открываем UTM::HiddenData::get_data(void):
    image

    Хорошо видно что разработчики не захотели просто так «положить» данные в исполняемый файл, а сделали это с помощью множества mov'ов.

    Вторая функция просто возвращает размер этих данных:
    image

    Поставим брейкпоинт в GDB на это место:
    image

    После останова на этом месте можно сдампить 0x49B символов из памяти по адресу, который находится в eax.

    Просматриваем либо через gcr-viewer, либо через консольный openssl x509 и видим:
    image

    Хорошо, у нас есть какой-то сертификат, теперь пойдем дальше и изучим то, что происходит дальше:
    image

    Дальше программа получает открытый ключ из этого сертификата, и передает это всё в "_ZN3UTM23CertificationCenterImpl23CertificateFromKeyStoreEi", а ниже видно что уже идет сообщение об ошибке, значит проверка находится здесь, заходим в эту функцию и листаем, натыкаемся на:
    image

    Теперь мы можем прийти к мысли что в mysql, в поле data лежит ещё один сертификат в формате pkcs12.

    Извлекаем эти данные из файла reg.sql, переводим в бинарный формат, т.к. это ascii-hex запись.

    Сохранив данные, допустим в файл «key», воспользуемся командой, чтобы извлечь множество сертификатов:
    openssl pkcs12 -in key -out key.pem

    Openssl спросит у нас пароль. Подсунем ей пароль, который шел вместе с ключом в reg.sql, т.к. ничего подобного и явного в листинге asm'а мы не видели.

    Введя несколько раз пароли мы получаем key.pem.

    Берем всё тот же gcr-viewer, просматриваем этот key.pem и видим:

    utm5_core
    Подлинность: utm5_core
    Проверен: UTM5 SUB CA
    Истекает: 03.01.2012

    utm5_dealer
    Подлинность: utm5_dealer
    Проверен: UTM5 SUB CA
    Истекает: 03.01.2012

    utm5_dynashape
    Подлинность: utm5_dynashape
    Проверен: UTM5 SUB CA
    Истекает: 03.01.2012

    utm5_hotspot
    Подлинность: utm5_hotspot
    Проверен: UTM5 SUB CA
    Истекает: 03.01.2012

    utm5_radius
    Подлинность: utm5_radius
    Проверен: UTM5 SUB CA
    Истекает: 03.01.2012

    utm5_tel
    Подлинность: utm5_tel
    Проверен: UTM5 SUB CA
    Истекает: 03.01.2012

    Ключ
    Секретный ключ RSA
    Надёжность: 1024 бита


    Почитав «Практическое руководство по созданию центра сертификации», становится понятно что лицензия на utm5 сделана с помощью сертификатов, и мы имеем сертификаты лицензий + выдернули из программы сертификат для проверки подлинности сертификатов лицензии.

    Если же выделить каждый сертификат из файла key.pem в отдельный файл, то можно через ту же консольную утилиту «openssl x509» просмотреть дополнительные поля, в которых как раз указаны ограничения тех или иных модулей.

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

    Хотя, на самом деле защита имеет очень большую уязвимость далее, когда считываются как раз те самые ограничения — они передаются в программу в виде обычных строк, которые легко подменить, либо на очень большие значения, либо вообще на «-1».

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

    Но более элегантным методом будет создание своих собственных сертификатов, с необходимыми нам значениями. Программа же сможет их принять, т. к. мы просто возьмем и впихнем свой проверочный сертификат в программу, заменив код функций «UTM::HiddenData::get_data(void)» и «UTM::HiddenData::size(void)» на свой, и utm5 будет работать хоть до 2050 года, но надо ли?