经常在代码审计中会遇到mybtais框架中关于sql注入的问题,如扫描器会提示#,$的告警,今天就以实战的角度去理解这个问题,后续还将总结关于sql注入的bypass和各种场景
0x01 关于mybatis框架
概念
ORM(Object-Relationship-Mapping):是对象关系映射的意思,它是一种思想,是指将数据库中的每一行数据用对象的形式表现出来。
JPA(Java-Persistence-API):是Java持久化接口的意思,它是JavaEE关于ORM思想的一套标准接口,仅仅是一套接口,不是具体的实现
Mybatis的功能架构分为三层:
(1)API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
(2)数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
(3)基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑.
0x02 demo
开发环境:idea,mysql8.0.15,jar包:mybatis-3.4.3.jar,mysql-connector-java-8.0.16.jar
创建java EE项目
src的包下创建主类:mybatis_test.java和pojo类:employee.java
mysql表:
mysql> select * from tbl_employee;
+----+-----------+--------+---------+
| id | last_name | gender | email |
+----+-----------+--------+---------+
| 1 | tom | 0 | tom@com |
| 2 | cat | 1 | cat@com |
+----+-----------+--------+---------+
package com.test.mybatis;
public class Employee {
private Integer id;
private String lastName;
private String email;
private String gender;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
package com.knownsec.test;
import com.test.mybatis.Employee;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class mybatis_test {
public static void main(String[] args) throws IOException {
System.out.println ("1");
test();
}
public static void test() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream (resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession openSession = sqlSessionFactory.openSession ();
try {
Employee employee;
int i=1;
employee = openSession.selectOne ( "com.test.mybatis.Employee.selectBmp", "%ca%' and '1'='1");
System.out.println ( employee );
} finally {
openSession.close ();
}
}
}
配置文件:mybatis-config.xml和EmployeeMaper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="EmployeeMaper.xml"/>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.mybatis.Employee">
<select id="selectBmp" resultType="com.test.mybatis.Employee">
select * from tbl_employee where last_name like '${value}'
</select>
</mapper>
Run:
1
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
Employee{id=2, lastName='null', email='cat@com', gender='1'}
注意,在maper配置中的格式,一定是有引号和$符号,其中的貌似只能写成value(不然会报错)
在openSession.selectOne中,传入的参数
%ca%' and '1'='1
,闭合了xml中单引号且拼接了字符串
在xml中换成#后,也就是采用预编译,未查询出记录值
此时,maper配置为
<mapper namespace="com.test.mybatis.Employee">
<select id="selectBmp" resultType="com.test.mybatis.Employee">
select * from tbl_employee where last_name like #{value}
</select>
</mapper>
**0x03 如何选择#和KaTeX parse error: Expected 'EOF', got '#' at position 22: …order by时: 一般使用#̲,防止注入,但在排序问题上,必…进行注入。
因为#是按string类型拼接,就成为:order by ‘cloumn’ ‘desc’