Русский
Русский
English
Статистика
Реклама

Обфускация

Перевод Безопасность через неясность недооценивается

16.09.2020 02:22:50 | Автор: admin
В информационной безопасности мы выработали ряд аксиом, с которыми не принято спорить:

  • Никогда не внедряйте собственную криптографию.
  • Всегда используйте TLS.
  • Безопасность через неясность (security by obscurity) это плохо.

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

Риск, эшелонированная оборона и швейцарский сыр


Одной из главных задач ИБ является снижение рисков. Согласно методологии OWASP, риск возникновения проблемы рассчитывается по формуле:

Риск = Вероятность * Воздействие

По этой формуле, проблема удалённого выполнения кода (RCE) представляет больший риск, чем проблема межсайтового скриптинга, поскольку RCE несёт большее воздействие. Здесь всё просто. Но что насчёт метрики вероятности? Согласно OWASP, вероятность определяется так:

На самом высоком уровне это приблизительная оценка шансов, что конкретная уязвимость будет раскрыта и использована злоумышленником

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



Согласно этой модели, вам нужно выстроить защитные механизмы в многоуровневой модели таким образом, чтобы даже если злоумышленник пройдёт первый уровень, он будет остановлен на других.

Безопасность через неясность


Итак, поговорим о безопасности через неясность. Плохая идея использовать её в качестве единственного уровня защиты. Если злоумышленник пройдёт его, то вас больше ничто не защитит. Но на самом деле он неплох в качестве дополнительного уровня. Потому что у него низкая стоимость внедрения и обычно он хорошо работает.

Рассмотрим несколько сценариев:

  • На моём сервере SSH запускается на дефолтном порту 22, а учётные данные root:123456. Какова вероятность компрометации?

Вероятность почти 100%, так как хакеры по всему интернету брутят сервисы со стандартными учётными данными.

  • SSH работает на порту 22, а учётные данные utku:123456. Какова вероятность компрометации?

Ну, мы устранили опасность брутфорса со стандартными учётными данными. Вероятность и риск снижаются. Однако мы по-прежнему сталкиваемся с массой целевых атак. Кто-то может угадать имя пользователя utku, так как это моё настоящее имя.

  • SSH работает в порту 64323, а учетные данные utku:123456. Какова вероятность компрометации?

Мы изменили номер порта по умолчанию. Поможет ли это? Во-первых, мы снова устранили опасность стандартного брутфорса, поскольку он сканирует только общие порты. А как насчёт остальных? Я провёл небольшой опрос в своём твиттере, чтобы выяснить поведение людей при сканировании портов.


Как видите, многие склонны сканировать только стандартные и самые популярные порты. Таким образом, если вы измените порт с 22 на 64323, то устраните некоторые из потенциальных атак. Вы уменьшите вероятность и риск.

То же самое относится и к уязвимостям программного обеспечения. Если уязвимость обнаружена в протоколе Microsoft Remote Desktop Protocol, весь интернет начнёт сканировать порт 3389. Вы можете уменьшить риски, просто изменив порт по умолчанию.

Другие области применения


Конечно, кроме изменения значений по умолчанию можно использовать ту же методологию и в других областях. В некоторых случаях (не всегда) можно применить следующие идеи.

  • Обфускация кода: конечно, это общеизвестно. Хакеры тоже люди. Если вы хорошенько обфусцируете код, им придётся уделить больше времени на поиск проблем. В конце концов они могут сдаться.
  • Случайные имена переменных для веб-приложения: Вместо понятных имён переменных можно использовать случайные символы. Это может помочь точно так же, как обфускация кода.
  • Симметричное шифрование в базе данных: при записи данных в БД используйте функцию вроде encryption_algorithm(data, key). Аналогично, при считывании данных decryption_algorithm(data, key). Если злоумышленник получил доступ к внутреннему коду, то, очевидно, сможет расшифровать БД. Но если из-за какой-то уязвимости злоумышленник считывает данные из БД, но не видит внутренний код (например, через SQL-инъекцию), то полученные данные ничего ему не дадут.

Применение в реальной жизни


Безопасность через неясность широко используется в физической/реальной безопасности. Например, президент едет из пункта А в пункт Б с кортежем из 30-ти автомобилей. Но он не сидит в своей президентской машине, чтобы не стать лёгкой мишенью. Он может находиться в любой машине из кортежа, и это снижает риск нападения.



Животные также используют безопасность через неясность это камуфляж. Скрытность снижает вероятность быть убитым. Поэтому в процессе эволюции они приобрели такую способность.



Вывод


Безопасности через неясность самой по себе недостаточно. Всегда следует применять лучшие практики. Но если вы можете снизить риск с нулевыми затратами, то должны это сделать. Неясность это хороший слой в общей системе безопасности.
Подробнее..

Обфускация как метод защиты программного обеспечения

19.12.2020 20:12:49 | Автор: admin

Или то, почему вы не можете издать свою улучшенную версию Counter Strike и уехать жить на Гавайи.

О чём речь?

Обфускация (от английскогоobfuscate делать неочевидным, запутанным, сбивать с толку) в широком смысле - приведение исходного текста или исполняемого кода программы к виду, сохраняющему её функциональность, но затрудняющему анализ, понимание алгоритмов работы и модификацию при декомпиляции.

Красивый пример из Википедии кода, прошедшего обфускацию. Красивый пример из Википедии кода, прошедшего обфускацию.

Далее в программе

  • Зачем это нужно?

  • Как это должно работать?

  • Как это работает?

  • Методы

  • Состояние дел сейчас

Зачем это нужно?

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

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

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

Как это должно работать?

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

В идеале хотелось бы, чтобы программа, прошедшая обфускацию, давала бы не больше информации нежели чёрный ящик, имитирующий поведение исходной программы. Гипотетический алгоритм, реализующий такое преобразование называется "Обфускация чёрного ящика". Декомпиляция зашифрованной таким образом программы дала бы злоумышленникам не больше информации, чем декомпиляция клиента мессенджера, представляющего собой лишь обёртку над апи "настоящего" приложения, что бы полностью решило поставленную в предыдущем блоке проблему. Однако показано[3], что реализация такого алгоритма для произвольной программы невозможна.

Как это работает

Большинство методов обфускации преобразуют следующие аспектов кода:

Данные: делают элементы кода похожими на то, чем они не являются

Поток кода: выставляют исполняемую логику программы абсурдной или даже недетерминированной

Структура формата: применяют различное форматирование данных, переименование идентификаторов, удаление комментариев кода и т.д.

Инструменты обфускации могут работать как с source или байт кодом, так и с бинарным, однако обфускация двоичных файлов сложнее, и должна варьироваться в зависимости от архитектуры системы.

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

Методы

1. Преобразование данных

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

По ссылке можно ознакомится с интересными примерами использования двоичной формы записи чисел для усложнения читабельности кода, а так же изменений формы хранения данных и замены значений различными тождественными им выражениями.

2. Обфускация потока управления кодом

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

3. Обфускация адресов

