Что такое SQL инъекцию сегодня наверное знает каждый второй ребенок. Error-Based — уже менее знакомый термин, но все же так же прост для понимания.
На всякий случай попробую объяснить. В некоторых ситуациях инъекция происходит в запросе который непосредственно не выводит никаких данных на страницу, либо же вообще никак не влияет на вывод. И если в первом случае данные из базы можно извлечь относительно просто, используя IF
, косвенно влияя на вывод страницы, и тем самым прибегнув к бинарному поиску. То вот во втором случае — все очень грустно, бинарный поиск, как правило, основывался на конструкции SLEEP
и замере времени ответа, что давало огромные задержки на вывод данных через эту инъекцию.
Следующей вехой в развитии этой атаки стал вектор Error-Based. Он основывается на выводе информации в тексте ошибки выполнения запроса. Как вы понимаете, для этого нужен прямой вывод текста ошибки на саму страницу. Да я согласен, это бывает не часто, и вообще за вывод ошибок на продакшене нужно жестоко карать. Но если вам повезло, то это поможет существенно сократить время атаки.
Duplicate entry
Наверное это один из самых популярных векторов атаки. Его предложил некто Qwazar еще в лохматые года. Выглядит он вот так:
SELECT COUNT(*) FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3)x GROUP BY CONCAT(MID([YOUR_QUERY], 1, 63), FLOOR(RAND(0)*2))
Потом этот способ дорабатывали все кому не лень (забегу немного вперед, в т.ч. и я), в итоге самый оптимальный и короткий запрос на сегодняшний день выглядит вот так:
SELECT COUNT(*) FROM (SELECT 1 UNION SELECT 2)x GROUP BY MID([YOUR_QUERY], FLOOR(RAND(33)*2), 64)
Так например, такой запрос:
SELECT COUNT(*) FROM (SELECT 1 UNION SELECT 2)x GROUP BY MID(VERSION(), FLOOR(RAND(33)*2), 64)
Выведет вот такую вот ошибку:
Duplicate entry '5.5.25-log' for key 'group_key'
Как видно — мы смогли передать в текст ошибки нужные нам данные, что существенно ускорит нашу атаку в дальнейшем. Ограничение — за один запрос выведется не более 64 символов.
Ошибка переполнения типа данных
Подробнее здесь. Буду краток, вектор выглядит вот так:
SELECT (i IS NOT NULL) - -9223372036854775808 FROM (SELECT ([YOUR_QUERY])i)a
Пример ошибки:
BIGINT value is out of range in '(('5.5.25-log' is not null) - -(9223372036854775808))'
Данный способ покруче предыдущего так как позволяет вывести аж 475 символов вместо 64, но говорят что работает не на всех версиях MySQL. Проверить это у меня возможности нет, поэтому оставлю это на совести авторов. По крайней мере на версии 5.5 это работает точно.
Еще похожая вариация:
SELECT !(SELECT * FROM(SELECT USER())x)-~0
Это выдаст вот такую ошибку:
'((not((select 'root@localhost' from dual))) - ~(0))'
Гео-функции
Появились только в MySQL >= 5.7.5
SELECT ST_LatFromGeoHash(VERSION()); //Incorrect geohash value: '5.7.6-m16-log' for function ST_LATFROMGEOHASH SELECT ST_LongFromGeoHash(VERSION()); //Incorrect geohash value: '5.7.6-m16-log' for function ST_LONGFROMGEOHASH SELECT ST_PointFromGeoHash(VERSION(),0); //Incorrect geohash value: '5.7.6-m16-log' for function ST_POINTFROMGEOHASH
Удобно, но 5.7.5 — это большая редкость на сегодняшний день. Тут я это наверное привел только ради того чтобы предложить альтернативу, предыдущим техникам и разбавить статью. Вряд ли это кто то применит на практике.
Заключение
Основной акцент в статье был сделан на то почему работает «Duplicate key»-метод (ради того чтобы не потерять мой пост отсюда), т.к. этот метод порой вызывает огромное недоумение. Ну а в целом буду собирать здесь все известные мне методы данной атаки.
Благодарю за внимание.
Спасибо! Статья помогла понять как это работает.
Спасибо за детальное объяснение!
спасибо, я был глуп, но теперь все ясно