История и описание ныне исправленной уязвимости в WarCraft 3

Это было в 2009 году, в марте, я увлекался созданием карт для игры WarCraft 3. Однажды мне показали карту, которая при запуске игры каким-то хитрым образом создавала консоль и писала в ней что-то вроде «Hello World!». Мягко говоря, я был ошарашен — это означало, что на системе можно запускать произвольный код.

Ниже приводится описание уязвимости и история того, как она была закрыта.

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

98% ЛЮДЕЙ НЕ ВЫДЕРЖАЛИ ТАКОГО ВИРУСА — WarCraft

Баг возвращения

Скрипты WarCraft 3 написаны на собственном неразвитом языке JASS (Just Another Script System) компании Blizzard. В целом, она достаточно гибкая (вся стандартная кампания сделана на визуальном дополнении на этом языке), но вот беда: нет структуры, а стандартный Sleep отсчитывает время даже когда игра поставлена на паузу, да еще и с пониженной точностью, словом, чтобы сделать плавное движение отряда, например, перемещая его каждые .03 секунды невозможно. Но есть таймеры, которые можно запустить, которые достаточно точны и по окончании отсчета можно вызвать функцию обратного вызова, указанную в аргументе. Но и они не решают проблему: например, способность, выполняющая некоторые отложенные действия, не будет работать правильно, если использовать ее дважды: нельзя передать никаких аргументов в функцию, которая вызывается после истечения таймера, поэтому невозможно выяснить, какой экземпляр способности она должна обрабатывать.

И тогда был найден баг с возвратом (это было давно, кажется в 2005 году, может раньше). Я не уловил этот момент.). JASS — язык со строгой типизацией, но эта ошибка позволила обойти ее. Это выглядело следующим образом:

function RB takes unit u return integer return u // она бы выдала ошибку, что функция должна вернуть число, // но она возвращает единицу return 0 // игра проверяла только последнюю инструкцию return endfunction

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

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

Читайте также:  Ошибка при запуске варкрафт 3 рефордж

История Событий World of Warcraft: Инцидент Порченой Крови

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

Как работает интерпретатор JASS

При загрузке скрипта карты игра создает псевдокод, который в некоторой степени напоминает ассемблер. В игре используются 8 байтовые опкоды, где первые 4 байта определяют код функции и опционально виртуальный регистр (их 256), а вторые 4 байта — аргумент, например, при загрузке значения в регистр он будет содержать непосредственно значение. Идентификаторы регистров для каждой следующей по коду операции увеличиваются, например foo = 0; bar = 2; — для присвоения значения foo будет использоваться регистр #00, а для bar #01, после использования регистра #FF снова будет использоваться регистр #00. Аналогично, индексы глобальных переменных также увеличиваются, и идут по порядку — первая объявленная переменная будет иметь индекс n, следующие n+1.

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

Уязвимость

В JASS есть тип code, это относительный указатель на функцию, он используется для передачи обратного вызова функции, например, если вы используете subject для вызова такой-то и такой-то функции. С ним не предполагается производить никаких математических операций и он определяется только литералом, например, код c = function foo. И он не указывает непосредственно на память, где находится псевдокод, он только задает отступ от начала всего обрабатываемого псевдокода. И здесь возникает ошибка возврата:

function StubFunc takes nothing returns nothing endfunction function I2C takes integer ic returns code return ic return (function StubFunc) // Просто пустая функция, нужна для проверки синтаксиса. endfunction функция C2I принимает код c возвращает целое число return c return 0 endfunction

Этот код вернет относительный адрес первого опкода переданной функции в виде числа.

function HackArrayW takes nothing returns nothing local code ctcode = I2C(C2I(function zOmgFunc2) + 1) // .

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

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

Читайте также:  Как летать в варкрафте