Данный метод изменяет структура хранения данных, так чтобы усложнить их использование. Например алгоритм, может выбирать случайными адреса данных в памяти, а также относительные расстояния между различными элементами данных. Данный подход примечателен тем, что даже если злоумышленник и сможет "декодировать" данные, используемые приложением на каком-то конкретном устройстве, то на других устройствах он всё равно не сможет воспроизвести свой успех.

Подробнее об адресной обфускации можно прочесть тут.

4. Регулярное обновление кода

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

5. Обфускация инструкций ассемблера

Преобразование и изменение ассемблерного когда также может затруднить процесс обратного инжиниринга. Одним из таких методов является использование перекрывающихся инструкций (jump-in-a-middle), в результате чего дизассемблер может произвести неправильный вывод. Ассемблерный код также может быть усилен против проникновения за счёт включения бесполезных управляющих операторов и прочего мусорного кода.

6. Обфускация отладочной информации

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

Заключение

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

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

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

Ссылки и источники

[1] https://en.wikipedia.org/wiki/Obfuscation_(software)

[2] https://www.sciencedirect.com/science/article/pii/S1877050915032780

[3] Barak B., Goldreich O., Impagliazzo R., Rudich S., Sahai A., Vadhan S. and Yang K. On the (im) possibility of obfuscating programs. CRYPTO 2001.

[4] https://www.researchgate.net/publication/235611093TechniquesofProgramCodeObfuscationforSecureSoftware

Подробнее..

Разработана опенсорсная утилита Depix для восстановления паролей с размытых скриншотов

21.12.2020 12:20:35 | Автор: admin
Разработана опенсорсная утилита Depix для восстановления паролей с размытых скриншотов


Результат работы программы Depix (исходный код)

В голливудских фильмах любят преувеличивать. Они зуммируют фотографии в миллион раз и выводят цифры из одного пикселя.

Хотя это невероятно, но научные исследования в этой области идут давно. Ещё в 90-е годы были опубликованы теоретические работы и PoC с восстановлением текста из размытых изображений. В 2012 году Владимир Южиков писал на Хабре о своей программе SmartDeblur для восстановления смазанных и расфокусированных снимков.

Несмотря на достаточно хорошее развитии науки в данном направлении, до сих пор не было специализированного инструмента конкретно для восстановления паролей (текста) после пикселизации. Программа Depix первый такой инструмент.

В 2019 году руководитель видеогруппы Лаборатории компьютерной графики и мультимедиа ВМК МГУ Дмитрий Ватолин рассказывал о современном состоянии науки в части повышения резкости фотографий. Он говорил, что российская полиция постоянно просит его о помощи, хотя и не понимает сложности проблемы:

Вопросы всегда одни и те же. У нас есть видео с подозреваемым, пожалуйста, помогите восстановить лицо Помогите увеличить номер с видеорегистратора Здесь не видно рук человека, пожалуйста, помогите увеличить И так далее в том же духе.

Чтобы было понятно о чем речь вот реальный пример присланного сильно сжатого видео, где просят восстановить размытое лицо (размер которого эквивалентен примерно 8 пикселям).


В общем, проблема повышения резкости действительно актуальна. Все хотят найти в кадре информацию, которой там нет.

Что такое пикселизация?


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

Реализация алгоритма Depix атакует (то есть пытается обратить вспять результат работы) общего линейного фильтра для блока пикселей (linear box filter). Этот фильтр берёт блок пикселей и перезаписывает его средним значением всех пикселей в блоке. Реализация простая и быстрая, поскольку можно обрабатывать несколько блоков параллельно.

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



Инструменты для снятия размытости, история и исследования


Изображения можно размыть множеством способов. Пикселизация линейными фильтрами для блоков пикселей лишь один из вариантов. Большинство алгоритмов размытия склонны смешивать/растягивать пиксели, поскольку пытаются имитировать естественные размытия, которые вызваны движением камеры или расфокусировкой.

Есть множество инструментов для повышения резкости в обычных задачах, таких как повышение резкости фотографий. К сожалению, именно с паролями нужен другой подход. Здесь высота символов всего в пару блоков, так что нет смысла просто повышать резкость, пишет автор программы Depix.

Выше мы привели ссылки на некоторые инструменты и исследования, опубликованные на Хабре с 2012 года.

Последние разработки в области искусственного интеллекта породили на свет причудливые заголовки в новостях, типа Исследователи создали инструмент, который идеально повышает резкость лиц. На иллюстрации ниже примеры из научной статьи с описанием алгоритма PULSE исследователей из университета Дьюка (США).


Работа алгоритма PULSE из университета Дьюка

Но на самом деле здесь ИИ не восстанавливает фотографии, а генерирует новые изображения, которые размываются в такие же пиксели. Фундамент этих работ заложен алгоритмом RAISR от 2016 года. ИИ генерирует лица, которые размываются в картинку, данную на входе. Важно понимать, что сгенерированное лицо не является оригиналом, из которого получено исходное размытое пятно.

Алгоритмы вроде PULSE кажутся новыми, но они ведут очень давнюю историю инструментов для удаления размытия. Ещё в 1994 году (!) Марк Буйе из Юго-западного исследовательского института (США) написал программу для генерации Плутонов, размытия картинок и их сравнения с настоящими фотографиями, полученными с телескопа Хаббл.

Восстановление номера


В широко известной статье от 2006 года Дхира Венкатраман объясняет алгоритм, как восстановить пикселизированный номер кредитной карты. Идея проста: сгенерировать все номера кредитных карт, пикселизировать их и сравнить результат с пикселизированным числом.

Например, мы видим в интернете фотографию чека или банковской карточки с размытым номером. Как видим, здесь для размытия использовался линейный фильтр для блоков 88 пикселей:



Как восстановить эти цифры?

1. Берём образец чистого бланка.



2. Скрипт генерирует картинки для всех номеров.



3. Размываем каждую картинку по образцу исходного изображения.



4. Определяем вектор яркости каждого изображения. Вектор типа $a=[a_1,a_2...,a_n]$ содержит значения яркости каждого блока.



Здесь номер чека 0000001 соответствует вектору a(0000001)=[213,201,190,...].

Также определяем вектор яркости образца $z=[z_1,z_2,...z_n]$.



5. Находим вектор с минимальным расстоянием от исходного (после нормализации).

Константы нормализации:

$N(a(x)) = (a(x)_0^2 + a(x)_1 ^2 + ...)^2$


$N(z) = (z_0^2 + z_1 ^2 + ...)^2$


Вычисление расстояния:

$d(x)=sqrt((a(x)_0/N(a(x)) - z_0/N(z))^2 + (a(x)_1/N(a(x)) - z_1/N(z))^2 + ...)$


Например:

d(0000001) = 1.9363d(0000002) = 1.9373...d(1124587) = 0.12566d(1124588) = 0.00000

Так находим номер чека: 1124588.

В 2019 году Сомдев Сангван описал интересный метод восстановления размытых лиц в расследованиях OSINT. Метод такой: разрешение фотографии повышается в Фотошопе. Оно сначала размывается:



