![]() |
Всем доброго дня!
В течении последнего полугода играю в одну не очень известную онлайн-игрушку на планшете. Попутно пытаюсь ее ломать то с одного боку, то с другого. Но каких-то успехов достиг только на пакетном уровне. К сожалению большинство переменных там защищены. Взлом в стиле ололо-репитов не канает. Дыры есть, но мало, особо не разгуляешся. А хочется гораздо большего. Поэтому пришел к вам, за советами. Итак, что уже достигнуто: 1. Обошел SSL-шифрование. Могу слушать трафик между игрой и клиентом. 2. Расковырял игровой клиент, выдрал оттуда алгоритм подписи пакетов. На его основе сделал тулзу чтоб подписывать свои собственные пакеты. Могу вклиниваться в процесс и менять значения переменных на лету. Либо самостоятельно формировать и отправлять на сервер любые пакеты. Сервер их принимает и обрабатывает. 3. Нашел несколько незащищенных переменных, подмена которых дает некоторое игровое преимущество. К сожалению возможности у этих дыр ограничены. 4. Собрал кое-какую информацию об игре. Сервер работает на CentOS, имеет Apache версии 2.2.15, клиент написан на С#. Запросы от клиента обрабатываются на сервере PHP скриптами. Думаю есть БД, но какая - не знаю. 5. Пытался проверить сервер на уязвимость Shellshock (Bashdoor). По моим скромным выводам результат отрицательный. Какие цели есть на данный момент. Найти любую уязвимость, которая откроет передо мной более широкие возможности. Хорошо бы по крайней мере один их пунктов: 1. Найти новые полезные дыры на пакетном уровне. Хотя за полгода я наверное уже все щели обнюхал. 2. Получить частичный или полный доступ к БД. Как минимум читать произвольные таблицы. Как максимум - редактировать их. 3. Получить доступ к исходникам серверной части игры. Как минимум заглянуть во внутренности скриптов. Как максимум - внести в них свои поправки. 4. Было бы хорошо залить шелл. Еще лучше - сделать это не привлекая внимания админов. 5. Получить доступ к админке (CP), FTP или SSH (мечты, мечты...) 6. Получить доступ еще к чему-нибудь полезному, может я о чем-то даже не подозреваю, а вы подскажете. Но оговорюсь что чужие аккаунты меня не интересуют. И гробить сервер или мешать его работе я тоже не собираюсь. Скорее наоборот, предпочитаю быть тише воды ниже травы. Какие ресурсы и опыт имеются: 1. Понимание самых базовых принципов работы приложений и серверов. На уровне начинающего. 2. Небольшой опыт программирования. Программирую методом топора, подпирая программы костылями со всех сторон. 3. Любительский опыт взлома. На 70% почерпнутый из разнообразных статей в сети, на 30% состоящий из личных шишек, пота и крови. На самом деле опыт не очень большой. Умею делать часть из того, чему учат в мануалах "для чайников" которыми пестрит рунет. 4. Терпение, время. Готовность курить мануалы с уровнем утомительности не превышающим мои психические возможности. "Войну и мир" о принципах работы с ассемблерным кодом читать не готов. Какие будут идеи? |
Тема провисела на форуме 2 суток, набрала 500 просмотров и 0 ответов. Куда подевались все гуру-хакеры?
Ладно, попробую задать более конкретный вопрос. Что имеем: Последние несколько дней я пытаюсь сделать игре SQL-инъекцию. Как я уже говорил, клиент обменивается с сервером HTTPS запросами. На сервер отправляются обыкновенные POST-запросы вида https://www.game.ru/public/api/scrip...ta1&var2=data2... В ответ приходит целая гора данных в формате JSON, основываясь на которых, клиент выдает картинку игровых действий (передвижение, битвы, игровой инвентарь ит.д.) Разумеется никаких html-страниц и форм нет и в помине. Но поскольку я могу слушать трафик напрямую, то и вмешиваться в него могу тоже напрямую. Следовательно - изменять переменные отправляемые на сервер так, как если бы я это делал в строке запроса GET. Я могу придать переменной любое значение, однако часть символов экранируется. А именно символы / (слэш), \ (обратный слэш) и "(двойная кавычка). Все остальные символы поступают на сервер без экранирования. По крайней мере символы ['],[`],[*],[:],[;],[&],[%],[$],[@],[?],[(],[)],[{],[}],[,],[.],[!],[-],[|],[=],[^],[#] можно передать в исходном виде. Однако SQL-инъекцию затрудняет то, что часть переменных защищена проверками на валидность, а другая часть, по видимому, в SQL-запросах не участвует. Но я таки отыскал одну переменную, через которую инъекция возможна. Как не удивительно, но это переменная uid (id игрока). Что работает: Предположим мы работаем с исходной переменной uid=99 Если привести ее к виду uid=99' получим ошибку 500 (Internal Server Error), т.е. ошибочный SQL-запрос который сервер выполнять откажется. Значение uid=99/* передать к сожалению нельзя из-за экранирования слэша. Значение uid=99-- будет обработано. Так же будет обработано: uid=99--+любой текст Будет обработано: uid=99+and+null-- Будет обработано: 99+and+null Будет обработано: 99+and+concat('1','2') Будет обработано: 99+and+version() Будет обработано: 99+and+@@version Приведет к небольшому зависанию и ошибке 504 Gateway Time-out: uid=99+or+1-- Ну еще бы, аккаунтов в игре зарегистрировано более 13 млн. Вот такая переменная затянет выполнение запроса на ~2300мс: uid=99+and+BENCHMARK(10000000,md5(current_date)) Обычно запрос выполняется за 5-15мс. Скорее всего есть возможность провести DOS атаку, но меня это не интересует. Что не работает (подводные камни): Проблема 1. Первая проблема состоит в том, что значение переменной uid используется не только в запросе к БД, но и каким-то образом связано с проверкой валидности игровой сессии. Всего в проверке сессии их учавствует три - uid (номер игрока), serverid (номер сервера) и sessionToken (ключ сессии). uid - всегда неизменный для отдельного игрока serverid - неизменен до тех пор пока мы играем на одном и том же сервере sessionToken -выдается каждый раз новый. Происходит это при входе в игру, либо при смене сервера. Предыдущий sessionToken при выдаче нового становится недействительным. Внешне он напоминает хеш md5. Если поменять хотя бы один символ в любой из этих переменных, получим обрабатываемую игровым движком ошибку "Ключ сессии неверный!". При этом, несмотря на то, что запрос к БД будет выполнен, обычный набор данных в JSON-формате PHP-скрипт нам не отправит. А если он их не отправит, то и результаты SQL-запроса вставлены никуда не будут... То есть не представляется возможным получить какую-либо пользу даже от успешного внедрения в запрос конструкции UNION SELECT... Как решить данную проблему я не понимаю и очень рассчитываю на вашу помощь. Проблема 2. Собственно, мне не удается узнать число столбцов между SELECT и FROM. Я пытался это сделать вот так: uid=99+union+select+null uid=99+union+select+null,null uid=99+union+select+null,null,null ... и т.д. К сожалению сервер все время возвращает ошибку 500. То есть запрос не выполняется. Предположим это может быть просто результатом неверного числа добавленный мной null. Я утомился после 30-го по счету. Конечно, их может быть 100 или 300. Ну да черт с ним. В случае чего я пару часов своего времени на перебор убить могу. Но что если сервер отказывается принимать саму конструкцию select+null? Или оператор union? Или еще что-нибудь в синтаксисе моего запроса? У меня есть основания полагать что это так, поскольку переменная uid=99; (добавлена точка с запятой) сервером обрабатывается. В то время как uid=99;+select+null приводит к ошибке 500, хотя после точки с запятой количество нуль-значений в запросе никак не должно влиять на его валидность. Ведь мы не объединяем результат с предыдущим, а делаем новый независимый запрос. Почему конструкция uid=99;+select+null не работает? Я не знаю какая именно СУБД там находится. Но поскольку сервер на CentOS думаю я не ошибусь если предположу что это MySQL, причем с версией никак не ниже 4.* Мне точно известно что Apache имеет версию 2.2.15, а PHP версию 5.4.11. По-моему крайне маловероятно, что вместе с ними стали устанавливать бы такую древность как MySQL 3.* А современные версии MySQL поддерживают, как UNION, так и расщепление запросов оператором ; (точка с запятой). Следовательно, существует какая-то другая причина, по которой uid=99;+select+null не работает. Но какая? Наверно ответ на вопрос элементарный. Но я к сожалению ничего не смог нагуглить, а чтобы догадаться самому - не хватает опыта. Требуется ваша помощь. |
Возможно слепая инъекция. Пробуй так:
Код:
Code: |
Не понял как ты хочеш узнать число стлобцов:
Цитата:
Цитата:
Цитата:
|
Цитата:
|
Цитата:
Поскольку никаких данных, кроме злосчастной ошибки о неверном ключе сессии, скрипт не выводит - пришлось в качестве критерия угадывания использовать HTTP ошибку 504. Постепенно по одной цифре узнал версию базы данных: MySQL 5.6.21 Использовал такие запросы: Код:
Code:После чего переходил к следующей цифре. Самое интересное, что после каждого такого угадывания сервер переставал отвечать на мои запросы на 10 минут, даже самые безобидные. Через 10 мин все возвращалось на круги своя. Причину такого поведения не понимаю. С одной стороны запрос возвращает 13 миллионов строк, это серьезная нагрузка на сервер. Но с другой сам по себе сервер не уходил в даун. Я проверял это входя в игру обычным способом, через клиент. Что ж, еще раз спасибо. Ссылка тоже полезная, я пока прочитал не все, так что когда закончу - отпишусь о результатах. |
Цитата:
Дело в том, что игровой движок сперва выполняет SQL-запрос и только после этого проверяет игровую сессию на валидность. Я бы на месте разработчиков игры сделал с точностью до наоборот - сперва проверял нужно ли вообще делать запрос к БД, и только потом бы его делал. Но они решили иначе В результате получаем следующую картину: Когда запрос к БД успешно выполнен - я получаю движковую ошибку "Ключ сессии неверный!", ведь для инъекции мне волей-неволей пришлось изменить значение uid. Если же запрос к БД завершается ошибкой (например при добавлении символа кавычки), я получаю HTTP ошибку с кодом 500. Таким образом, постепенно добавляя к запросу uid=99+union+select+null новые и новыеnull через запятую, я буду получать ошибку 500 до тех пор пока количество null не станет равнымм количеству столбцов. В этом случае я должен буду получить сообщение о неверном ключе сессии. В теории должен, на практике пока ни разу не получил... Цитата:
У меня бывает всего 4 ситуации: 1. Если переменная uid находится в девственно неприкосновенном виде, я получаю: JSON-текст, содержащий данные из БД. 2. Если переменная uid была изменена и SQL-запрос был выполнен, я получаю: ошибку движка throwException("Ключ сессии неверный!"); 3. Если переменная uid была изменена и SQL-запрос НЕ был выполнен (например добавлен символ кавычки), я получаю: HTTP 500 Internal Server Error 4. Если переменная uid была изменена, SQL-запрос был выполнен, при этом он попытался вернуть всю таблицу целиком (в ней 13млн. строк), я получаю: HTTP504 Gateway Time-out Других ситуаций не бывает. В идеале я хочу получить 5-тую ситуацию, когда uid была изменена, SQL-запрос был выполнен, и я получаю JSON-текст, с данными из запроса. Но пока не получается... В этом и заключается Проблема №1, описанная во втором посте данной темы. А почему символ ; должен удаляться перед подачей в БД? Ты думаешь разработчики сделали специальную функцию для этого? |
Версию скуля я узнал просто в виде эксперимента.
Все-таки я впервые в жизни слепую инъекцию делал, хотел понять как она работает. Юзера я хочу и сам, но никак не могу сообразить, как его выцепить из БД. Я ведь даже имен таблиц не знаю. Наверно потому что спать пора и соображалка туго работает... Завтра продолжу. |
Используй and, а не or.
Для, простого, быстрого перебора: [CODE] Code: id=99 and ascii(substring(version(),1,1)) > 100 -- false id=99 and ascii(substring(version(),1,1)) > 50 -- true id=99 and ascii(substring(version(),1,1)) > 55 -- false id=99 and ascii(substring(version(),1,1)) |
2crlf, спасибо, ваши советы бессценны! Попробую применить все, что смогу.
Цитата:
Да, and удобнее. Но если я буду использовать and- я получу throwException("Ключ сессии неверный!"); в не зависимости от результатов запроса. Я писал об этом ранее. Цитата:
К сожалению совсем быстрым он не выйдет, т.к. ошибка 504, на которую я ориентируюсь, помимо прочего приводит еще и к отказу сервера на 10 минут. Угадали символ - ждем 10 минут пока сервер отвиснет, угадали еще один - опять 10 минут ждем. Если я попробую автоматизировать этот процесс, рискую привлечь нежелательное внимание админов. все-таки столь большая нагрузка на сервер - плохо. Но другого выхода пока не вижу. Вот если б заставить работать оператор LIMIT... но он работать отказывается... Цитата:
Код:
Code:Такое может быть, если инъекция производится не в хвост а в середину запроса (я ведь не знаю какой он там). Но это предположение опровергается тем, что запрос id=99; обрабатывается корректно. Кроме того, я, на всякий случай, отбрасываю ввероятный хвост при помощи --, но и это не помогает. Откуда растут ноги у проблемы понять не могу. |
Можно использовать time based варианты и обойтись без or, там вывод вообще не нужен.
Так же, стоит попробовать конструкцию с and, без использования комментария. Возможно, дальше идёт важная часть запроса и выборка проходит неправильно, что, по дальнейшей логике сценария, приводит к ошибке. Либо, нужно каким-то образом попытаться достроить запрос. Как вариант, считать вслепую, таким образом: Код:
Code: |
2crlf, спасибо, time based работает! Даже не знал что такое возможно.
Вы, как всегда, по делу советуете) Побольше бы таких людей! Появился кое-какой прогресс во взломе. Вместе с новыми успехами появились и новые проблемы, требующие решения. Подробности расскажу позже, когда появится время. Сейчас вынужден заняться другими делами. |
После длительного перерыва вернулся ко взлому.
Достиг следующих успехов: 1.Методом blind-инъекции + брутфорса нащупал в базе данных названия четырех таблиц. Внутри этих таблиц нащупал 23 названия столбцов. 2.С помощью того же блайнда наловчился двоичным перебором ASCII кодов, вытаскивать данные из БД. То есть любые данные из любого столбца любой таблицы, названия которых мне известны. 3.Наконец-то обошел злосчастную проблему с ключом сессии. Нашел еще одну уязвимую переменную в другом скрипте. Инъекция в данную переменную позволяет получать php и скуль-ошибки. А это уже делает иньекцию не такой слепой, как до сих пор. Я даже почерпнул из одного мануала запрос, благодаря которому можно получать данные из БД прямо внутри текста ошибок! Например отправляю: Код:
Code:Код:
Code:Брутфорсом я нащупал едва ли сотую часть БД. И мне по зарез нужны названия других таблиц/столбцов. Но я никак не могу извлечь их напрямую из information_schema. Когда, описанным выше способом, я пытаюсь вытащить из базы данные: Код:
Code:Код:
Code:Проблема даже не в том, что точка фильтруется. Просто символ точки, почему-то, срабатывает как комментарий. Причем комментарий с довольно странными свойствами. Допустим в исходном виде без инъекции var=99 Запрос: var=99 -- abra cadabra comment(скрипт выполнится корректно) Запрос: var=99 abra cadabra comment(приводит к ошибке) Код:
Code:Код:
Code:Более того запросы вида: var=99 -- .abra cadabra comment приведет к такой же ошибке. То есть точка (.) каким-то образом работает даже в закомментированном виде уже после двух дефисов (--) ! Что еще более удивительно, по заголовкам функций в apache-ошибках можно обнаружить, что в одну из функций попало значение нашей строковой переменной varдополненное еще двумя символами, а именно '99 -- .abra cadabra comment.7' Кстати происхождение числа 7 мне известно. Это номер игрового сервера, который был передан в том же самом HTTP-запросе, однако в совсем другой переменной, никаким модификациям не подвергавшейся. То есть, если я все правильно понимаю, на каком-то этапе обработки данных моя точка спровоцировала конкатенацию строк. Причем произошло это в какой-то другой среде, еще до того, как строка попала в среду MySQL и запрос к БД был выполнен. В пользу этого говорит так же и тот факт, что точка генерирует ошибку даже после двойного дефиса. Хотя может я ошибаюсь и конкатенация изначально была задумана движком. Поправьте если не прав. После этого я попробовал сделать тот же самый запрос, но с двумя точками. var=99 -- ..abra cadabra comment Запрос был обработан и выполнен без ошибок! var=99 ..abra cadabra comment Привел так же привел к корректной обработке без ошибок. То же самое верно для запросов с любым количеством точек от 2-х штук. Независимо от наличия или отсутствия комментариев SQL. Самое главное чтобы за самой первой точкой, следовала еще одна, причем вплотную. При этом все, что следует за двойной точкой будет в SQL-запросе отсечено, как если бы точки были однострочным комментарием. var=99 . .abra cadabra comment Если между точками вставить пробел или любой другой символ ошибка снова появится. Резюмируя проблему: Если одинарную точку, либо точку с другими символами после нее, поставить ДО инъекции, получим вышеуказанную ошибку "host config can not be empty!". Работа скрипта будет прервана так же до выполнения инъекции. Если одинарную точку, либо точку с другими символами после нее, поставить ПОСЛЕ инъекции, то сперва будет выполнена инъекция. Если инъекция привела к SQL-ошибке, получим SQL-ошибку. Если инъекция выполнена без SQL-ошибок - получим "host config can not be empty!" Если одинарную точку, либо точку с другими символами после нее, поставить ВНУТРИ инъекции (например при обращении к information_schema.tables), то вся инъекция после точки будет отсечена. Соответственно мы получим SQL-ошибку "... error in your SQL syntax ... near '...огрызок нашей инъекции до точки' at line 1" Если поставить две точки подряд в любом месте, они сработают как однострочный комментарий. Вопрос: Как получить доступ к information_scherma? Сделать это можно либо разобравшись в свойствах этой загадочной точки и заставить ее работать на нас. Что это за странный баг и с чем его едят? Либо обратится к information_scherma каким-то обходным путем, не используя точек в запросе. Существует ли такой способ? Если да, то как? Оговорюсь сразу что функция char() и HEX-строки здесь не помогут, я пробовал. Они работают со строковыми параметрами в операциях сравнения после WHERE, однако не годятся для обращения к именам таблиц в операторе FROM. Очень надеюсь на вашу помощь) |
Цитата:
Цитата:
|
Цитата:
Если точка внутри запроса - получаем ошибку 500. Если точка после запроса получаем ошибку "Ключ сессии неверный!", о которой я писал еще давно. Что отнюдь не означает отсутствие ошибки "host config can not be empty!". Единственная разница в том, что точка до запроса работает как комментарий, даже в количестве 1 шт (две точки подряд ставить не обязательно). Считаете, что есть шансы найти другой уязвимый параметр, в котором проблем с точкой не будет? Цитата:
Возможно я неверно указываю путь до файлов. Затрудняюсь определить правильный. А может быть косячу где-то еще. По правде сказать, я почти не уделял этому времени - попробовал пару раз, а затем переключился на другие задачи. Но возможно стоит углубится в изучение данного вопроса. Буду благодарен за какой-нибудь мануал по файлам. А вообще - чтение локальных файлов одна из основных целей атаки. Мне интересно почитать их содержимое и так. |
load_file('/etc/passwd') или load_file(0x2f6574632f706173737764)
|
Цитата:
Результат - NULL |
А чё , права есть разве? Я чему не собираюсь читать, слишком много букв . Я вот не пойму, автору делать нечего что ли, или решил цветных тролить тонко? Если так, то не тонко Нифига
|
|
Цитата:
А на основании чего вы решили, что я троль? Цитата:
Я в ручную брутил. Вернее составил собственный word-лист из 600 слов, на основе моих субъективных предположений о том, как могут называться таблицы. Добавил к этому вордлисту десяток префиксов и постфиксов, тоже взятых из головы. Получилось около 10.000 слов. Брут по данному листу, нашел четыре таблицы и два десятка столбцов внутри них. SQLMap брутит намного эффективнее? |
чувак ну вруби и узнаешь,или будешь по каждому пустяку вопросы задавать,запустил sqlmap перебрал и узнал.
|
Цитата:
nknown erruplicate entry 'Vasya_Pupkin1990@mail.ru1' for key 'group_key'" им и вытащищ все данные, тебе только узнать имена таблиц и столбцы |
Скачал SQLMap. Вытащил из него word-лист common-table.txt(длина 3350 слов)
Пробрутил. Новых таблиц не нашлось. Просмотрел глазами. В списке названия таблиц из популярных движков и банальщина вроде users, dataит.д. К сожалению движок не типовой. Предполагаю, что разработчики писали его сами, с нуля. Нашлись только таблицы serverи user, но их я и сам уже давно нашел. Цитата:
Пока что никаких результатов. Но даже если пару новых таблиц найдется - это не та эффективность, которой я был бы доволен. Нужны имена всех таблиц/столбцов базы, ну или по крайней мере значительная их часть. Брутом этого можно достичь: - либо полным перебором (за пару сотен лет) - либо нужен какой-то супер-крутой вордлист, заточенный именно под игровые базы данных (но я такого найти не смог) - либо можно как-то еще оптимизировать процесс, возможно я чего-то не знаю |
Цитата:
Цитата:
А што ты хотел хак дело нудное у тебя дайнэмик эскуэль тоже не разрешен? попробуй тестовый запрос SET @q='select(12)';prepare i from @q;execute i тогда можно было бы обойти точку |
Цитата:
Цитата:
|
Цитата:
user() на локальном: adminname@localhost version() на локальном: 5.5.52-38.3 user() на целевом: gameuser@10.11.28.1221 version() на целевом: 5.6.21ucloudrel1-log Цитата:
Работает уже трое суток непрерывно. Проверено 187 тыс слов, ни одного совпадения, слова на букву А еще не закончились. Неделей тут и не пахнет. Быстрее сервер на запросы отвечать не хочет. Могу распаралелить брут на несколько потоков, хоть на 10, хоть на 20. Но опасаюсь привлечь внимание админов. Однажды уже пытался сделать нечто подобное - закончилось глухим зависанием сервера. Был большой переполох на игровом форуме. Хорошо еще, что не нашли виноватого. Цитата:
Но по-быстрому попробовал предложенные вами команды. Локалхост: При вводе команд - угрожающие подчеркивания красными волнистыми линиями и ошибка unrecognized statement type. Но не смотря на это, выполняется конструкция успешно. Возвращает два пустых результата и число 12 в третьем: Цитата:
Покачто не могу заставить работать разделение запросов при помощи точки с запятой. Еще давно пытался выполнить апдейт после селекта. Ошибка "... error in your SQL syntax ... near 'все что после точки с запятой' at line 1" Возможно с этим что-то можно сделать, но я пока не разобрался в причинах ошибки. Без точки с запятой внедрить эту фичу не получится? |
Цитата:
|
Цитата:
|
Чувак, как сервак похачишь, напиши статью. То что ты делаешь - это круто!!!
|
А что за игра?
|
| Время: 14:39 |