Показать сообщение отдельно

  #2  
Старый 25.06.2017, 00:20
KAPTOHHbIu
Guest
Сообщений: n/a
Провел на форуме:
3832

Репутация: 0
По умолчанию

Тема провисела на форуме 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 не работает. Но какая?

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

Требуется ваша помощь.
 
Ответить с цитированием