А потом запускается поиск по картинкам Яндекса (более продвинутый, чем Google Images). В данном случае Яндекс выполняет брутфорс лица на изображении:



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

Это является основой для нашего алгоритма восстановления паролей со скриншотов.

Описание алгоритма для восстановления паролей


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

У алгоритма есть определённые ограничения. Он требует одинакового размера и цвета текста на одном и том же фоне. Современные текстовые редакторы также добавляют оттенок и насыщенность, допуская огромное количество возможных вариантов шрифтов на скриншоте.

Здесь довольно простое решение. Берём последовательность де Брёйна для ожидаемых символов, вставляем в тот же редактор и делаем скриншот. Данный скриншот используется в качестве подстановочного изображения для аналогичных блоков:



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

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



Создание последовательности де Брёйна с пробелами вокруг, очевидно, создаёт ту же проблему, только наоборот: алгоритм не сможет найти правильные блоки, где на край блока попала соседняя буква. Можно сгенерировать изображение со всеми вариантами буквосочетаний, а также с пустыми местами по краям. По такой картинке поиск будет идти дольше, но даст лучшие результаты.

Для большинства размытых изображений инструмент находит результаты одиночного совпадения для блоков. Затем проверяется, что совпадения окружающих блоков находятся на том же геометрическом расстоянии, что и на размытом изображении.

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



Исходный код программы Depix опубликован на Github.

Кстати, описанная техника перекликается с некоторыми известными криптографическими атаками. Например, это похоже на взлом хэшей, напоминает атаку на блочный шифр ECB и атаку на основе открытых текстов (KPA).

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





На правах рекламы


Наша компания предлагает безопасные серверы с бесплатной защитой от DDoS-атак. Возможность использовать лицензионный Windows Server на тарифах с 4 ГБ ОЗУ или выше, создание резервных копий сервера автоматически либо в один клик.

Используем исключительно быстрые серверные накопители от Intel и не экономим на железе только брендовое оборудование и одни из лучших дата-центров в России и ЕС. Поспешите проверить.

Подробнее..

Исследование какие способы обхода антивирусов используют хакеры

12.04.2021 16:18:43 | Автор: admin

Создание уникального вредоносного ПО требует больших ресурсов, поэтому многие хакерские группировки используют в своих атаках массовое, часто публично доступное ВПО. Широкое использование неизбежно приводит к тому, что такой инструмент попадает на радары антивирусных компаний, а его эффективность снижается.

Для решения этой проблемы хакеры используют техники упаковки, шифрования и мутации кода. Такие техники часто реализуют отдельные инструменты крипторы (crypters) или просто пакеры. В этой статье на примере банковского трояна RTM мы рассмотрим, какие пакеры могут использовать злоумышленники и как эти пакеры осложняют обнаружение ВПО.

Полная версия данного исследования доступна по ссылке.


Packer-as-a-service

Хакерская группа, стоящая за распространением RTM, до конца 2020 года регулярно проводила массовые фишинговые рассылки с вредоносными вложениями. Этот процесс, по всей видимости, происходил автоматически.

Каждое такое вложение содержало существенно отличающиеся друг от друга файлы, при этом итоговая полезная нагрузка практически не менялась.

Пример архива RTMПример архива RTM

Подобная особенность естественное следствие применения крипторов. Первоначально группа, стоящая за RTM, использовала свой собственный уникальный криптор, однако в течение 2020 года дважды его сменила.

При исследовании по-новому упакованных образцов нам удалось обнаружить множество другого ВПО, которое было защищено аналогичным образом. Пересечения с другими вредоносами с учетом автоматизации процесса упаковки, на наш взгляд, позволяют говорить об использовании злоумышленниками модели packer-as-a-service. В этой модели упаковка вредоносных файлов делегируется специальному сервису, которым управляет третья сторона. Доступ к таким сервисам часто продается на хакерских форумах.

Rex3Packer

Первое использование этого пакера группой RTM, которое нам удалось обнаружить, относится к ноябрю 2019 года. Активное же его применение, по нашим данным, приходится на период апрельмай 2020 года.

Фишинговое письмо RTM, январь 2021Фишинговое письмо RTM, январь 2021

Нам не удалось связать этот упаковщик с каким-либо из ранее описанных публично, поэтому мы дали ему свое название по трем особенностям его устройства: наличию рекурсии (recursion), реверса битов (reverse) и рефлективной загрузки PE-файлов (reflection) Rex3Packer.

Алгоритм распаковки

Общий алгоритм извлечения полезной нагрузки выглядит так:

  1. С помощью VirtualAlloc выделяется заранее определенное количество памяти с правами на чтение, запись и исполнение.

  2. В выделенный буфер копируется содержимое образа текущего процесса в памяти (в частности, секция .text).

  3. Управление передается на функцию внутри буфера.

  4. Вычисляется разница между положением одних и тех же данных в буфере и в образе PE-файла (разность между адресами в буфере и виртуальными адресами в образе). Эта разность заносится в регистр ebx. Все обращения к виртуальным адресам в коде проиндексированы содержимым этого регистра. За счет этого везде, где это необходимо, к адресам из PE-образа добавляется поправка, которая позволяет получить соответствующий адрес в буфере.

  5. Выделяется еще один буфер под упакованные данные.

  6. Через вызов VirtualProtect устанавливаются права RWX на весь регион памяти с образом PE-файла.

  7. Упакованные данные копируются в свой буфер.

  8. Происходит декодирование упакованных данных.

  9. Регион памяти с образом PE заполняется нулевыми байтами.

  10. Декодированные данные представляют собой исполняемый файл PE-нагрузку. Эта полезная нагрузка рефлективно загружается на место исходного PE-образа, а управление передается на ее точку входа.

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

Непосредственно упакованным данным предшествует заголовок размером 16 байт, который содержит 4 поля по 4 байта:

  • размер самого заголовка,

  • размер исходных данных (PE-нагрузки),

  • позиция в исходных данных (*), по которой происходит их разделение,

  • режим кодирования (1, 2, либо 4).

Декодирование выполняется следующим образом:

  1. Внутри каждого байта выполняется реверс порядка битов (к примеру, 10011000 становится 00011001).

  2. В зависимости от режима кодирования (1, 2, 4), данные разбиваются на блоки размером N = 9, 5, либо 3 байта соответственно. Результат декодирования блока это (N 1) байт (то есть 8, 4, или 2).

  3. В первых N-1 байтах блока отсутствует часть битов: их значения всегда равны нулю. Чтобы восстановить оригинальные байты, с помощью масок вида 00000001, 00010001 или 01010101 из последнего байта блока извлекаются недостающие биты. При этом для каждого следующего байта маска сдвигается. То есть последний байт блока фактически составлен из объединенных логической операцией OR битов, которые извлечены из предыдущих байтов.

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

Схема получения исходных байтов в режиме 4Схема получения исходных байтов в режиме 4

