Доброго времени суток всем, кто читает этот цикл статей. К моменту написания цикла будет состоять из IV частей, ну и собственно это его первая часть. В ней я хотел бы вас познакомить с основами Flash технологии, методами создания Flash приложений, исследования, типичных ошибках создания приложения с обоих сторон(Клиентская и серверная), и познакомить с простыми примерами использования приложения в целях, непредусмотренный разработчикам. Для работы мы будем использовать кроссплатформенное ПО, так что вы можете повторить всё(Конечно же только на localhost, и на своими Flash приложениями) под системами Windows, Linux(В частности и *nix), и в большинстве случаев даже под MacOS X. I. Технология Flash Adobe Flash (ранее Macromedia Flash), далее просто Flash — мультимедийная платформа компании Adobe для создания веб-приложений или мультимедийных презентаций. Широко используется для создания рекламных баннеров, анимации, игр, а также воспроизведения на веб-страницах видео- и аудиозаписей. Я думаю вы знаете, что технология Flash обычно располагается на клиентской части, подобно JavaScript в виде частично скомпилированных SWF файлов(Расширение может быть изменено). Как я думаю, вы уже знаете, всё, что находиться на клиентской части может быть прочитано, изменено(Или заменено полностью), модифицировано и использовано в совершенно других целях, без ведома серверной части, и Flash этому не исключение; однако часть Flash разработчиков не имеет представления о вторжении в Flash, изменении кода, интерфейса, перехвата данных и это тоже следует учитывать. Также далее в тесте будет употребляться термин «Правильные Flash приложения» ,- под ними будут подразумеваться Flash приложения, действия реверсинга с которыми которые не будет иметь никого смысла, за исключением изучения исходного кода для самообучения создания подобных приложений. II. Используемое ПО Браузер: Mozilla Firefox, - http://www.mozilla.org/ru/firefox/new/ Требуемые дополнения: NoScript, NoFlash, FireBug, FlashFireBug, Greasmonkey. Flash: Debug версия Adobe Flash: http://www.adobe.com/support/flashplayer/downloads.html Сниффер: Wireshark,- http://www.wireshark.org/ tcpdump,- http://ru.wikipedia.org/wiki/Tcpdump JRE or JDK from Oracle , Adobe AIR: http://java.com/ru/download/index.jsp http://get.adobe.com/ru/air/ HTTP Анализатор: Charles,- http://www.charlesproxy.com/ Декомпилятор: Asdec,- http://code.google.com/p/asdec/ Отладчик: De Monster Debugger,-http://demonsterdebugger.com/downloads Версия 3.0 совместима с последней версией AIR for Linux. Adobe Flex(328 МБ): http://www.adobe.com/devnet/flex/flex-sdk-download-all.html Так-же нам понадобиться любой текстовый редактор с подсветкой синтаксиса, HEX-редактор. В случаи необходимости этот инструментарий будет расширяться. III. Классификация уязвимостей Перейдем собственно к уязвимостям: Уязвимости Flash платформы Уязвимости серверной части, связанные с недостаточной фильтрацией данных. Недостаточная проверка данных на серверной стороне. Возможность обмана серверной части посредством использования UDP протокола связи между Flash и сервером. Использование клиентской части для формирования данных, которые пользователь изменять ни в коем случае не должен. «Отсутствие» как таковой северной части, служащей ля обработки важных данных. Список составлен приблизительно и в будующем будет пополняться. IV. INTRO 1. В первой части цикла мы рассмотрим как таковые уязвимости и наиболее простые примеры. 2. Вторая часть будет примерно о этом же, но с более сложными примерами. В этих двух частях будут рассказаны основные идеи, способы выполнения, ошибки. 3. В этой части будет рассказано о нестандартном использовании Flash. 4. Ну и эта самая сложная часть вам расскажет о секретах нелегального заработка с использованием различных систем онлайн казино. Сразу скажу, тут не будет приведено примеров реального заработка, однако объем информации будет очень большой, так что вы ход статьи на ближайшее время не планируется. Статья приводиться только для ознакомления и не может являться руководством к побуждению противоправных действий ни в коем случае. В данном цикле не будет рассматриваться изменение переменных с помощью ArtMoney и подобных программ, однако скажу, что это всё же возможно. V. BODY 1 Как вы уже поняли, тут будут рассматриваться наиболее простые примеры, - для понимания общих технологий использования уязвимостей и базовой работе с ПО, с которым у вас могут возникнуть большие проблемы. Сразу говорю, - тут не будет приводиться руководство к установке ПО, настройке и использованию. Основная часть действий с ним требует предварительного ознакомления, что выходит за рамки этого цикла. Так же говорю, - большинство текущих уязвимостей на момент выхода будет закрыто, так что вам не надо пытаться повторить это. Ну что же, начнём... Начать я планировал с рассказа о моей первой найденной уязвимости в Flash, на mail.ru, опубликованной под видом «Взлом mini.games.mail.ru BETA версия»(В настоящее время закрыта), и была растиражирована по всему интернету скрипткиддерами, и даже продавалась за деньги: http://www.youtube.com/watch?v=XAK6-fj2Jzk http://www.youtube.com/watch?v=pAyHxuLW3LU http://pro-xaker.do.am/load/poleznye_materialy/internet/vzlom_mini_games_mail_ru_beta_versija/27-1-0-320 И т. д. Сейчас я расскажу, как это всё было найдено работало. С помощью Charles был полностью проанализирован весь трафик Flash приложения, После чего было выяснено, что Flash по HTTP протоколу запрашивал данные о цене различных бонусов к играм в формате JSON, - эти данные были подменены, а т. к. серверная часть доверяла клиентской можно было их использовать бесплатно. Изучение Flash приложения начинается именно с этапа мониторинга всех его соединений с сетью интернет, по HTTP,- Сharles, по другим протоколам, - Wireshark. Во время этого исследования выясняется в первую очередь, - что передаётся серверу, а что клиенту. Этого обычно хватает для общего представления о структуре приложения, однако при выполнении данного этапа следует учитыватть, что данные в передаваемом соединении могут быть зашифрованы. С помощью Charles можно видеть все обращения к скриптам, которые не отображаются на странице, к примеру с помощью него была найдена эта XSS(Не закрыта): PHP: http://forum.antichat.ru/showthread.php?p=2988185#post2988185 http://ads.depositfiles.com/p.php?v=5678%27%29; alert%28%27xss%27%29; $.get%28%275678 так что эту программу следует всегда держать на компьютере. Рассмотрим пример, найденный специально для этой статьи, демонстрирующий полезные возможности Charles. Сайт http://flashplayer.ru/ , - специализируется на публиковании Flash-игр, при этом зачастую у игр бывает рейтинг лист(High Score) на сайте разработчика(Почти у всех игр). Одну из таких игр, в которой используется «Защита разработанная автором» мы сейчас рассмотрим. Gold fishing ,- http://flashplayer.ru/play_6988.php . Открываем, играем, ждём момента когда нас попросят ввести ник для записи очков(После проигрыша), вводим, смотрим LOG Charles: PHP: POST /saveScore.aspx HTTP/1.1 Host: www.fupa.com User-Agent: Mozilla/5.0 *** Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Cookie: ASPSESSIONIDQASRTCCT=GMPJIDFDFPGKKKIBFEENCGHJ; ASP.NET_SessionId=mmsramukt2k4muvbogqeft55 Referer: http://flashplayer.ru/games/flash/6988_92442.swf Content-Type: application/x-www-form-urlencoded Content-Length: 96 onLoad=%5Btype%20Function%5D&hash=226b9d8ff5b7ae9619d8a74823fb6649&score=5237&name=AlexR&id=3913 success=true Как видим, количество очков и ник не шифруются, однако на сервер передаётся ещё какой то хэш, который должен сравниваться на серверной части по определённому алгоритму. Пытаемся переотправить запрос с нужным кол-вом очков(L Mouse Click->Edit), получаем в ответе success=false. Значит всё же придётся декомпилировать. Скачиваем(http://flashplayer.ru/games/flash/6988_92442.swf), открываем в Asdec. Как видим, игра написана на AS2: Немного покопавшись в коде, находим следующее(Использовалось сразу несколько декомпиляторов): PHP: //Object.registerClass("HighScores",com.novelgames.flashgames.highscoresAS2.HighScores); Push "com.novelgames.flashgames.highscoresAS2.HighScores" GetVariable Push "HighScores" 2 "Object" GetVariable Push "registerClass" CallMethod Pop Значит нам нужно искать код самого com.novelgames.flashgames.highscoresAS2, который как ни странно находиться на самом видном месте и состоит из: DoInitActionTag (153: __Packages.com.novelgames.flashgames.highscoresAS2.Config) DoInitActionTag (154: __Packages.com.novelgames.flashgames.highscoresAS2.Record) DoInitActionTag (155: __Packages.com.novelgames.flashgames.highscoresAS2.MD5) DoInitActionTag (80: __Packages.com.novelgames.flashgames.highscoresAS2.HighScores) Теперь у нас имеется 2 варианта: Внести необходимые изменения в P-Код, или Самому сгенерировать нужный хэш и отправить его на сервер. Мы пойдём вторым путём, хотя первый был немного проще. Иногда для генерации хэша при наличии исходных кодов будет удобнее переписать функцию на JS, однако перепись на PHP будет немного сложна, так как точность работы с малыми числами у JS выше и придётся использовать библиотеку BCMath, иначе результаты работы будут отличаться. Функция сохранения очков, как ни странно называется saveScore(): PHP: function saveScore() { var highScores = this; var __reg3 = new LoadVars(); var __reg2 = undefined; if (this.records == null) { this.finishedLoadingScoresAction = this.saveScore; this.showLoadingMessage = true; this.loadScores(); return undefined; } else { __reg2 = 0; while (__reg2 < this.records.length) { if (this.records[__reg2].score <= this.score) { break; } ++__reg2; } this.highScoresHighlightIndex = __reg2; this.records.splice(__reg2, 0, new com.novelgames.flashgames.highscoresAS2.Record(this.playerName, this.score)); this.records.splice(this.__maxNoOfScores); } __reg3.id = this.__gameID; __reg3.name = this.playerName; __reg3.score = this.score; __reg3.hash = com.novelgames.flashgames.highscoresAS2.MD5.md5("" + this.__gameID + this.playerName + this.score + this.__get__hashKey()); __reg3.onLoad = function (success) { highScores.finishedSavingScore(this, success); } ; __reg3.sendAndLoad(this.__saveScoreURL, __reg3, "POST"); this.showSavingScore(); } Нас интересует строка: PHP: com.novelgames.flashgames.highscoresAS2.MD5.md5("" + this.__gameID + this.playerName + this.score + this.__get__hashKey()); __gameID = 3913 //Похожих игр больше 4k playerName = 'Ret3' // Наш ник score = 1264364//Для первого места хватит Разведаем, что выдаёт this.__get__hashKey(): PHP: dynamic class com.novelgames.flashgames.highscoresAS2.HighScores extends mx.core.UIComponent { var __hashKey; function get hashKey() { return this.__hashKey; } } Осталось только узнать, что должно находиться в this.__hashKey; Опять же, как ни странно скорее всего это 'superwazooo': PHP: onClipEvent(construct) { backgroundAlpha = 0.5; backgroundColour = 11711154; dialogAlpha = 1; dialogBorderAlpha = 1; dialogBorderColour = 11711154; dialogBorderThickness = 5; dialogColour = 14277081; gameID = 0; hashKey = "superwazooo"; highScoresHighlightColour = 16711680; loadScoresAtStart = false; loadScoresURL = "http://www.fupa.com/loadScores.aspx"; maxNoOfScores = 50; nameSWFVariable = ""; saveScoreURL = "http://www.fupa.com/saveScore.aspx"; enabled = true; visible = true; minHeight = 0; minWidth = 0; } Будем проверять наши догадки, - Играем, набираем очки, получаем с помощью Charles md5. ID = 3913 Name = Asd654 Score = 1474 ------ md5 от Flash = 9f1785cd7c7d132e776792acb2b87bdf md5(id+name+score+'superwazooo') = 9f1785cd7c7d132e776792acb2b87bdf Осталось только отправить нужный нам запрос, но на этот раз мы будем использовать хэш 7062398f7b519d9b186d59eb8f7a3741. Результат: Нам всё же удалось занять первое место.
VI. BODY 2 А сейчас я хотел бы опять перейти к неприступным играм на mail.ru, о которых в дальнейшем будет сказано ещё очень много и рассказать о назначении плагина FlashFireBug, предназначенного для AS3, который мы так же будем часто использовать. Игра «Покер на костях». Покер на костях — азартная игра в кости. В неё могут играть от двух человек и более, оптимальное число игроков*— четыре. Для игры используют 5 шестигранных кубиков с числовыми достоинствами от 1 до 6. Все кости выбрасываются одновременно. Цель игры*— набирать очки за выполнение определённых комбинаций. В варианте приведённом на mail.ru бросать кости можно три раза, при этом часть костей можно сохранять, и иметься возможность играть в блиц. Конечно в этой игре многое зависит от вероятности, однако игра есть игра, и нам нужно найти способ в неё выигрывать. Следуя теории вероятности, шанс сохранить к концу раунда 5 костей одного достоинства при 3 бросках значительно меньше чем при >3 бросках, а если мы сможем манипулировать выпадающими значением(1-6), мы будем выигрывать всегда, за исключением случая возникновения аналогичного нечестного игрока, который возможно сможет набрать кол-во очков, превосходящее возможное, а именно число (1 * 5) + (2 * 5) + (3 * 5) + (4 * 5) + (5 * 5) + (6 * 5) + (6 * 5) + (6 * 5) + (6 * 5) + 50 + 20 + 30 = 295 Перейдём от теории покера к самой игре. Среднестатистическая партия в покер на костях. Запускаем FlashFireBug: Спешу вас обрадовать - интерфейс у плагина довольно простой и удобный, в главном разделе окна вы можете путешествовать по дереву элементов интерфейсов и редактировать параметры отдельных элементов, хотя не так хорошо, как это реализовано в De Monster Debugger. Иметься возможность выбора элемента щелчком мыши по нему. На сайте разработчика можно купить Pro версию. Как видим, мы можем изменять любой элемент интерфейса, в том числе и его параметры. Нас интересует элемент SmallCup, кнопка при нажатии на которую происходит бросок оставленных костей, а точнее её Bool свойство visible, отвечающие за видимость. А что если на сервере не проверяется кол-во бросков? Надо бы проверить, - бросаем кости 3 раза, вновь активируем кнопку и нажимаем на неё. И действительно, серверная часть не проверяет количество — теперь мы можем бросать кости неограниченное число раз, и выбрасывать любую нужную комбинацию. Теперь всегда можно набирать 295 очков, оставив далеко позади любого честного человека. А что, если игрок играющий против нас, каким то способом наберёт 295 очков, а вы — меньше, так как время на бросок ограничено, а нужные кости могут и не выпасть. А если он наберёт больше 295 очков? Невозможно, скажите вы? Для нас нет ничего невозможного В большинстве игр работает очень простой способ проверки поступающих вам данных. Перед их получением вы отключаете сетевое соединение, и пытаетесь их получить. Если они пришли, значит они формируются на вашей стороне, или изначально там хранятся. Пробуем... Перед броском костей выполняем: Code: sudo ifconfig eth0 down Бросаем... Значения костей выпадают(Как и при повторном броске), - значит нам нужно всего лишь их подменить, а заодно проверить возможность хранения кости числа больше 6. В файле dice-r1.swf, найденном через Charles храниться любезно предоставленный разработчиками класс dice и package diceClasses где скорее всего находиться основная часть кода работы с костями, а именно: Функция проверки на комбинацию: PHP: public static function getAvailableCombos(arg1:Array, arg2:Array):Array { var loc2:*; loc2 = null; var loc3:*; loc3 = 0; var loc4:*; loc4 = false; var loc5:*; loc5 = null; var loc6:*; loc6 = 0; var loc1:*; loc1 = new Array(12); diceClasses.rules.Rules.enNullArray(loc1); loc3 = 0; while (loc3 < 6) { if (arg2[loc3] == -1) { loc2 = count(arg1, loc3 + 1); loc1[loc3] = loc2.count * (loc3 + 1); } ++loc3; } if (arg2[6] == -1) { loc4 = false; loc3 = 0; while (loc3 < 6) { loc2 = count(arg1, loc3 + 1); if (loc2.count >= 4) { loc4 = true; break; } ++loc3; } loc1[6] = loc4 ? loc2.count * (loc3 + 1) + loc2.restSum : 0; } if (arg2[7] == -1) { loc4 = false; loc3 = 0; while (loc3 < 6) { loc2 = count(arg1, loc3 + 1); if (loc2.count == 3 && loc2.restArr[0] == loc2.restArr[1]) { loc4 = true; break; } ++loc3; } loc1[7] = loc4 ? loc2.count * (loc3 + 1) + loc2.restSum : 0; } if (arg2[8] == -1) { loc4 = false; if (!(arg1.indexOf(1) == -1) && !(arg1.indexOf(2) == -1) && !(arg1.indexOf(3) == -1) && !(arg1.indexOf(4) == -1) || !(arg1.indexOf(2) == -1) && !(arg1.indexOf(3) == -1) && !(arg1.indexOf(4) == -1) && !(arg1.indexOf(5) == -1) || !(arg1.indexOf(3) == -1) && !(arg1.indexOf(4) == -1) && !(arg1.indexOf(5) == -1) && !(arg1.indexOf(6) == -1)) { loc4 = true; } loc1[8] = loc4 ? 25 : 0; } if (arg2[9] == -1) { loc4 = true; loc5 = arg1.concat(); loc5.sort(Array.NUMERIC); loc3 = 1; while (loc3 < 5) { if (loc5[loc3] != loc5[(loc3 - 1)] + 1) { loc4 = false; break; } ++loc3; } loc1[9] = loc4 ? 30 : 0; } if (arg2[10] == -1) { loc4 = false; loc3 = 0; while (loc3 < 6) { loc2 = count(arg1, loc3 + 1); if (loc2.count == 5) { loc4 = true; break; } ++loc3; } loc1[10] = loc4 ? 50 : 0; } if (arg2[11] == -1) { loc6 = 0; loc3 = 0; while (loc3 < 5) { loc6 = loc6 + arg1[loc3]; ++loc3; } loc1[11] = loc6; } return loc1; } PHP: private static function count(combos:Array, combos:int):Object { var loc1:*; loc1 = 0; var loc2:*; loc2 = 0; var loc4:*; loc4 = 0; var loc3:*; loc3 = []; var loc5:*; loc5 = 0; var loc6:*; loc6 = combos; for each (loc4 in loc6) { if (loc4 == combos) { ++loc1; continue; } loc2 = loc2 + loc4; loc3.push(loc4); } return {"count":loc1, "restSum":loc2, "restArr":loc3}; Класс Cup, в котором находиться очень интересная строка(Можете проверить это сами): PHP: public class Cup extends mg.display.ReplacingContainer { *** public const helperTxt:String="Чашка с г*вном"; *** } Класс DiceConfig, который нам обязательно понадобиться: PHP: package diceClasses { public class DiceConfig extends Object { public function DiceConfig() { super();//Уже не раз встречаемся с различными super return; } { TIMER_PER_MOVE = 60;//время INTERROUND_DELAY = 1500; } public static const MAX_THROWS:int=3;//Количество бросков public static const MAX_SLOTS:int=5; public static const COMBO_COUNT:int=12; public static var TIMER_PER_MOVE:int=60; public static var TEST:Boolean; public static var INTERROUND_DELAY:int=1500; } } И его P-код: PHP: getlocal_0 pushscope debug 1 "TIMER_PER_MOVE" 0 3 findproperty m[474]"TIMER_PER_MOVE" pushbyte 60 setproperty m[474]"TIMER_PER_MOVE" debug 1 "INTERROUND_DELAY" 1 4 findproperty m[476]"INTERROUND_DELAY" pushshort 1500 setproperty m[476]"INTERROUND_DELAY" debug 1 "TEST" 2 5 debug 1 "MAX_SLOTS" 3 6 findproperty m[477]"MAX_SLOTS" pushbyte 5 initproperty m[477]"MAX_SLOTS" debug 1 "MAX_THROWS" 1 4 findproperty m[473]"MAX_THROWS" pushbyte 100 initproperty m[473]"MAX_THROWS" debug 1 "COMBO_COUNT" 5 8 findproperty m[478]"COMBO_COUNT" pushbyte 12 initproperty m[478]"COMBO_COUNT" returnvoid Как видите, мы подменили MAX_THROWS с 3 на 100, при поставлении больших чисел возможно добавление отрицательного знака, и у вас будет только одна попытка. Сохраняем.... Для подмены текстовых данных на странице можно использовать использовать Charles, и его функцию BreakPoints, позволяющую подменить пакет с данными к серверу и от сервера: Однако подменять файл таким способом не очень удобно, поэтому мы будем использовать его же функцию Map Local, которая позволяет указать файл на сервере и на локальном диске и автоматически подменять его: Всё, теперь для броска костей в пределах 100 нам не нужен FlashFireBug. А с функцией генерацией чисел вам предлагается поработать самостоятельно, - в этой статье я это затрагивать не буду, т. к. алгоритм действий очень похожий и игра настолько дырявая, что подобных багов можно расписать ещё очень много. VII. End Ну вот собственно первая часть подходит к концу. Почему же я не написал первую и вторую часть одной частью — различных способов и хитростей много, расписать за дин раз это невозможно, да и примеров мало, а без них статья была бы неинтересной. Так же кто то может возразить, - Для чего заносить это в статью, если это было известно и раньше? Отвечаю: Статей с подобным материалом на русском языке я не видел. До момента выхода второй части вам предоставляется возможность поиска багов в вашем любимом приложении, достаточно лишь отправить мне в ПМ ссылку, или написать в теме, что более предпочтительно. Часть этих приложений войдёт во вторую статью в качестве примеров. (с) XAMEHA, 2012. На Mail.ru было отправлено письмо с списком указанных багов.