This is a mobile optimized page that loads fast, if you want to load the real page, click this text.

FAQ Как не стоит делать: безопасность клиентских скриптов на примере свежих дампов Majestic и SmotraRAGE (часть 2)

welaurs

Начинающий специалист
Автор темы
30 Ноя 2021
19
46
48
Дисклеймер. Сказанное ниже является личным мнением автора. Сам по себе автор является мастером спорта международного класса по продавливанию дивана и ничего полезного в своей жизни он, разумеется, не сделал. Сказанное не претендует на звание истины в последней инстанции, а автор готов признавать свои ошибки и публично приносить извинения, если заденет чьи-то чувства прекрасного своей графоманией с шизофреническими наклонностями.

Ранее в статье Как не стоит делать: безопасность ивентов и клиентских скриптов я указывал на возможность дампа любых клиентских ресурсов, в том числе скрипты, контент браузера и dlcpack'и. Мнимая безопасность, которую создали разработчики RageMP создает иллюзию, которая играет плохую шутку с разработчиками серверов. Но есть и те, кто позаботился о безопасности своих скриптов, иногда даже в ущерб игрокам. В данной теме будет разобрана безопасность на примере Majestic и Smotra RAGE, так как принципы обеспечения безопасности клиентских ресурсов у них отличаются, а в следующей проведем разбор GTA 5 RP.

Перед началом отмечу, что дампы (а тем более их деобфусцированные или расшифрованные версии) я не предоставляю.

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

Возьмем случайно место из дампа:


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


После объявления массива сразу следуют функции его "исправления": массив изначально перемешан и в нем присутствует проверка целостности. В случае, если какая-то строка изменена, код зависнет в бесконечном цикле исправления массива.


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


Потеряли названия переменных, потому подумаем над восстановлением хотя бы части их названий. По структуре дампа явно видно, что дамп собран webpack'ом или подобным сборщиком: есть реализация импортов, экспортов, shadow-переменных и прочей магии сборщиков. Можно предположить, что экспорт и импорт происходит посредством передачи функций в аргументы, потому допишем скриптик, добавив переименование функций и переменных в стиль вебпака, раскладывание предикейтов (!0, !1), а также переведем числа из hex в десятичные:


Итог по Majestic: подобный вид обфускации бесполезен. Единственная потеря в результате деобфускации - названия переменных. Несмотря на это, деобфусцированный дамп все также легок в чтении и не доставляет никаких проблем узнать названия функций, вызовов, аргументов функций. Несмотря на легкость в получении читабельного кода, подобная техника обфускации создает большие проблемы с производительностью:
JavaScript:
// оригинальный вид
mp.players.local.setHealth(100)

// vs обфусцированный псевдо-код
let array = [
    'players',
    'setHealth'
    'local',
];

function getOriginalString(offset) {
    // здесь большой кусок кода, который исполняется один раз при запуске (проверка целостности)
    return array[offset];
}

(() => {
    let properties = {
        0: 0,
        1: 2,
        2: 1
    };

    mp[getOriginalString(properties[0])][getOriginalString(properties[2])][getOriginalString(properties[1])](0x64);
}());
В обфусцированном виде для вызова функции необходимо сделать 6 обращений к свойству объекта (которые, кстати, не оптимизируются v8, так как Ignition не умеет предугадывать результаты исполнения функции во время компиляции в байт-код), 3 обращения к массиву, против оригинального кода, который только 3 раза обращается к свойствам объекта и попадает под оптимизацию. Примерно то же самое происходит и в браузерной части Majestic, с одной оговоркой: там все еще хуже, так как используется Vue, который под обфускацией показывает совсем плачевную производительность.


Перейдем к SmotraRAGE: парни выбрали интересное решение и просто зашифровали скрипты своим алгоритмом с использованием pako и base64. Структура клиентских файлов примерно следующая: index.js, где выполняется расшифровка и подключение скриптов и основная папка "core", содержащая весь код. Любой файл из core встречает нас примерно следующим содержимым и пафосной надписью с информацией о том, кто создал защиту:

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


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