4.После операции по восстановлению битов во всех блоках полученные данные представляют собой исходный PE-файл, который был разделен по позиции (*) на две части. Эти части, в свою очередь, были переставлены между собой. Обратная перестановка с учетом значения (*) позволяет получить оригинальный файл.

Обфускация

Чтобы усложнить анализ кода, в пакере применяется различного рода запутывание:

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

 Примеры вызова функций WinAPI Примеры вызова функций WinAPI
  • Характерная особенность данного пакера наличие циклов (не выполняющих полезных операций), которые реализуются через рекурсивную функцию.

Функция с рекурсивным вызовом (вариант без обфускации)Функция с рекурсивным вызовом (вариант без обфускации)
  • Для дополнительного запутывания в исполняемый файл добавляется несколько десятков случайно сгенерированных функций. Они могут ссылаться друг на друга, но в процессе работы ни одна из них не получает управления.

Использование

Кроме экземпляров RTM, мы обнаружили использование Rex3Packer для упаковки различного ВПО, в основном из стран СНГ.

Семейство ВПО

SHA256

Phobos Ransomware

6e9c9b72d1bdb993184c7aa05d961e706a57b3becf151ca4f883a80a07fdd955

Zeppelin Ransomware

8d44fdbedd0ec9ae59fad78bdb12d15d6903470eb1046b45c227193b233adda6

Raсcoon Stealer

3be91458baa365febafb6b33283b9e1d7e53291de9fec9d3050cd32d98b7a039

KPOT Stealer

9b6af2502547bbf9a64ccfb8889ee25566322da38e9e0ccb86b0e6131a67df1e

Predator The Thief

d1060835793f01d1e137ad92e4e38ef2596f20b26da3d12abcc8372158764a8f

QakBot

18cc92453936d1267e790c489c419802403bb9544275b4a18f3472d2fe6f5dea

Также мы отметили использование пакера для упаковки экземпляров ВПО из семейств Nemty, Pony, Amadey.

HellowinPacker

В мае 2020 группа RTM переключилась на использование нового упаковщика HellowinPacker, который продолжала активно использовать до начала 2021 года. Ключевой особенностью этого пакера является два уровня мутации кода. Первый из них существенно меняет структуру кода распаковки, делая различные образцы не похожими друг на друга.

Сравнение кода в двух экземплярах разной структурыСравнение кода в двух экземплярах разной структуры

Второй уровень меняет лишь отдельные детали при неизменной в целом структуре кода. При этом изменения главным образом затрагивают ассемблерные инструкции и не влияющие на работу программы константы. В результате в декомпилированном виде код выглядит практически идентичным.

Сравнение кода в двух экземплярах одной структурыСравнение кода в двух экземплярах одной структуры

Так же, как и в случае с Rex3Packer, мы имеем дело с массовым использованием HellowinPacker для упаковки различного ВПО. При этом вредоносное ПО из одного семейства, как правило, имеет в упакованном виде одну и ту же структуру. Это можно пронаблюдать, по крайней мере, на протяжении некоторого времени затем структура может измениться.

Алгоритм распаковки

Одни из первых действий, которые встречаются во всех упакованных файлах это попытки открыть ключ реестра HKEY_CLASSES_ROOT\Interface\{b196b287-bab4-101a-b69c-00aa00341d07} (регистр символов в конкретном случае может отличаться) и запросить в нем значение по умолчанию (Default). От успешности этих операций в некоторых модификациях генерируемого кода зависит корректное продолжение работы программы.

GUID интерфейса в разных случаях также может отличаться.

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

Этот блок начинается с четырехбайтного числа, которое хранит размер исходных данных (тех, которые будут получены после декодирования). Вызовом VirtualAlloc под расшифрованные данные выделяется блок памяти нужного размера с правами RWX. В выделенную память блоками по X байт копируются зашифрованные данные. При этом в оригинальном файле между этими блоками располагаются пропуски длиной Y байт.

Схема копирования данных в HellowinPackerСхема копирования данных в HellowinPacker

Затем происходит процесс дешифровки блоками по 4 байта:

  • очередной блок интерпретируется как целое число (DWORD),

  • к его значению прибавляется индекс первого байта в блоке,

  • выполняется операция xor между полученным значением и суммой индекса и фиксированного ключа, числа Z.

Обфускация

Как и в случае с Rex3Packer, в экземплярах с HellowinPacker встречаются вызовы функций WinAPI, не относящихся к основной логике программы. Однако в данном случае они используются скорее как способ затруднить поведенческий анализ и детектирование в песочницах. В пользу этого предположения говорит то, что в большинстве случаев разнообразные функции вызываются подряд в самом начале программы.

Точка входа в одной из упакованных библиотекТочка входа в одной из упакованных библиотек

Дополнительным эффектом от такого использования WinAPI становится невозможность детектирования по списку импортируемых функций и imphash.

При работе с различными числовыми значениями часто встречается некоторая арифметическая обфускация: необходимые константы представляются в виде суммы или разности других констант (в определенных случаях равной нулю). При этом для получения констант могут быть использованы и вызовы функций WinAPI, дающие предсказуемый результат (например, 0 в случае неудачи).

Использование

HellowinPacker существует по крайней мере с 2014 года. За это время он был использован в различном массовом вредоносном ПО. Вот лишь несколько примеров:

Семейство ВПО

SHA256

Cerber Ransomware

1e8b814a4bd850fc21690a66159a742bfcec212ccab3c3153a2c54c88c83ed9d

ZLoader

44ede6e1b9be1c013f13d82645f7a9cff7d92b267778f19b46aa5c1f7fa3c10b

Dridex

f5dfbb67b582a58e86db314cc99924502d52ccc306a646da25f5f2529b7bff16

Bunitu

54ff90a4b9d4f6bb2808476983c1a902d7d20fc0348a61c79ee2a9e123054cce

QakBot

c2482679c665dbec35164aba7554000817139035dc12efc9e936790ca49e7854

Заключение

Пример с использованием крипторов позволяет проиллюстрировать разделение обязанностей в хакерской среде, особенно в сфере массового ВПО. Совершенно не связанные друг с другом хакеры могут заниматься разработкой вредоносной нагрузки, ее защитой от антивирусов (криптом) и доставкой конечному пользователю. При этом каждый элемент в этой цепочке может быть предоставлен как сервис. Такой подход снижает порог входа для технически неподготовленных киберпреступников: для проведения массовой атаки достаточно обладать лишь необходимой суммой денег на оплату всех сервисов.

Описанные нами упаковщики, конечно же, далеко не единственные на рынке. При этом они хорошо демонстрируют общие свойства подобных инструментов: в результате их работы получается исполняемый файл с обфусцированным полиморфным кодом распаковщика и шифрованной полезной нагрузкой. Мутации в коде и использование одних и тех же крипторов делают практически невозможным статическое детектирование полезной нагрузки. Однако, поскольку эта нагрузка так или иначе расшифровывается в память и начинает свою вредоносную деятельность, поведенческий анализ с использованием песочниц (таких, как PT Sandbox) позволяет обнаруживать ВПО и выносить точные вердикты даже для упакованных файлов. Следует также отметить, что упаковщики никак не влияют на взаимодействие вредоносов с управляющими серверами. Это дает возможность определять присутствие ВПО в сети, используя инструменты анализа трафика такие, как PT Network Attack Discovery.