Известно, что в игре используется одна библиотека, которая не обновляется патчами — Storm.dll. Вы можете найти данные в его адресном пространстве и присвоить их адрес переменной массива, таким образом, вы получите массив, данные которого находятся не в специально выделенном пространстве, а прямо в исполняемом коде процесса. Нам нужно, чтобы поле size было больше и не приводило к перераспределению при попытке записать что-либо по высоким адресам, а второе поле указывало на адрес, по которому мы собираемся писать. В результате появилась возможность писать и читать память процесса. Простая запись в такой массив:

function Inj_PrepareInjector takes nothing returns nothing set zg0oI[0x200]=0xE8575653 set zg0oI[0x201]=0x000000F3 set zg0oI[0x202]=0x9F2DC88B set zg0oI[0x203]=0xFF000006 set zg0oI[0x204]=0x72656BE0 // / .

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

История

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

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

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

Игра всегда использует преобразование относительного адреса игрового опкода (тот, который можно получить с помощью Return Bug) в реальный адрес, и я просто добавил операцию и 0xfffffff8, просто чтобы предотвратить выполнение неправильного псевдокода. Я разместил его на форумах, посвященных созданию карт для WarCraft 3. Я поехал на дачу, где у меня не было интернета. Я понимаю, что поступил безответственно 😉

Кто-нибудь пытался связаться с разработчиками игры, не чуть позже они выпустили патч 1.24, который полностью запретил Return Bug и добавил его легальный аналог, но не разрешил возвратные преобразования — получить объект из числа стало невозможно. В результате часть карт, которые были написаны в JASS грамотно — быстро заменили функции и стали работать корректно, а другая часть, которая использовала обратное преобразование из числа в объект, сломана. Карты, созданные на визуальном дополнении, никак не отреагировали на это событие. В общем, Blizzard выбрала не самый лучший вариант, да еще и нарушила совместимость.

Читайте также:  Системные требования для варкрафт батл фор азерот

Что я хочу сказать в последний раз?

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

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

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

Добавлено:

Источник: habr.com

Вирус, который сделал Warcraft

При цитировании информации гиперссылка на ИА REGNUM обязательна.

Использование материалов ИА REGNUM в коммерческих целях без письменного разрешения агентства не допускается.

Свидетельства о регистрации Медива:

El No. ФС77-55029 от 14 августа 2013 года, выдан Федеральной службой по надзору в сфере связи, информационных технологий и массовых коммуникаций (Роскомнадзор);

ИА Нет. ФС77-51367 от 23 ноября 2012 года, выдано Федеральной службой по надзору в сфере связи, информационных технологий и массовых коммуникаций (Роскомнадзор).

Данный ресурс содержит материал 18+

Источник: regnum.ru

На неофициальном сервере World of Warcraft была эпидемия обучения

Пандемия коронавируса напомнила многие события в World of Warcraft: В 2005 году из-за небольшой игровой ошибки Азерот охватила чума «испорченной крови». Уже тогда ученые увидели в этом модель грядущих эпидемий.

В 2008 году Blizzard до выхода Wrath of the Lich King провела игровое мероприятие с похожей механикой заражения. Чума Плетта опустошала серверы в течение пяти дней. И вот эпидемия вернулась, но только на неофициальном сервере Elysium.

Администраторы сервера «запустили» в игру «вирус», он заразил один из игровых предметов. За первые 24 часа она поразила 7000 персонажей, а на пике эпидемии болезнь подхватили 88% населения сервера. А затем организаторы пандемии объяснили свои цели.

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

NPC постоянно предупреждали игроков о необходимости соблюдать дистанцию в любых условиях и оказывали помощь «больным». И все принятые меры возымели эффект: вторая волна охватила лишь 42 процента населения.

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

Подробнее о Геймеромания

  • Дуэт разработчиков хочет сделать игру по мотивам «Сайнфелда.»
  • Сиквел ATOM RPG выйдет в раннем доступе 11 мая
  • Хаймердингер, Джинкс и Экко в новом сюжетном ролике «Легенды Рунетеры

Источник: www.Игромания.ru