Проведение SQL инъекций в Oracle. [Введение] Последнее время при исследовании различных веб проектов на уязвимости, стал натыкаться на sql инъекции в Oracle. Хотя в настоящее время редко можно встретить использование этой СУБД в Веб программировании, но все-таки такое случается. Все исследования заканчивались простым обнаружением баги, что делать дальше было непонятно. В ходе поиска статьи, хорошо описывающей практические аспекты эксплуатации данной уязвимости в Oracle, такой как статьи cash и spyder, описывающих инъекции в MSSQL и PostgreSQL, найти не удалось. В результате поиска была найдена, только лишь серия статей k00p3r, причем полностью копипастнутых со сторонних источников и являющихся простым переводом, прочтение которых не давало ясного представления о проведении скулей в Oracle, т.к. статьи по сути имеют большой объем, носят теоретический характер, и по большей части содержат воду. В конечном итоге пришлось вспоминать институтские навыки работы с Oracle и перечитывать кучу разрозненной информации в интернет. В этой статье хотелось бы поделиться с вами тем, что мне удалось накопать по проведению sql injection в Oracle и постараться объединить это в одно целое. Ну и попытаться восполнить пробел, и дополнить серию статей cash и spyder. [Особенности 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 в тексте сообщения об ошибке, например: Code: [Macromedia][Oracle JDBC Driver][Oracle]ORA-00933: SQL command not properly ended Не всегда в тексте ошибки присутствует слово Oracle, например Code: Warning: OCIStmtExecute: ORA-01722: invalid number in [Подбор столбцов] Пусть ошибка присутствует в параметре id: Code: www.site.com/view.php?id=1’ Определение количества столбцов присутствующих в основном запросе происходит так же, как и в MySQL. Так как оператор UNION требует одинакового количества столбцов, как в основном запросе, так и в подзапросе нам нужно количество этих столбцов определить. При неправильном указании столбцов в подзапросе выводится стандартное сообщение об ошибке: Code: ORA-XXXXX: query block has incorrect number of result columns Для подбора столбцов существует 2 известных способа и хорошо описанных в статье spyder. Но приведу их еще раз, дабы читателю не бегать по статьям: 1. Простой перебор. Составим следующий запрос Code: www.site.com/view.php?id=-1+union+select+null+from+sys.dual-- Если ошибка появилась, увеличиваем количество столбцов на один Code: www.site.com/view.php?id=-1+union+select+null, null+from+sys.dual-- и так пока не исчезнет ошибка. 2. Использование оператора ORDER BY Второй способ намного быстрее и приятнее, если количество столбцов достаточно большое. Составим следующий запрос Code: www.site.com/view.php?id=-1+order+by+1-- если ошибки нет, значит столбцов 1 или более 1 Code: www.site.com/view.php?id=-1+order+by+99999-- При таком запросе должна появиться ошибка, что означает столбцов меньше 99999. Далее таким же образом сужаем границы выбранного интервала слева и справа и в конечном итоге определяем реальное количество столбцов в основном запросе. [Определение принтабельных столбцов] Допустим, мы определили точное количество столбцов в основном запросе, предположим их 4. Code: www.site.com/view.php?id=-1+union+select+null, null, null, null+from+sys.dual-- Теперь нам необходимо определить те столбцы, которые выводятся на страницу. Обычно в выводе участвуют столбцы с типами данных int,char и data. Нам будет достаточно принтабильных столбцов с типами int и char, их и будем искать. Как было отмечено ранее, Oracle не осуществляет автоматического приведения типов в подзапросе. Поэтому при попытке подстановки в какой либо столбец значения несоответствующего типа мы получим следующую ошибку несоответствия типов Code: ORA-XXXXX: expression must have same datatype as corresponding expression Далее мы начинаем составлять запросы, поочередно заменяя каждый столбец на любое число Code: www.site.com/view.php?id=-1+union+select+123, null, null, null+from+sys.dual-- .... Code: www.site.com/view.php?id=-1+union+select+null, 123, null, null+from+sys.dual-- Таким образом, мы выявим принтабельные столбцы с типом int. В том случае если мы получим ошибку несоответствия типов, мы можем воспользоваться функциями преобразования типов to_char(), to_date() и выявить принтабельные столбцы с типами char и data. Code: 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, то запрос на получение этих данных будет выглядеть следующим образом Code: www.site.com/view.php?id=-1+union+select+null, login, password, null+from+users+where+id=123-- Так же как и в MySQL, для удобства отображения и преодоления различных проблем с кодировками можно воспользоваться функциями concat(), to_char(). Для преодоления фильтрации кавычек или других необходимых символов, существует функция chr(). [Таблицы и столбцы] Если пользовательские таблицы нам неизвестны, то мы можем получить различную информацию из известных системных таблиц Oracle. Узнать имя пользователя, под которым работает интерфейс, а значит и вы, можно вызвав функции user или sys.login_user Code: 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, которые содержат все таблицы и их столбцы доступные пользователю. Вытаскиваем имена таблиц и столбцов: Code: www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.user_tables-- Code: 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. Но, к сожалению, составленные выше запросы выведут нам лишь по одной - первой записи из всей таблицы. Возникает непреодолимое желание воспользоваться оператором LIMIT, как в MySQL или в PostgreSQL. К огромному всеобщему разочарованию данный оператор не поддерживается в Oracle, и более того не имеет достойного эквивалента в виде другого оператора. “ВСЕ ПРОПАЛО!!!” – скажете вы. “НЕТ!!!” – отвечу я вам. Помучив изрядно google, я все-таки нашел возможность составить сложный запрос хоть как-то отдаленно реализующий смысловую нагрузку оператора LIMIT. К сожалению, не удалось восстановить его возможности в полном объеме. Code: www.site.com/view.php?id=-1+union+select+null, table_name, null, null+from+sys.user_tables+where+rownum+<=+5-- Таким образом, перебирая различное количество записей в выборке, мы можем посмотреть по очереди все имена таблиц. Туже самую конструкцию мы можем использовать при просмотре таблицы SYS.USER_TAB_COLUMNS, при получении всех имен столбцов доступных пользователю. Так же в Oracle существует понятие префикса объекта (таблица является объектом), который присутствует в названии или имени таблицы: ALL_ - все доступные пользователю (владельцем может и не быть), USER_ - объекты, чьим владельцем этот пользователь является. Следовательно, мы можем упростить себе задачу и вытащить имена только тех таблиц, к которым мы имеем доступ Code: 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. [Пароли] Если нам повезло и пользователь, под которым мы работаем с базой, имеет права sysdba, то мы можем получить хеши всех пользователей базы. Основное место хранения свертки пароля (хеш) - таблица словаря-справочника SYS.USER$. Над этой таблицей как базовой построена производная, SYS.DBA_USERS. Если в профиле пользователя включен параметр PASSWORD_REUSE_TIME, свертки пароля также хранятся в SYS.USER_HISTORY$. Достать хеши и имена пользователей можно вот так Code: 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. Последний блок результата переводится в знаки шестнадцатиричной арифметики и объявляется конечным результатом - сверткой. [Копирайты] При написании статьи использовались следующие материалы: Проведение SQL-Injection в PostgreSQL, статья Spyder, http://forum.antichat.ru/thread35599-oracle.html Проведение Инъекций в MSSQL сервер от Microsoft, статья cash, http://forum.antichat.ru/thread30501-mssql.html Как взломать парольную защиту Oracle или как ее обойти, статья Пржиялковского В., http://citforum.ru/database/oracle/passwd/ А так же пользовался документацией по Oracle 10i. [ЗЫ] В этой статье я попытался рассказать и показать практические аспекты проведения SQL инъекций в Oracle. Надеюсь кому нибудь пригодится. Критика, дополнения и замечания приветствуются в полном объеме, т.к. это моя первая статья. Хочу выразить благодарности cash и spyder, за их статьи, на примере которых я писал и учился. А так же Thanat0z за предварительную рецензию.
Имхо синтаксис SELECT в SQL ORACLE не поддерживает вывода результата запроса в файл или загрузки файлов, как например в MySQL.
Не видел ничего про sys.all_tables sys.all_tab_columns - V$session - user_objects - user from dual Про это всё тоже добавь, думаю лишним не будет. Кстати про создание своего акка в Оракле тоже не написано.
Об этом написано в разделе [Таблицы и столбцы], а вот про session, действительно забыл, обязательно дополню, спасибо что напомнил. По-поводу добавления акка, я вначале статьи, подчеркнул, что провожу анализ инъекций через SELECT. И его синтаксис не позволяет добавлять акк. И вообще я не уверен, что даже через INSERT или UPDATE возможно это провернуть, т.к. только через CREATE мона создавать юзверя и имхо в sys.dba_users инсертом не внесешь юзверя, если ошибаюсь - поправьте.
Манн от Elekt Создаём Аккаунт: CRATE USER name IDENTIFIED BY pass123 TEMPORARY TABLESPACE temp DEFAULT TABLESPACE users; GRANT CONNECT TO name; GRANT RESOURCE TO name;
Моя по ораклу статья ушла в болталку: https://forum.antichat.ru/thread16614-dual.html Там надо бы конечно все собрать во едино, но думаю на следующей неделе собирусь с силами и перепишу ее нормально. Хотя и ольше года ей уже... Теперь немного по твоей статье: Подзапросы и юнион это разные вещи. Юнион просто объединяет два запроса и называть один из них запросом, а другой подзапросом некорректно. Зато есть параметр rownum, что дает большую функциональность. Есть не только такие комментарии. Другие указаны в той статье. Пистапольство! Само собой в оракле это есть. В частности благодаря этому можно свои процедуры и функции вставить через скуль, а в них юзать сплойты, которые до сих пор бывают актуальны. Но это уже тема отдельной статьи. Тут можно было бы чуть подробнее расписать. Вьюхи и триггеры ИМХО не будут представлять большого интереса. Триггер может конечно представлять, если он, например, вставляте записи от другого юзера в недоступную обычному таблицу, но я не думаю, что это где-то реализовано, да и в таком случае можно вряд ли можно откопать что-то существенное. Ну в таком случае можно что угодно сделать, например добавить еще одного юзера с правами ДБА. Так как в статье ошибка по поводу использования ";", то юзер должен создаваться без всяких проблем. Также через V$session можно узнать времена подключения разных юзеров к БД и некоторые другие параметры. Но ИМХО если это скуль, то доступа к V$session не будет, а если и будет, то будет все засорено обычными пользователями сайта. Также следует уточнить, что по умолчанию пассы в оракле следующие: system:manager sys:change_on_install Привилегий у sys больше чем у system (правда я хз куда уж больше) и всякие нерадивые админы частенько о нем забывают. Еще есть scott:tiger, если мне не изменяет память, в честь кота создателя оракла, который есть по умолчанию и о котором тоже забывают многие и еще какие-то юзеры. Кому интересно, думаю не трудно найти в инете или дождаться, когда у меня руки дойдут для переписывания старой статьи. П.С. Че-то прям вспомнил как мне обидно было когда ту статью мою перенесли в болталку. Тогда решил больше не писать ничего из-за такого отношения...
Спасибо конечно за критику, но.... Согласен на все 100, просто для удобства разъяснения, не будешь же писать: "в первом запросе объединенным со вторым", можно запутать читателя Во-первых про энтот параметр у меня написано в разделе [таблицы и столбцы]!!! Во-вторых не надо вводить в заблуждение читателей, данный параметр не дает большей функциональности!!! Их вообще нельзя сравнивать, limit работает как с таблицей так и с выборкой, а numrow работает только с выборкой и является просто псевдостолбцом!!! А если уж сравнивать то параметр limit позволяет выбрать конкретное число строк из таблицы начиная с определенной, а параметр numrow только лишь количество строк. Для проведения инъекции достаточно и этих Дорогой друг не надо путать божий дар с яичницей!!! Разделитель запросов точка с запятой ";" присутствует только во всяких средствах разработки типа SQL*Plus или SQLNavigator, позволяющих разделять запросы, но только у себя на уровне приложения, естественно на уровне драйвера к самой СУБД они их сами разбивают на несколько запросов и проводят по-раздельности!!! Пробовали ли вы хоть раз составить запрос из нескольких разделенных точкой запятой операторов и выполнить это в приложении на java или php, не важно через какой интерфейс вы работаете (OCI, JDBC, ....), боюсь, что нет. В этом случае вы моментально получите сообщение об ошибке invalid character с указанием на ";"!!! Так же этот разделитель используется в процедурах PL\SQL, но ето совсем другая история и не относится к инъекции в SQL (имхо надо различать!). А если вы мне не верите вот вам пример живой скули с Oracle: Code: http://www.newsdesk.umd.edu/uniini/release.cfm?ArticleID=-1+union+select+1,null,null,null,sys.login_user+fro m+sys.dual-- попробуйте вставьте два запроса через точку с запятой и все мои слова подтвердятся Ошибки НЕТ! Не надо путать читателя!!! По остальным замечаниям претензий не имею, готов дополнить свою статью ЗЫ podkashey не обижайся, но я кажется догадываюсь почему перенесли твою статью в болталку ЗЗЫ Спасибо за ЗАМЕЧАНИЯ!
Вот тут находится список пользователей по умолчанию: логины, пароли, хэши паролей, краткое описание. почти 600 штук, не думал, что их ТАК много.
Введи rownum <=3 and rownum >=1 Это однострочный комментарий и он не закомментит оставшиеся строки. Про разделитель ; мне не хочется искать примеров, но во многих местах он работает. Скорее всего зависит от того как происходит связь БД с Веб. Как сказано выше, ошибка есть. ЗЫ Не обижайся, но только что ты кажется сел в лужу и то, что ты написал много слов про драйвера, средства разработки, интерфейсы никак не помогут обычному читателю, поэтому я стараюсь избегать таких слов. Хотя можно конечно во всяких нотациях расписать все комманды скуля и сказать думайте сами. ЗЗЫ Спасибо за попытку поспорить ЗЗЗЫ Че-то у меня снова отпало желание переписывать статью... Это к разным модификациям, веткам итд, то есть в реале штук 5 - 10 от силы будет. Сейчас смотрю на 8ом оракле: adams, blake, clark, jones, scott.
Это я писал не для обычного читателя а для тебя, надеясь что более полное объяснение с привидением примеров, в качестве док-ва, поможет тебе разобраться! Видимо не помогло, не вижу смысла дальше пытаться тебя переубедить А с твоей стороны кроме пустой болтовни и необоснованных утверждений я ничего так и не услышал. Я готов с радостью признавать свои ошибки и исправляться, но для етого должно быть четкое обоснование своих утверждений! ЗЫ Я же не виноват, что твою статью перенесли в болталку, не надо на мне срывать свое недовольство. Вместо пустых приперательств, выложи свою версию статьи и посмотрим что скажет народ!
Хорошо, назови пункты по которым ты со мной не согласен кроме точки с запятой и само собой вытекающего отсюда создания юзера. Позже приведу тебе пример скули, где проходит ; Можешь расставить плюсики и минусики напротив моих утверждений с обоснованием: 1. rownum как минимум равноценен limit, но вообще удобнее, так как можно вывести строки например через одну. 2. комментариев "--" не достаточно при скулях в оракле и в большинстве случаев надо использвать другие из-за многострочных запросов. 3. точка с запятой в некоторых случаях поддерживается, а в некоторых нет. Это основные пункты, по остальным не интересно спорить, так как они не принципиальны, малозначимы или вытекают из этих.
Честно говоря особо спорить здесь не почему, только личное мнение что где-то одно лучше, а где-то другое Собственно для проведения скулей одинаково удобны, имхо не понадобится выведение строк через одну Как показал мой прошлый пример и вообще если использовать union, то необходимо комментить только запрос в котором скуля, до остальных пофиг. Но опять имхо таких скулей больше Да и вообще по этому моменту спорить нет смысла, я согласен етсть другие коменты про них тоже надо написать. То есть ты согласен, что хотя бы в некоторых нет. Так что не надо было утверждать что поддерживается всегда. Но вообще с твоим перефразированным утверждением я согласен. При чем могу все таки предположить, что скорее всего возможно разделение запросов именно в процедурах PL/SQL и если уязвимость действительно в процедуре, то может быть возможно воспользоваться ;. Но могу поспорить, что именно в SQL запросах Oracle нет возможности использования ; обоснование данного утвержедния я отписывал выше. Имхо надо различать SQL и PL/SQL, и по инъекциям в процедуры в PL/SQL мона писать отдельную статью и как раз там описать возможность добавления пользователей и тд ЗЫ Не вижу смысла спорить дальше, у всех свои методы проведения инъекций, мои мне всегда помагали и я о них написал. На полный мануал я не претендую. Внес дополнения и изменения в связи с последнимими замечаниями и предложениями! ЗЗЫ С удовольствием посмотрю пример с использованием разделителя ; и добавлением пользователя
Запрос может быть в несколько строк. Это бред Уязвимость в создании процедры чтоле? А если в функции, то она вызывается, как и внутренняя функция. Процедура вызывается через бегин-енд, то есть в пл/скл, то есть там точно поддерживается ;. По поводу использования скл или пл скл. ИМХО на нормальных сайтах используется пл/скл, чтобы проводить единые транзакции. То есть вместо обычного запроса используется begin select ... end; то есть ; в инъекции применима. Вобщем все выяснили. С меня скуля с ; а с тебя пиво, если я ее предоставляю. Договорились ))
Имелось ввиду - уязвим параметр вставляемый в какой-то запрос в хранимой процедуре, соответственно на этапе выполнения процедуры, мы можем через уязвимый параметр сделать инъекцию в процедуру, а так как там поддерживается ; (я знаю что там как раз это поддерживается ) мы можем использовать разделение на несколько запросов и вставить свой. Да, но только в Pl/sql. Договорились, адназначна
Прочитал статью много не противоречий, в целом написанна грамотно. 1) rownum не когда не был аналогом лимит, согласен они похожи но сравнивать их нереально. 2) иногда их не надо исползывать вообще, коментарии используються для отброса дальнейшего запроса, и их всегда достаточно другое дело если используються сложные функции то ее можно просто закрыть или привети к нулевому значению. И какая разница сколько строк занимает скуль часто встречал очень длинный запрос со сравниванием сортировкой и так далее и в конце where=$a. 3); может не работать только из-за неправильно или умышленно построенной реализацей кода так, как в большинстве СуБД Строки запросов разделяються именно так, посмотрим банальный пример дампа.
прочитал и статью и далее следующий мега батл великих умов . Интрересно всё же узнать правильный ответ, можно ли коректно юзать";"? Сам пробовал на 2х сайтах, результат - ORA-00911: invalid character. Хотя большая вероятность, что просто не верно составлял запрос . Кста афтору +1
В снитаксисе Orale Запросы разделяються ; другой вопрос можно ли применять их в иньекциях. В MySQL запросы тоже разделяються ; но в иньекциях их нельзя применять, а оркл же иногда позваляет их применять.
[ cash ], тоже пива хочешь? [53x]Shadow, думаю ты не против, если мы с [ cash ] пивка попьем? Приведи примеры того, что можно сделать лимитом и нельзя rownum. Пример в пользу rownum я уже привел. гыгыгыы.... Пример в студию. Само собой сортировка должна быть не в подзапросе и не в одном из запросов, объединенных юнионом.... Хотя я не против, если ты тоже мне пивка поставишь вместо того чтобы признать ошибку.... )) Ты имеешь в виду например select my_func($a) from dual; и вместо $a подставить строку с инъекцией? Ну это уже перебор. На уровне того, если в паскале например мы создадим процедуру и туда вместо параметра подставим "15; exit" например. Вобщем само собой такого в оракле не будет. Если я конечно тебя правильно понял.