Автор: Алексей Захаров

Подробнее..

Защита программного обеспечения от обратной инженерии

20.12.2020 20:21:03 | Автор: admin

В данной статье мы представим себя в роли разработчика лицензированного ПО и рассмотрим способы защиты от взлома нашей программы пиратами.

Введение

Мы будем рассматривать методы защиты программного обеспечения, написанного на компилируемом языке, от реверс-инжиниринга, пиратства и внедрения стороннего вредоносного ПО. Изложенная информация актуальна, поскольку одной из целей любого проприетарного проекта является лицензировать и контролировать распространение данного программного обеспечения. Практически все программы, требующие наличие лицензии подвергаются попыткам взлома и многие из них на данное время имеют пиратски аналоги. Далее для простоты взломанную программу будем называть крякнутой, а процесс взлома кряком (англ. crack).

В данной статье мы представим себя в роли разработчика лицензионного программного обеспечения на С++ и будем анализировать какие методы защиты следует использовать, чтобы усложнить процесс кряка нашей программы. Следует понимать, что любая программа может быть в конечном итоге взломана, а абсолютной защиты не существует, целью является сделать реверс инжиниринг наиболее сложным и время, требуемое на взлом программы больше, чем время между обновлениями нашего вымышленного ПО.

Общие сведения

Пиратство программного обеспечения является одной из основных проблем для разработчиков. Для защиты ПО от незаконного распространения недостаточно лицензии, необходимо защитить программу от обратного инжиниринга. Существуют сотни способов защиты программы, однако все они также имеют свой обход. Предположим, что мы хотим написать проприетарную программу на компилируемом языке С++ под операционную систему Windows, мы её лицензируем и будем продавать копии. Рассмотрим, как же нам необходимо поступить, чтобы единственным способом получения нашего ПО была покупка его лицензии у разработчика.

Разработанное на С++ ПО будет собрано в исполняемый файл, который и будет продаваться конечному пользователю. Во избежание его дальнейшего незаконного распространения в первую очередь нам необходимо встроить проверку лицензии в наш код: при запуске программы будет проверяться наличие лицензии у данного пользователя. Часть кода, которая занимается проверкой лицензии будем называть протектором. Оптимально чтобы протектор проверял наличие лицензии у пользователя через интернет. В таком случае если пользователь, который купил нашу программу передаст её другому, протектор не обнаружит лицензию и попросит приобрести ПО, либо просто завершит процесс.

Реверс инжиниринг

В случае, если мы проверяем наличие лицензии через интернет, подделать её практически невозможно, однако стоит понимать, что программа вместе с протектором находится на компьютере пользователя. Это значит, что для человека, владеющего отладчиком и умеющего редактировать ассемблерный код, не составит никакого труда просто удалить протектор из программы или сделать так, чтобы проверка лицензирования работала неправильно и всегда думала, что программа лицензионная. Анализ работы бинарного кода и внесение в него изменений без наличия исходников называется обратной инженерией (англ. reverse engineering). Декомпиляция ассемблерного кода обратно в код на С или С++ невозможна, однако возможно получить дизассемблер текстовое представление машинного кода. Несмотря на то, что чтение такого кода достаточно сложно, для реверс-инженера этого вполне достаточно, чтобы найти протектор. Рассмотрим способы защититься от обратной инженерии.

Методы защиты от реверса

Существуют множество методов защиты от кряка. Я перечислю наиболее эффективные современные методы защиты, а далее в статье мы рассмотрим каждый из них подробнее:

  • Создание зависимостей между протектором и основным кодом

  • Защита от отладки программы и изменения ассемблерного кода

  • Обфускация (мутация) нативного кода

  • Виртуализация нативного кода

Нативным кодом будем называть код, исполняемый напрямую на процессоре (т. е. то, что мы получаем после компиляции нашего кода под целевую архитектуру). Отладчик в нашем случае программа для пошагового обхода и изучения работы ассемблерного кода, позволяющая увидеть значения всех переменный в процессе исполнения и последовательность выполнения кода.

Создание зависимостей

Как только мы добавили проверку лицензии в нашу программу, пирату достаточно было лишь удалить её из ассемблерного кода, и он получал версию программы, работающую без лицензии.

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

Теперь реверс инженер не может просто так удалить протектор, так как это приведет к дальнейшей неправильной работе или крашу в программе. Но ПО всё еще плохо защищено, так как под отладчиком можно легко сломать проверку лицензирования в протекторе или, анализируя сам протектор, получить необходимые для программы значения и инициализировать их в обход защиты.

Защита от отладчика

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

Первое, что нам необходимо сделать, это запускать протектор в другом потоке. Регистр DR7 debug control register, может сигнализировать о том, что приложение запущено под отладчиком. Также можно проверять значения регистров, используемых при отладке, таких как DR0 DR3. Есть множество возможностей обойти эту защиту, но её реализация в протекторе не будет лишней.

Второй способ детектирования отладчика подписаться на хуки ОС windows, которые будут вызывать переопределенную нами функцию при попытке прикрепить к процессу отладчик или изменить наш нативный код. Например, можем использовать хук DbgUiRemoteBreakin(), который вызовется, когда к процессу прикрепится отладчик, сообщив нам об этом. Данный метод не сработает, если реверс-инженер запустит наш процесс изначально под отладчиком. В таком случае во время вызова хука протектор еще не будет запущен, а значит и словить его не сможет. Для комплексной защиты используют большое количество различных хуков.

Третий способ создания ситуаций, не влияющих на работу ПО, но вызывающие действия в отладчике. Например, мы можем выбросить исключение, сразу-же его обработать и замерить время между выбросом и обработкой. Исключение в отладчике может вызвать остановку, после чего, обработав исключение, по времени протектор поймет, что программа работает под отладчиком.

Четвертый способ воспользоваться интерфейсом ОС. В windows API есть множество функций, позволяющих узнать о наличии отладчика, прикрепленного к программе. Можно использовать такие функции, как:

  • IsDebuggerPresent() активен ли отладчик

  • CheckRemoteDebuggerPresent() удаленный отладчик

  • NtQueryInformationProcess() получает информацию о процессе

  • RtlQueryProcessHeapInformation() получает флаги кучи процесса

  • RtlQueryProcessDebugInformation() получает флаги отладчика процесса

  • NtQuerySystemInformation() получает информацию из системы

Полученная информация позволит определить наличие отладчика в системе.

Обфускация нативного кода

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

