Песочница →
Исследуем защиту на основе сертификатов (utm5)
Эта статья не повествует о том как сделать кряк или кейген. Здесь будет простое исследование защиты достаточно дорогого программного продукта.
Так сложилось, что выбор пал на utm5.
Целью являлось понять какой метод защиты использует данный программный продукт, тем более что этот комплекс программ есть как под windows так и под linux/freebsd.
Я взял unix версию, т. к. это был первый опыт исследования программ не под windows.
А пользоваться мы будем всё той же IDA, запущенной из под wine.
Допустим что utm5 у нас загружен, имеется демо-ключ, всё настроено и работает. Ну что же, приступим:
Берем ядро системы(utm5_core) и скармливаем его IDA. Попьем чаёк и вернемся к компу, где IDA радостно сообщит что полностью проанализировала файл.
Смотрим файл reg.sql, и приходим к выводу что лицензию ядро системы считывает из mysql.
Внимательно посмотрев на данные, решаем что нас интересуют поля «hash1, hash2, data».
Делаем поиск строчки hash1 в strings, находим:
Отлично, это запрос в БД, так что идем туда, где используется эта строка, т. е. в UTM::DBAccess::get_license_info (такие названия есть только в unix-версии, в windows-версии таких удобств нету, только абстрактные названия функций)
Покрутившись туда-сюда в UTM::DBAccess::get_license_info, видим что тут считываются данные из таблицы, и в конце возвращаются либо что всё хорошо, либо что всё плохо:
Поэтому идем на уровень выше, в main+ABC:
И натыкаемся на очень интересную вещь — «CirtificationCenterImpl»:
В UTM::CertificationCenterImpl::instance(void) нет ничего интересного, поэтому войдем в UTM::CertificationCenterImpl::init и посмотрим, что может быть интересного внутри:
Мы видим "_d2i_X509" и "_X509_get_pubkey". Быстрый поиск приводит нас к тому, что это функции нужны для работы с X.509.
А теперь обратим внимание, какие данные попадают в _d2i_X509.
Как раз чуть выше мы видим две функции — «UTM::HiddenData::get_data(void)» и «UTM::HiddenData::size(void)»
Открываем UTM::HiddenData::get_data(void):
Хорошо видно что разработчики не захотели просто так «положить» данные в исполняемый файл, а сделали это с помощью множества mov'ов.
Вторая функция просто возвращает размер этих данных:
Поставим брейкпоинт в GDB на это место:
После останова на этом месте можно сдампить 0x49B символов из памяти по адресу, который находится в eax.
Просматриваем либо через gcr-viewer, либо через консольный openssl x509 и видим:
Хорошо, у нас есть какой-то сертификат, теперь пойдем дальше и изучим то, что происходит дальше:
Дальше программа получает открытый ключ из этого сертификата, и передает это всё в "_ZN3UTM23CertificationCenterImpl23CertificateFromKeyStoreEi", а ниже видно что уже идет сообщение об ошибке, значит проверка находится здесь, заходим в эту функцию и листаем, натыкаемся на:
Теперь мы можем прийти к мысли что в mysql, в поле data лежит ещё один сертификат в формате pkcs12.
Извлекаем эти данные из файла reg.sql, переводим в бинарный формат, т.к. это ascii-hex запись.
Сохранив данные, допустим в файл «key», воспользуемся командой, чтобы извлечь множество сертификатов:
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 года, но надо ли?
Так сложилось, что выбор пал на utm5.
Целью являлось понять какой метод защиты использует данный программный продукт, тем более что этот комплекс программ есть как под windows так и под linux/freebsd.
Я взял unix версию, т. к. это был первый опыт исследования программ не под windows.
А пользоваться мы будем всё той же IDA, запущенной из под wine.
Допустим что utm5 у нас загружен, имеется демо-ключ, всё настроено и работает. Ну что же, приступим:
Берем ядро системы(utm5_core) и скармливаем его IDA. Попьем чаёк и вернемся к компу, где IDA радостно сообщит что полностью проанализировала файл.
Смотрим файл reg.sql, и приходим к выводу что лицензию ядро системы считывает из mysql.
Внимательно посмотрев на данные, решаем что нас интересуют поля «hash1, hash2, data».
Делаем поиск строчки hash1 в strings, находим:
Отлично, это запрос в БД, так что идем туда, где используется эта строка, т. е. в UTM::DBAccess::get_license_info (такие названия есть только в unix-версии, в windows-версии таких удобств нету, только абстрактные названия функций)
Покрутившись туда-сюда в UTM::DBAccess::get_license_info, видим что тут считываются данные из таблицы, и в конце возвращаются либо что всё хорошо, либо что всё плохо:
Поэтому идем на уровень выше, в main+ABC:
И натыкаемся на очень интересную вещь — «CirtificationCenterImpl»:
В UTM::CertificationCenterImpl::instance(void) нет ничего интересного, поэтому войдем в UTM::CertificationCenterImpl::init и посмотрим, что может быть интересного внутри:
Мы видим "_d2i_X509" и "_X509_get_pubkey". Быстрый поиск приводит нас к тому, что это функции нужны для работы с X.509.
А теперь обратим внимание, какие данные попадают в _d2i_X509.
Как раз чуть выше мы видим две функции — «UTM::HiddenData::get_data(void)» и «UTM::HiddenData::size(void)»
Открываем UTM::HiddenData::get_data(void):
Хорошо видно что разработчики не захотели просто так «положить» данные в исполняемый файл, а сделали это с помощью множества mov'ов.
Вторая функция просто возвращает размер этих данных:
Поставим брейкпоинт в GDB на это место:
После останова на этом месте можно сдампить 0x49B символов из памяти по адресу, который находится в eax.
Просматриваем либо через gcr-viewer, либо через консольный openssl x509 и видим:
Хорошо, у нас есть какой-то сертификат, теперь пойдем дальше и изучим то, что происходит дальше:
Дальше программа получает открытый ключ из этого сертификата, и передает это всё в "_ZN3UTM23CertificationCenterImpl23CertificateFromKeyStoreEi", а ниже видно что уже идет сообщение об ошибке, значит проверка находится здесь, заходим в эту функцию и листаем, натыкаемся на:
Теперь мы можем прийти к мысли что в 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 года, но надо ли?
19.01.2012 07:09+0400