Выводы из урока: не пытайтесь защитить код способами, что я показал ранее. Majestic страдает серьезным снижением производительности из-за обфускатора, который не справляется со своей задачей. А в случае SmotraRAGE это, ну я бы сказал, бесполезно. В обоих случаях все еще работает правило "не доверять клиенту".

P. S. Если "правообладатели" захотят связаться со мной - https://t.me/msmk_cn
 

Вложения

  • 1685075135416.png
    318.2 KB · Просмотры: 217
Последнее редактирование:

mippoosedev

Гуру
2 Мар 2021
294
139
100
По маджу - им скорее важно серверные дыры закрывать, чем вступать в вечную борьбу с дампами клиентов
Ну а по смотре - эту защиту сделал разработчик drift andreas(нишевый дрифт сервер), продает за скромные деньги. Для защиты от дурачков с экзеками вполне отлично подходит

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

+rep за статью
 
Реакции: vpn и Inoi

welaurs

Начинающий специалист
Автор темы
30 Ноя 2021
19
46
48
Серверные дыры нельзя закрыть путем исправления чего-то на клиенте. Единственный, как ни странно, рабочий способ закрывать дыры - не доверять клиенту.

Странно рассчитывать на то, что "htmlEscape" на клиенте гарантирует тебе отсутствие инъекций. А если он есть на сервере, зачем он тогда на клиенте?
 

mippoosedev

Гуру
2 Мар 2021
294
139
100
Я не говорил, что они исправляют серверные дыры на клиенте. Я лишь указал, что им ВАЖНЕЕ исправлять проблемы на сервере, чем бороться с дампами
 

mippoosedev

Гуру
2 Мар 2021
294
139
100
UPD:: Лучший способ защиты клиента - писать клиент на шарпе <3
 

vpn

Начинающий специалист
29 Май 2022
130
64
65
Возможно я что-то не так понял, но вроде речь идет о читах по типу executor. (Вызов серверной части, не по запланированному клиентскому коду)
И как мне кажется, что решение закрывать серверные дыры (Например проверять позиции игрока, если он пытается взломать какую нибудь работу на проекте),
это самый оптимальный вариант из всех.
А обфускацией можно как-раз скрыть некоторый код, который кажется важным или уникальным для проекта.
Фраза "не доверять клиенту" звучит довольно странно, в подобных случаях она звучат как "не доверять коду Back-End разработчиков".

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

В любом случае тема классная и мы можем сделать вывод, что нужно лучше защищать серверный код.
А по поводу защиты клиентского кода, человек который является хотя-бы мидлом, он найдет сервисы которые ему нужны для деобфускации, и спустя время сможет восстановить логику переменных. (И в 90% случаев он бы сам за это время смог написать этот код. Поэтому обфускация это в целом защита от дураков.)
 
Реакции: NITRO.dev и wholinc

kirillzver

Гуру
2 Ноя 2020
156
117
104
Я всегда был приверженцем того, что любые функции на стороне сервера должны быть защищены от несанкционированных запросов со стороны клиента.
Если придерживаться элементарных правил проверки того что приходит, и, при этом, хоть немного продумывать и исправлять возможные варианты обхода своих проверок, то, в принципе, можно и не бояться дампа клиентских файлов.

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

Inoi

/dev/null
VIP
15 Окт 2020
2,452
1,454
208
34
странные у вас споры парни
конечно лучше "делать заебись", проверять всё на сервере
но в чём проблема либо если пока ты это сделать не успел, если нет возможности (мб ты иблан, например), да и даже если успел - ещё и "защиту от дурака" впердоливать
с обфускацией, инкапсуляциями, переименованием коллремоута и вот этим вот всем
ну типа
а почему нет-то?

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

ну то есть я лайкнул, пушо люблю интересные в меру лонгриды
но с тем что это "бесполезно и так делать не надо" - совершенно не согласен
 
Реакции: MiLT и kirillzver

sonnyk

Участник портала
26 Ноя 2022
20
2
13
Ну от executor это не спасёт, все равно его можно юзать, ты только спрячишь название клиентских эвентов, а тому кто шарит за дешифровку не составит большого труда расшифровать и узнать название эвентов