В нашем случае мы будем обфусцировать ассемблерный код. Такую обфускацию называют мутацией нативного кода. Для обфускации кода используют специальные программы обфускаторы. Данный метод защиты создает лишние инструкции, запутывает, добавляет ложные зависимости в коде, тем самым делая код сложнее для анализа и реверса, однако это замедляет программу. Чтобы не сильно влиять на работу ПО мы будем обфусцировать только наш протектор. Поскольку он связан со работой ПО, реверс-инженеру придется разбираться в работе мутированного кода протектора. Мутация одного лишь протектора незначительно повлияет на производительность всей программы, но значительно усилит безопасность. Для большей безопасности можно обфусцировать уже мутированный код протектора повторно.

Несмотря на все, даже такой код подвержен анализу опытных ревёрсеров. Перейдем к еще более мощному механизму защиты кода

Виртуализация нативного кода

Более надежной альтернативой мутации является виртуализация. При виртуализации мы исполняем наш код не напрямую на процессоре, а имеем уникальную виртуальную машину, исполняющую защищенный участок кода. В нашем проекте мы воспользуемся данным методом защиты вместо обычной обфускации. Для этого нам придется купить программное обеспечение VMProtect или Themida. Принцип работы его следующий: наш нативный код протектора транслируется в байткод и для него создается уникальная виртуальная машина. Пользователь получает виртуальную машину с байткодом внутри. При запуске программы пользователем, протектор запускается через виртуальную машину. Данный способ защиты снижает производительность в тысячи раз, но поскольку протектор это лишь малая часть ПО, общее снижение производительности все еще незначительно.

Заключение

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

Подробнее..

Pg_obfuscator обфускатор для postgres с сохранением распределения данных (на основе clickhouse obfuscator)

07.04.2021 12:05:29 | Автор: admin

Введение

В конце прошлого года мы завершили один из самых интересных и необычных проектов, которыми нам приходилось заниматься.

Наш клиент - klara.com - коммуникационная телемедицинская платформа, упрощающая взаимодействие пациентов с врачами в США, столкнулась со стремительным ростом на волне пандемии 2020 года. Одним из вызовов на которые пришлось отвечать инженерам klara.com в это непростое время стало автоматизированное нагрузочное тестирование, способное обнаружить проблемы с производительностью до того как они проявят себя в production среде.

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

Постановка задачи выглядела так: спроектировать и реализовать пайплайн нагрузочного тестирования таким образом, чтобы его можно было легко поддерживать силами QA-инженеров, использовать как часть CI/CD процессов компании, расширять по необходимости и иметь возможность реализовать различные сценарии нагрузочного тестирования. Критерием успешности проекта стала точная реализация одного из кейса по производительности из production в среде нагрузочного тестирования с помощью инструментов, которые мы разработали.

Технологическая платформа

Основные языки программирования в команде - Ruby, JS. В качестве основного хранилища klara.com использует Postgres. Безопасность персональных данных пациентов (PHI - Protected Health Information) является ключевым аспектом бизнеса klara.com. Для обеспечения надежного хранения и обработки данных платформа использует HIPPA совместимую SaaS платформу - Aptible. Aptible покупает ресурсы у AWS, поэтому для дальнейшего описания будет достаточно считать Aptible сильно урезанной и зарегулированной версией AWS.

Для максимально корректной реализации нагрузочного тестирования нам нужна среда максимально похожая на production среду. Идеально, если идентичными будут: серверный парк, структура и объем данных, версии кода, структура и объем трафика. Очевидно также, что сделать все перечисленное абсолютно идентичным за разумное время и бюджет не реально и всегда приходится принимать некие допущения.

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

Чтобы воспроизвести похожее поведение приложения во время тестов нам нужно иметь максимально похожую на production базу данных с точки зрения объема данных и их распределения. Из-за того, что klara хранит в том числе персональные данные, нам понадобится обфускация базы. Дополнительное условие - скорость работы обфускатора, хотелось бы быстро.

Обзор решений

Сейчас существует несколько инструментов для решения этой задачи в postgres, мы провели краткий сравнительный анализ, который приведен ниже:

postgresql_anonymizer

+ Самое популярное по количеству звезд на github решение из имеющихся

