0x01 前言
Java里面常见的数据库连接方式有三种,分别是JDBC,Mybatis,和Hibernate。
0x02 JDBC注入场景
很早之前的Javaweb都是用JDBC的方式连接数据库然后去实现dao接口再调service业务层去实现功能代码
JDBC连接代码
@WebServlet("/demo")
public
class
domain
extends
HttpServlet
{
@Override
protected
void
doGet
(HttpServletRequest req, HttpServletResponse resp)
throws
ServletException, IOException {
System.out.println(
"get访问"
);
String
id
=
req.getParameter(
"id"
);
Connection
conn
=
null
;
try
{
Class.forName(
"com.mysql.jdbc.Driver"
);
conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/demo"
,
"root"
,
"root"
);
String
sql
=
"select * from users where id = '"
+id+
"' "
;
Statement
statement
=
conn.createStatement();
ResultSet
resultSet
=
statement.executeQuery(sql);
}
catch
(ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
@Override
protected
void
doPost
(HttpServletRequest req, HttpServletResponse resp)
throws
ServletException, IOException {
this
.doGet(req,resp);
}
}
这里使用statement对象去执行sql语句然后采用拼接的语法会造成get型sql注入,其它类型注入方法:
POST型注入:
String
sql
=
"select * from users where username = '"
+username+
"' and password = '"
+password+
"' "
;
Like型注入:
String
name
=
req.getParameter(
"name"
);
String
sql
=
"select * from users where name like '%'+name+'%'"
;
//String sql = "select * from users where name like '%" + name + "%'";
Header注入:
String
referer
=
req.getHeader(
"referer"
);
String
sql
=
"update user set referer ='"
+referer+
"'"
;
JDBC 预编译
预编译的定义其实就是使用问号先来占位,后面再传入具体的值。
后面传值的时候,程序会把传入的参数,自动转换为spring类型的字符,并不会拼接成sql语句生效。
预处理会自动过滤 ' 等敏感字符然后进行转义(Likeorder by 预处理会报错需要在setstring方法设置%%)
Connection
conn
=
JDBCUtils.getConnection();
String
sql
=
"select * from users where username = ? and password = ?"
;
PreparedStatement
pstmt
=
conn.prepareStatement(sql);
//使用预编译传入sql语句
pstmt.setString(
1
,username);
//设置第一个参数为username
pstmt.setString(
2
,password);
//设置第二个参数为password
pstmt.executeQuery();
0x03 Mybatis注入场景
Mybatis获取值的方式有两种,分别是 ${} 和 #{}
#{}
:解析的是占位符问号,可以防止SQL注入,使用了预编译${}
:直接获取值,采用拼接的方式
因为like、order by直接使用#{}
预编译会进行sql报错,所以开发人员在使用${}
不当后会造成like注入和oder by注入,Mybatis中常见的注入场景为以下三种:
- ${}
- like 使用 ${}
- order by 使用 ${}
1. Get注入
靶场使用了Mybatis框架,首先在Mapper文件中查找到sql语句使用了 ${}
的写法,在Mybatis中 ${}
为拼接的方式构造sql语句
跟进findByUserNameVuln01函数到controller层找到漏洞触发URI, 并且未对sql语句进行过滤造成sql注入
观察URI上一层还有/sqli路径,所以漏洞触发URI为/sqli/mybatis/vuln01
字符型注入,构造闭合,构造sql语句为
select * from users
where
username
=
'xxx'
or
'1'
=
'1'
http:
//localhost/sqli/mybatis/vuln01?username=xxx' or '1'='1
where后语句恒为真所以执行了select * from users即查询了所有用户的信息
2. Like注入
以上是采用注解的方式写sql语句,Mybaitis中还有一种是用配置xml的方式,在mapper下找到UserMapper.xml
可以看到findByUserNameVuln02、findByUserNameVsec02两个方法都是以这种方式配置的sql语句,在Mapper中跟进findByUserNameVuln02方法
得到URI为/mybatis/vuln02
观察XML中sql为like型注入且使用了 ${}
like注入, like模糊查询语法 %xxx% , %23 为 # 注释掉后边的 %
http:
//localhost/sqli/mybatis/vuln02?username=xxx' or '1'='1' %23
出数据
修复方式,使用mysql函数concat()先预编译再进行拼接%字符进行模糊查询
select * from users where username like
concat
(
'%'
,#{_parameter},
'%'
)
3. Order by 注入
controller中找到此方法,用户传入sort值并赋值给String sort
在mapper中又把sort值赋给order
在xml配置文件中观察findByUserNameVuln03使用order by排序方法构造sql语句,可以看到如果order值不为空走进排序查询语句
构造payload
http://localhost:8080/sqli/mybatis/orderby/vuln03?sort=1 desc%23
desc倒序执行sql语句进行排序
asc正序执行sql语句进行排序
修复方式
使用sqlFilter方法对传入的值进行过滤
@GetMapping("/mybatis/orderby/sec04")
public
List<User>
mybatisOrderBySec04
(
@RequestParam("sort")
String sort)
{
String
filter_order
=
SecurityUtil.sqlFilter(sort);
return
userMapper.findByUserNameVuln03(filter_order);
}
}
4. In 注入
使用预编译 #{} 的代码会报错所以使用以下 ${} 方式会造成注入
Select
*
from
news
where
id
in
(${id})
0x04 Hibernate
@Autowired
CategoryDAO categoryDAO;
//依赖注入
@RequestMapping("/hibernate")
public
String
hibernate
(
@RequestParam(name = "id")
int
id)
{
Category
category
=
categoryDAO.getOne(id);
return
category.getName();
}
hibernate即我们经常使用的orm的一种实现,如果使用已封装好的
方法,那么默认是使用预编译的。需要注意的有这么几种情况:
- 对于一些复杂的sql语句,需要开发手写sql,此时要严格过滤用
户输入 - 上面提到的预编译不生效的几种场景同Mybatis一样
0x05 总结
存在问题的关键词:
Mybatis: $
JDBC连接方式下: +、like、order by
hibernate: +、like、order by
原文地址:https://www.cnblogs.com/Ne2o1/p/17174150.html
原文始发于微信公众号(亿人安全):java代码审计-sql注入
- 我的微信
- 微信扫一扫
-
- 我的微信公众号
- 微信扫一扫
-
评论