Этот неживой и баснословный мир
Все начиналось хорошо, ничто не предвещало беды. В один поздний вечер мне один хороший знакомый попросил об одной услуге выражаясь фразами типа «ну ты ж у нас программист». Писал он о просьбе взломать некое приложение. На что я ответил, что постараюсь, но о удачном взломе не гарантирую. На следующий день мы встретились, он мне дал диск и объяснил, что это за приложение.
Начало
Есть некая организация, которая занимается обучением людей для сдачи одного определенного экзамена. Чтобы получить это приложение надо пойти в эту организацию, записаться и оплатить курсы. В конце пройденного курса организация за дополнительную плату дает диск с установщиком программы с индивидуальным ключом активации. Приложение позволяет делать тесты, смотреть на результаты. Есть некий режим «На экзамене», который позволяет имитировать среду экзамена. Приложение выдает случайные тесты из разных разделов. Все хорошо и прекрасно.
Первые шаги — экспериментируем
Устанавливаем приложение запускаем его, чтобы посмотреть, что оно из себя представляет.
Открывается такой сплэш экран, и приложение на несколько секунд зависает (данное зависание не спроста).
Открывается сплэш экран, а за ним, через несколько секунд открывается такое окошко:
От нас требуется ввести ключ активации, которого у нас естественно нет. Первое что меня насторожило, это то, что окно ввода ключа активации открывается с ощутимой задержкой, как будто приложение подключается куда-то через интернет и разработчик приложения не позаботился об асинхронном подключении к интернету. Чтобы удостовериться в том, что приложение лезет в интернет отключил сетевые подключения на компьютере
Отсюда делаем вывод, что приложение активируется через интернет и в ее исходниках не зашиты какие-либо ключи активации или алгоритмы расшифровки.
Лезу в папку уставленной программы:
Структура:
- Arial Narrow.ttf – шрифт
Кеп - DataSource.data – файл БД в котором все тесты
- *************.exe – екзешник приложения
- MySql.Data.dll – бесплатная opensource библиотека от MySql
Наличие библиотек MySql.Data.dll в папке с программой навела на мысль о том, что приложение скорее всего написано на языке C#. Ни для кого не секрет то, что не защищенные специальными утилитами приложения написанные на этом языке программирования легче всего поддаются декомпиляции. Обрадованный данным предположением, мой мозг автоматически дал мне сигнал запустить программу IlSpy, которая позволяет декомпилировать приложения написанные на C# и открыть приложение в нем.
В итоге передо мной открылась такая картина
Как видно приложение действительно написано на C#, отображается информация о разработчике, используемой версии .NET. После открытия структуры приложения последовало разочарование.
Судя по непонятным знакам, пустым функциям, приложение обфусцировано — код нечитаемый. За помощью я обратился к поисковикам и вскорее нашел бесплатную опенсоурс программу de4dot, которая позволяет деобфусцировать обфусцированные приложения написанные на C#.
Попробуем деобфусцировать и получаем такой результат:
Судя по сообщению приложение обфусцировано с помощью .NET Reactor, и декомпилировать его не представляется возможным. После долгих поисков метода деобфускации от защиты .Net Reactor найти так и не удалось.
Тогда я, решил попробовать хотя бы открыть файл базы данных DataSource.data, в SQLite.
От нас требуется пароль от базы данных.
Разочарованный неудачей я уже сдавался, взлом я оставил на потом на лучшие времена. Но из головы никак не уходила мысль о том, что я что-то пропустил.
Уважаемый вы здоровы?
Иногда шаг вперед является результатом пинка в зад
Прошло какое-то время. Когда я копался в файлах нашел эту программу и обратил внимание на файл MySql.Data.dll. А что если поменять MySql.Data.dll на модифицированный, чтобы он отображал строку подключения к бд. Для этих целей есть opensource программа — dnSpy. Она позволяет редактировать код .net приложений и библиотек. Загружаем dll файл в программе и находим класс MySqlConnection и редактируем функцию .ctor:
Добавим строку:
System.Windows.Forms.MessageBox.Show(connectionString);
Нажимаем «Compile», сохраняем файл, заменяем с оригинальным и наконец запускаем приложение.
Выйдет такое окно:
По названию сервера cloudapp.net можно сделать вывод, что база данных создана на Azure.
Скачиваем любую бесплатную утилиту подключения к бд, скажем HeidiSQL. После ввода полученных данных подключения открылась БД. А вот и наши ключи активации:
У большинства ключей отсутствовали значения полей Name, CardId, Phone. Видимо эти ключи еще не продали. Добавил из себя 16 значный ключ, и зарегистрировал программу. В папке с установленной программой появился файл data.dat и приложение выдало сообщение об успешной регистрации. В таблице с ключами пропал созданный ранее ключ. После недолгих поисков этот ключ я нашел в таблице logs. Там был мой ключ с подробным описанием характеристик моего компьютера таких как модель, процессор, видеокарта и т.д. Эту строку я удалил, чтобы не оставить после себя следов.
Итог
Стоит отдать должное разработчику приложения, он позаботился о защите своего приложения. Он защитил БД, обфусцировал приложение, содержание data.dat файла тоже зашифровано, но о проверке хеша используемой библиотеки он позабыл.
P.S.: Вред организации, взлом приложения не произвел. К тому времени, пока удалось взломать приложение, другу оно уже не было надобным. Активированная копия приложения была только у меня и третьим лицам передано не было. В связи с ненадобностью приложения у себя я тоже её удалил.
Комментарии (46)
vshmidt
29.01.2018 09:34Забавно, давно у Рихтера кажись было написано пару строк по поводу секурности дот нет не на серверах. Так вот секурности предполагалась за счёт недопущения получения сборок. То есть если ты влез на сервер но уже ничего не поможет. В связи с этим вопрос, строгие имена не гарантируют безопасность в случае со статьей. Мне на ум приходит только компиляция приложения в нативный код на клиентской машине и уже в таком виде проверять целостность и ТД. Какие ещё есть способы защиты?
molnij
29.01.2018 10:43В связи с этим вопрос, строгие имена не гарантируют безопасность в случае со статьей.
Если это вопрос — то нет, не гарантируют, если ваша цель именно сломать приложение. Просто цепочка слегка удлиняется — потребуется перелопатить все сборки через dnSpy.
Способы защиты, если уж мы считаем нормой лезть за активацией в сеть — просто чуть разумнее, чем в этом примере. Например идёте с ключём в сервис активации, он вам возвращает пароль к локальной базе. Непонятно зачем это делать напрямую конектом к базе, причем с такими роскошными правами. Если уж не хотелось заводить какой-то отдельный сервис — можно было права учётке ограничить на какую-нибудь хранимку которая вернула бы нужны данные.
dartraiden
29.01.2018 09:44В интернете гуляет и мод de4dot с поддержкой .NET Reactor 5.0. Возможно, имело смысл попробовать.
Gradarius
29.01.2018 10:45Спасибо, достаточно интересная статья.
Мне кажется тут плохая защита удаленной БД.
Во-первых не было смысла давать прямой доступ к БД, проще было разместить простое веб-приложение.
Во-вторых можно было ограничить права пользователя, только на одну конкретную операцию, а именно на проверку наличия ключа. К этому так же ограничит кол-во запросов в секунду.
Хотя о чем тут можно говорить, если весь тест расположен в локальной базе.
martin_wanderer
29.01.2018 10:47А ведь могло не оказаться прав на таблицу аудита…
AkshinM Автор
29.01.2018 10:58учитывая то, что приложение лезет в БД, и само же приложение там делает изменения (добавление логов активации в бд к примеру), то об ограниченных правах тут даже речи не может быть. там была таблица users, в которой были логины и хеши паролей. видимо есть админка управления. все храниться в этой бд и видимо пользователь один с максимальными правами)
staticlab
29.01.2018 12:00Вполне могли быть отдельные права на таблицы. Другое дело, что даже R/O-доступ к таблице пользователей — весьма серьёзная дыра в безопасности.
berezuev
29.01.2018 11:22+1Ну, тут даже взломом сложно назвать… Разрабы сами положили на клиент логин и пароль от базы данных. Такие косяки даже джунам в 2018-м не позволительны.
Эх… Наберут по объявлению…nikitasius
29.01.2018 12:24Именно. Можно было просто найти в коде вызовы к базе и выдернуть оттуда данные для подключения.
Обфускация обсускацией, а язык-то не меняется.
AkshinM Автор
29.01.2018 13:21Обфускация обсускацией, а язык-то не меняется
язык то не меняется, но код абсолютно не читаемый
unsafePtr
29.01.2018 12:44Подскажите, а как быть если нужно подключаться к удаленной базе? Ограничить в правах подключаемого пользователя? Я джун, не кидайте камнями.
justmara
29.01.2018 13:05+1Даже если подключаться к удалённой базе по логину/паролю, выдаваемому конкретному пользователю с адово-параноидально настроенными правами доступа… То всё равно будут дыры типа чтения чужих данных и тому подобное.
Так что ответ — никак. Делать поверх базы api и отдавать только его.
Использовать прямой коннект к базе из клиентского приложения можно разве что в доверенной среде. Например, в рамках локальной сети организации, когда авторизация в базе делается по AD-учётке текущего пользователя.
berezuev
29.01.2018 13:12Обязательно должен быть API между клиентом и базой.
Вообще, по хорошему, база должна быть доступна только под 127.0.0.1 (по дефолту так и есть), либо внутри сети приложения (если мы говорим про масштабирование), т.к. в СУБД тоже могут быть 0-day уязвимости.Csharper101
29.01.2018 13:19Под API, вы имеете в виду ORM?
berezuev
29.01.2018 13:27Под API я имею в виду API-сервер. Клиент должен отправлять запросы на сервер с авторизацией. Как реализовать сервер — дело каждого. Самое простое — HTTP с oAuth2.
А уже на сервере запросы к БД можно делать как угодно: ORM, голый SQL, да хоть через handlersocket…Csharper101
29.01.2018 13:32Веб-приложения также нужно реализовать?
berezuev
29.01.2018 13:40А какая разница, кто у вас клиент — веб-страница, десктопное/мобильное приложение или чайник Xiaomi?
Csharper101
29.01.2018 13:48Но у веб-приложений, реализованных на паттерне mvc, контроллер служит в качестве серверной части приложения, зачем ему что-то еще?
berezuev
29.01.2018 15:31Ну, во-первых, контроллер служит не «для серверной части приложения», а для направления данных от пользователя к системе и наоборот. Бизнес-логика, например, описывается в компонентах, а не в контроллерах.
Во-вторых, в современных веб-приложениях повсеместно отделяют фронтенд и бэкенд. И общаются они между собой по API-интерфейсу.Csharper101
29.01.2018 17:15Но они же в mvc итак отделены
michael_vostrikov
29.01.2018 18:19Какая нафиг разница?) Вы не должны давать в клиентском коде прямой доступ к базе данных. Точка.
Как вы будете это реализовывать, дело ваше.
Csharper101
29.01.2018 13:16Да просто засунуть строку подключения в webconfig/appconfig, оттуда их достать нельзя(как я знаю), другого выхода нет
MrDaedra
29.01.2018 13:49По умолчанию app.config превращается в appname.exe.config и легко редактируется
блокнотомчем угодно
darkdaskin
29.01.2018 14:42Шифрование строк подключения производится ключом пользователя ОС. Если перенести этот файл на другой компьютер, расшифровать его приложение уже не сможет. Это защита только от удалённого доступа к файлам на серверах, локальный админ может расшифровать конфиги так же, как и зашифровал.
martin_wanderer
29.01.2018 14:12Одно из возможных решений, если мы остаемся в двухзвенке — доступ к данным только через хранимые процедуры. Тогда такой взломщик, даже зайдя в базу, получит не больше данных, чем мог бы получить в приложении. Все процедуры и таблицы у другого пользователя, а у приложения — только права на выполнение процедур.
nikitasius
01.02.2018 01:32Если ну никак нельзя сделать АПИ, то можно просто плотить view по мастер таблице с аккаунтами и давать каждому клиенту доступ к view. Но далее — надо правильно настроить сервер, чтобы клиент не запускал n-n-n-n… запросы, отъедая по 100% от ядер.
Csharper101
29.01.2018 12:43А что бы ты делал, если данные в БД были зашифрованы, а ключ к расшифровке находится, где-нибудь на сервере(да, странно, но все все-таки)
namikiri
29.01.2018 13:24Материал весьма интересный, с удовольствием прочитал, порадовало как ларчик просто открывается. Но… Слишком много размазни на скринах. Неаккуратной, неопрятной размазни. Сплешскрин — зачем? Чтобы посмотреть на слова «Version» и «Copyright»? Замазать размер шрифта Arial — спешите видеть, раскрытие личности по размеру файла!
Для Хабра можно было и постараться.AkshinM Автор
29.01.2018 14:46Неаккуратной, неопрятной размазни
следующий раз учту. даже не обраил на это внимания
раскрытие личности по размеру файла!
в условиях страны, которой я живу за такие деяния можно схлопотать не мало лет. поэтому замазал даже размеры файла
dmitryredkin
29.01.2018 14:26А без декомпилятора слабо? Ну там как в старые времена: Запустить Иду, найти функцию проверки активации, пропатчить nop-ами и т.д.?
AkshinM Автор
29.01.2018 14:43к сожалению не разбираюсь в этой программе. хотелось бы научиться да вот руки все не доходят
iVladislaV
29.01.2018 14:53Сейчас бы .NET в иде патчить.
qw1
29.01.2018 17:33Как ни странно, я это делал, когда нужно было исправить ровно 1 байт, а не пересобирать всю DLL.
Декомпилировал сборку в dotPeek, разобрал логику, нашёл нужный переход. Нашёл соответствующее место в IL-коде. Однако, по какому смещению находится в файле нужный байтик, ни один инструмент, кроме IDA, мне не подсказал.
keenua
29.01.2018 15:45Не вижу смысла усложнять себе жизнь. Вот когда часть программы, к примеру шифрование, в нативной библиотеке лежит, тогда и IdaPro пригодится.
dartraiden
29.01.2018 16:15Для отладки .NET лучше использовать специализированный отладчик, допустим, ILSpector или dnSpy.
fareloz
30.01.2018 15:38Когда-то тоже пытался взломать программку на c#. Сначала пытался посмотреть алгоритм создания файла для trial лицензии чтобы самому создать файл и получить бесконечный период. Но там был какой-то хитрый алгоритм с ключами шифрования. Потом хотел просто поменять код чтобы лицензия была валидна при любых аргументах. Но программа тянула не локальные dll, а с GAC. В итоге сдался.
XopHeT
«декомпилировать его ну удается возможным.»
Вероятно имелось в виде «декомпилировать его не представляется возможным»
AkshinM Автор
спасибо, подправил)