+ Очень много функций для разных типов данных с разными стратегиями, которые можно применять точечно для выбранных полей (http://personeltest.ru/aways/postgresql-anonymizer.readthedocs.io/en/latest/masking_functions/)

+ Можно выгружать сразу в *.sql дамп

- Нужно устанавливать как расширение рядом с бд

- Для каждого поля нужно прописывать security labels с масками

- Маски работают только с одной схемой

- Нет данных по производительности

Это решение мы не рассматривали из-за того, что оно должно устанавливаться как расширение, запихивать, что-то в production - так себе идея.

triki

+ Заявлена высокая скорость работы (1.4гб mysql dump 17sec)

+ Много типов данных + можно определить свои (форк + правки т.к. кристал руби-френдли язык)

+ Можно выгрузить конфигурацию всей схемы для дальнейшей настройки обфускатора (таблицы-поля)

+ Не требуется никаких правок в исходной бд, только настроить коннект

+ Выгружает в *.sql дамп

Выглядело неплохим вариантом, удобный деплой, понятный нам и заказчику язык, очевидный недостаток - не понятно как сохраняется распределение данных.

pgdump-obfuscator (форк)

+ есть возможность задавать параметры полей через cli (только в форке)

- нет информации о производительности

- обновлялся 8 лет назад

clickhouse-obfuscator

+ Заявлена высокая скорость работы (в докладе говорилось, что 1тб данных обфусцирован за 1.5 дня)

- Написан на C++ (нашей команде сложно вносить изменения)

- Принимает только csv-формат

- Нет внятной документации (только статья на Хабре)

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

pg_obfuscator

К сожалению для нашей задачи, clickhouse obfuscator не поддерживал прямое подключение к postgresql. Поэтому нам пришлось написать утилиту, которая решает задачу обфускации postgresql с учетом всей специфики работы именно с этой базой. Исходный код доступен по адресу.

Утилита представляет собой wrapper над psql client и clickhouse obfuscator и реализует следующую функциональность

  • выгрузка схемы базы с сохранением внешних ключей и проверок ссылочной целостности

  • исключение из обфускации таблиц, полей таблиц

  • использование предопределенных шаблонов для генерации фейковых значений для полей

  • маппинг типов данных postgres на типы данных clickhouse

  • генерацию конфигурации со значениями по умолчанию

Из-за специфики работы clickhouse-obfuscator утилита требует дискового пространства для работы равного двойному размеру базы данных. Поставляется в виде docker image и доступна по адресу.

В настоящий момент есть ограничения, которые следует иметь в виду:

  • утилита поддерживает только базовые типы postgres и не поддерживает вложенные: hstore, json, jsonb

  • несмотря на автоматическую генерацию конфига, для первого запуска он нуждается в правках

  • объем docker image составляет почти 700Mb

В рамках поставленной задачи мы наблюдали следующие скоростные характеристики: тестовая база 10Гб обфусцировалась за 40 минут, продуктовая в 50 Гб - 6..8 часов. Чем обусловлена нелинейность работы мы не выясняли.

Ниже я продемонстрирую работу c pg_obfuscator на примере работы с devrimgunduz/pagila: PostgreSQL Sample Database.

Демо

Развернем контейнер с postgres и создадим в нем 2 базы для демонстрации:

docker run --rm --name=db -e POSTGRES_PASSWORD=password -p5432:5432 postgresdocker exec -i db psql -U postgres postgres -c 'create database pagila;'docker exec -i db psql -U postgres postgres -c 'create database pagila_o;'

Посмотрим IP-адрес базы - он понадобится для работы обфускатора:

docker inspect db | grep IPAdd

"SecondaryIPAddresses": null,

"IPAddress": "172.17.0.2"

И зальем в контейнер скрипты из проекта pagila:

cd /tmpgit clone git@github.com:devrimgunduz/pagila.gitdocker exec -i db psql -U postgres pagila < /tmp/pagila/pagila-schema.sqldocker exec -i db psql -U postgres pagila < /tmp/pagila/pagila-data.sql

Убедимся, что там появились данные:

docker exec -i db psql -U postgres pagila -c 'select a.first_name, a.last_name, f.film_id, f.title, f.description from film f join film_actor fa on f.film_id = fa.film_id join actor a on a.actor_id=fa.actor_id where f.film_id = 7;'

first_name | last_name | film_id |   title   |                  description------------+-----------+---------+-----------------+-----------------------------------------------------------------------------------JIM    | MOSTEL  |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet BoatRICHARD  | PENN   |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet BoatOPRAH   | KILMER  |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet BoatMENA    | HOPPER  |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet BoatMICHAEL  | BOLGER  |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet Boat(5 rows)

База для экспериментов готова. Теперь расчехлим pg_obfuscator, принципиальным моментом является монтирования тома для конфига, чтобы иметь возможность его потом поправить.

mkdir /tmp/configdocker run -it --rm -v /tmp/config:/opt/pg_obfuscator/config pg_obfuscator sh

Дальше команды выполняются в шелле обфускатора, если не сказано другого:

bundle exec ruby pg_obfuscator.rb --configure --source-db-host 172.17.0.2 --source-db-port 5432 --source-db-name pagila --source-db-user postgres --source-db-password password.......I, [2021-04-02T08:47:54.682868 #9] INFO -- : Processed 20 tablesI, [2021-04-02T08:47:54.683243 #9] INFO -- : Check config before run export tables and obfuscation!I, [2021-04-02T08:47:54.696328 #9] INFO -- : Config saved to: config/config.yml

Обфускатор говорит, что нужно проверить конфиг и внести необходимые изменения. Конфиг для 20 таблиц получился около 400 строк, секции, которые нуждаются в правках отмечены - need_fix: true. Для того, чтобы вам было легче повторить я выложил исправленный конфиг сюда.

Для демонстрации генерации фейковых данных посмотрим на секцию в таблице actor:

last_name:db_data_type: textnot_null: trueobfuscator_data_type: Stringfake_data:type: patternvalue: "%{first_name}SON"

В качестве фамилии мы используем имя и постфикс SON.

Выполним последовательно экспорт схемы, данных, обфускацию и заливку полученных данных в базу pagila_o

ruby pg_obfuscator.rb --export-schema --source-db-host 172.17.0.2 --source-db-port 5432 --source-db-name pagila --source-db-user postgres --source-db-password passwordruby pg_obfuscator.rb --export-tables --source-db-host 172.17.0.2 --source-db-port 5432 --source-db-name pagila --source-db-user postgres --source-db-password passwordbundle exec ruby pg_obfuscator.rb --obfuscateruby pg_obfuscator.rb --import --target-db-host 172.17.0.2 --target-db-port 5432 --target-db-name pagila_o --target-db-user postgres --target-db-password password

и выйдя из контейнера с обфускатором посмотрим на результат

docker exec -i db psql -U postgres pagila_o -c 'select  a.first_name, a.last_name, f.film_id, f.title, f.description from film f join film_actor fa on f.film_id = fa.film_id join actor a on a.actor_id=fa.actor_id where f.film_id = 7;'
first_name | last_name | film_id |  title  |                           description------------+-----------+---------+-----------+------------------------------------------------------------------------------------------------------------------------SA     | SASON   |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark TankRURA    | RURASON  |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark TankBER    | BERSON  |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark TankCA     | CASON   |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark TankMER    | MERSON  |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark Tank(5 rows)

Видим, что last_name сформирован фейкером, описание обфусцировано, ссылочная целостность сохранена.

На этом все, мы надеемся, что утилита будет полезна сообществу, будем рады видеть пулреквесты.

Благодарим команду clickhouse obfuscator за отличный продукт!

Подробнее..

Первые пять шагов для перелома ситуации с читерами в PvP-шутере

18.03.2021 20:06:33 | Автор: admin

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

Итак, эти шаги:

  • Обфускация.

  • Хранение данных.

  • Миграция прогресса.

  • Система бана.

  • Подсчет хеша всех библиотек.

  • Защита от переподписывания версий.

  • Photon Plugin.

  • Серверная валидация инаппов.

  • Защита от взлома оперативной памяти.

  • Собственная аналитика.

  • И одновременный релиз всех решений.

Сегодня поговорим про первые пять пунктов.

Для удобства я пронумеровал все разделы, но напомню, что приведенные ниже решения мы разрабатывали и выкатили одновременно. Потому что постепенный ввод изменений сильно облегчит взломщикам отслеживание апдейтов.

Шаг 1. Обфускация

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

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

Мы используем плагин Beebyte Obfuscator. Но для работы плагинов обфускаторов надо придерживаться определенных правил оформления кода, иначе названия свойств и методов не будут скрываться.

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

  • internal вместо **public** и **private** или **internal** вместо **protected**.

  • Все члены классов, помеченных [Serializable], не обфусцируются.

  • Свести к минимуму использование Parse/ToString для enum (при обфускации результат, как правило, бесполезен), но если это все-таки необходимо, то помечаем атрибутом **[Obfuscation(Exclude = true)]**.

    Например:

[Obfuscation(Exclude = true)]public enum GameEventItemContainerContentType{   None = 0,   SingleItem = 1,   ItemsCollection = 2,   Start = 3,}
  • По возможности заменяем `const` на `static`. Статики нельзя использовать в switch. Например, вместо internal const string A_B = "my_constant" делать internal static readonly string A_B = "my_constant" либо internal static string A_B { get{...} }.

  • События анимаций их нужно оставлять/делать public или помечать атрибутом [Obfuscation(Exclude = true)].

  • Лямбды имя лямбды включает имя того метода/класса, в котором она определена, вне зависимости от модификатора доступа метода или класса. По возможности нужно заменять лямбды методами.

  • Kорутины в IL не обфусцируются. Поэтому их можно обфусцировать вручную, например, назвать vfg45_00.

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

Отмечу минус использования обфускации время сборки неминуемо увеличивается (у нас примерно на 30%), но польза несравнимо выше.

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

Шаг 2. Хранение данных

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

Для реализации этой задачи необходимо было переработать все функционалы, в которых что-либо сохранялось.

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

Что ж, для начала составили критерии, которым должна удовлетворять наша система хранения данных:

  • Пользовательский опыт, когда все действия в игре происходят моментально без задержек на серверную валидацию, не должен пострадать.

  • При запуске приложения одним пользователем на нескольких устройствах игрок должен видеть абсолютно одинаковые состояния.

  • Нельзя допустить, чтобы какие-либо проблемы с сервером приводили к запрету входа в игру.

  • Минимизировать трафик и нагрузку на сервер.

  • После реализации основного этапа поддержка и развитие новых функционалов должны быть максимально простыми и быстрыми.

  • Все должно быть надежным и исключать возможность несанкционированного накручивания прогресса.

  • Желательно оставить возможность пользоваться игрой оффлайн, так как такие режимы востребованы среди наших игроков.

Потом начали составлять план работ. Выделили несколько глобальных этапов:

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

    Тогда опыта использования постоянного сокетного соединения у нас еще не было (предполагалось, что в дальнейшем без соединения нельзя будет находиться в основных разделах игры), поэтому решили обкатать соединение постепенно.

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

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

  2. Формат хранения данных определили JSON. Может он и не самый оптимизированный по трафику и работе, но удобен в использовании. Его мы расширяем и часто используем по проекту.

    Глобально прогресс представляет собой Dictionary<int, object>, где каждая пара это так называемые слоты для хранения данных. Каждый слот служит для хранения своего типа данных: слот валюты, слот инвентаря, слот ачивок и так далее. Ключ он же номер слота данных решили сделать интовым, чтобы сократить использование трафика, значение в каждом слоте может иметь свой формат, но это всегда JSON.

    Чтобы все действия на клиенте отрабатывались моментально, прогресс хранится и на клиенте, и на сервере (команды по изменению прогресса пишутся и там, и там). Отрабатывают сначала на клиенте: визуально пользователь видит, что все окей, а в это время на сервер отправляются параметры для команды. Там они проходят необходимые проверки, и если все хорошо, то прогресс меняется аналогичным способом, как и в клиенте. По результату сравниваются итоговые хеши изменившихся слотов на сервере и клиенте, если не сходятся рвется соединение с клиентом, клиент переавторизовывается и подтягивает последнее валидное состояние слотов.

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

    На случай временной потери интернета (или если, например, приложение закроется до отправки команды на сервер), команды сохраняются локально и при следующем запуске перед началом сравнения слотов на сервере и клиенте сначала отправляются они и только потом хеши имеющихся слотов.

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

  3. Для сохранения возможности входа в Pixel Gun 3D в те моменты, когда необходимо по каким-либо причинам остановить сервер прогресса, реализовали для него аварийный режим. При его включении все команды отрабатывают только локально. А когда включается штатный режим, клиент присылает серверу текущие слоты. В эти моменты, конечно, есть возможность что-либо накрутить через какой-нибудь мод. Но аварийный режим мы включаем крайне редко, да и визуально на клиенте никак этого не понять, поэтому вероятность, что этим воспользуются минимальна.

  4. Оставили возможность входа в игру при отсутствии интернета. Игрокам доступны одиночные режимы без наград и ряд других локальных возможностей, которые не требуют изменений прогресса.

Шаг 3. Миграция прогресса

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

Для этого мы добавили выдачу уникальных ключей всем, кто заходил в игру во время реализации новой схемы прогресса (примерно полгода). В дальнейшем, как только выпустили версию с обновленным прогрессом, мы отключили на сервере выдачу этих ключей, а принимали мигрированный прогресс только от тех, у кого был ключ и только один раз (чтобы нельзя было вернуться в прошлую версию и начислить прогресс тем, кто этого не сделал ранее).

Так мы мигрировали прогресс всем активным игрокам и решили проблему взлома через старые незащищенные версии.

Шаг 4. Система бана

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

Ранее, когда не было постоянного соединения с сервером, не было возможности надежно забанить клиент информация о бане запрашивалась отдельным http-запросом с сервера, и в случае положительного ответа в клиенте выводился баннер, что аккаунт забанен. Хоть мы и старались это спрятать в коде, появлялись различные моды, где весь мешающий жизни функционал был нейтрализован.

Сейчас, когда реализована постоянная связь с сервером, большинство функционалов просто не работает без соединения. Для бана достаточно запретить авторизацию при открытии соединения с отдельной ошибкой (для показа баннера, что игрок забанен), чтобы сделать невозможным пользование приложением с заблокированным аккаунтом.

Для защиты онлайна на серверах фотона от забаненных мы также сделали проверку с плагина фотона на факт бана. Если там выясняется, что такой id забанен, то игрока выкидывает из комнаты.

Шаг 5. Подсчет хеша всех библиотек

Одним из традиционных способов взлома является модификация библиотек приложения напрямую. В случае с приложениями на Unity это libil2cpp.so (при билде через IL2CPP).

Для обнаружения таких изменений может использоваться проверка на несовпадение контрольных сумм (хеша библиотек). Самым контролируемым способом будет вычисление текущего хеша на клиенте и отправка его на сервер (где он будет сравнен с эталонным).

Получить путь до наших библиотек можно так:

public string GetLibraryDirectory(){var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");if (unityPlayer == null)throw new InvalidOperationException("unityPlayer == null");var _currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");if (_currentActivity == null)throw new InvalidOperationException("_currentActivity == null");AndroidJavaObject packageManager = _currentActivity.Call<AndroidJavaObject>("getPackageManager");if (packageManager == null)throw new InvalidOperationException("packageManager == null");string packageName = _currentActivity.Call<string>("getPackageName");if (string.IsNullOrEmpty(packageName))throw new InvalidOperationException("string.IsNullOrEmpty(packageName)");const int GetMetaData = 128;AndroidJavaObject packageInfo = packageManager.Call<AndroidJavaObject>("getPackageInfo", packageName, GetMetaData);if (packageInfo == null)throw new InvalidOperationException("packageInfo == null");AndroidJavaObject applicationInfo = packageInfo.Get<AndroidJavaObject>("applicationInfo");if (applicationInfo == null)throw new InvalidOperationException("applicationInfo == null");string nativeLibraryDir = applicationInfo.Get<string>("nativeLibraryDir");if (string.IsNullOrEmpty(nativeLibraryDir))throw new InvalidOperationException("string.IsNullOrEmpty(nativeLibraryDir)");return nativeLibraryDir;}

Для автоматизации процесса при сборке билдов можно использовать OnPostprocessBuild в Unity и производить расчет эталонного хеша. Обратите внимание на то, что при сборке с включением нескольких платформ (ARM, x86) необходимо вычислять хеш по каждой платформе.

Что дальше

В следующий раз поговорим про остальные решения, а именно: защиту от переподписывания версий, Photon Plugin, серверную валидацию инапов, защиту от взлома оперативной памяти, одновременный релиз всех решений и собственную аналитику. А про некоторые объемные пункты уже готовим отдельные, более подробные материалы.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru