HacKerQWQ的博客空间

javaweb代码审计学习(sql注入)

Word count: 1.7kReading time: 8 min
2021/11/01 Share

环境配置

链接:https://pan.baidu.com/s/1jAXBe7_EqiPtSo1RUcoxLg
提取码:fd7a

创建数据库sec_sql

1
create database sec_sql charset utf8;

创建表adminuserinfo并插入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin` (
`uid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'uid',
`username` varchar(100) NOT NULL COMMENT '账号',
`password` varchar(100) NOT NULL COMMENT '密码',
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
BEGIN;
INSERT INTO `admin` VALUES (1, 'admin', '7a57a5a743894a0e');
COMMIT;
DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(100) NOT NULL COMMENT '名称',
`age` int(11) NOT NULL COMMENT '年龄',
`content` varchar(100) NOT NULL COMMENT '联系⽅式',
`address` varchar(255) NOT NULL COMMENT '家庭地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
BEGIN;
INSERT INTO `userinfo` VALUES (1, 'panda', 22, 'panda@cnpanda.net', '中国');
INSERT INTO `userinfo` VALUES (2, 'John', 29, 'test@cnpanda.net', '英国');
INSERT INTO `userinfo` VALUES (3, 'Tom', 45, 'hello@cnpanda.net', '美国');
INSERT INTO `userinfo` VALUES (4, 'Mr.Li', 33, 'li@cnpanda.net', '韩国');
INSERT INTO `userinfo` VALUES (5, 'Miss', 32, 'miss@cnpanda.net', '法国');
INSERT INTO `userinfo` VALUES (6, 'Ling', 17, 'ling@cnpanda.net', '中国');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

运行用IDEA创建maven项目,导入tomcat7的plugin到pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- http port -->
<port>9090</port>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>

导入mysql和servlet的denpendency

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

通过maven启动tomcat7

image-20211101171902061

访问http://localhost:9090/sql显示如下

image-20211101171927185如果要改映射路径/sql的话可以在tomcat7的plugin中的configuration增加

1
<path>/</path>

通过传入?id=1即可进行查询

image-20211101172308883

SQL注入关键字

1
2
3
4
5
6
7
8
Statement
createStatement
PrepareStatement
like "%${
in (${
select
update
insert

sql注入漏洞

当传入的id没有进行过滤就与sql语句进行拼接带入数据库进行查询,就会造成sql注入漏洞,具体漏洞代码如下

image-20211101172405628

在25行处,对用户传入的id与语句进行拼接后,通过executeQuery执行sql语句,造成sql注入

payload:

1
?id=1 union select 1,2,3,user(),database()

image-20211101172827046

常见的sql注入存在的地方

  1. sql语句直接进行拼接

  2. 预编译使用不正确(语句本身有问题而不是方法问题)

  3. order by注入

    由于order by后面只能接数字或者字段名,因此不能用setString进行预编译,常见形式如下

    1
    2
    3
    String sql = 'SELECT * FROM user '+ 'order by '+id;
    PreparedStatement preparedStatement = conn.prepareStatement(sql);
    rs = preparedStatement.executeQuery();
  4. 模糊查询

    在预编译的时候,如果使用setString进行处理,则%_不会进行转义,依旧作为通配符带入sql语句

    1
    SELECT * from users where username = '%%';

Mybatis中的sql注入

Mybatis中如果使用不当,也会存在sql注入

  • #{}在底层使用?作为占位符进行参数化查询,安全

  • ${}类似字符串拼接,存在sql注入风险

1
2
SELECT * fro user WHERE id=#{id} //安全写法
SELECT * fro user WHERE id=${id} //不安全写法

假设sql查询代码如下,mybatistest.java

1
2
3
4
5
public void testSelectUser(){
String Statement = "com.mybatis.userMapper"+".getUser";
User user = sqlSession.selectOne(statement,"1 and 1=2 union select 1,database(),3");
System.out.println(user);
}

在userMapper.xml中定义SQL映射

安全写法:

1
2
3
4
5
<mapper namespace="com.mybatis.userMapper">
<select id="getUser" resultType="com.mybatis.sql.User">
select * from user where id=#{id}
</select>
</mapper>

不安全写法:

1
2
3
4
5
<mapper namespace="com.mybatis.userMapper">
<select id="getUser" resultType="com.mybatis.sql.User">
select * from user where id=${id}
</select>
</mapper>

Mybatis常见出现sql注入地方

以下例子都是在SQL映射文件中的定义

  1. order by 查询

    1
    2
    3
    4
    # 安全
    select * from user order by #{age}
    # 不安全
    select * from user order by ${age}
  2. like查询

    1
    2
    3
    4
    # 安全
    select * from users where name like '%#{user}%'
    # 不安全
    select * from users where name like '%${user}%'
  3. in关键字

    in关键字有些特殊由于括号中需要接可变的参数,而不是单纯的字符串,因此只能使用${},存在SQL注入的可能性很大

    1
    select * from users where name in (${user})

预防sql注入

预编译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
25
public UserInfo UserInfoFoundDao(String id){

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
UserInfo userinfo = null;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sec_sql?&useSSL-false&serverTimezone=UTC","root","root");
String sql = "select * from userinfo where id = ?";
ps = conn.prepareStatement(sql);
//传值
ps.setInt(1,Integer.parseInt(id));
rs = ps.executeQuery();

while(rs.next()){

userinfo = new UserInfo();
userinfo.setId(rs.getString("id"));
userinfo.setName(rs.getString("name"));
userinfo.setAge(rs.getInt("age"));
userinfo.setContent(rs.getString("content"));
userinfo.setAddress(rs.getString("address"));

}

以上代码将id经过Integer.parseInt转换后填入到sql语句的占位符中再执行

但是如果开发者不正确使用预编译语句,也会导致sql注入的产生,典型代码如下

1
2
3
4
5
6
7
8
9
10
11
Class.forName("com.mysql.cj.jdbc.Driver")
conn = DriverManager.getConnection("jdbc:mysql://192.168.88.20:3306/iwebsec?&useSSL=false&serverTimezone=UTC","root","root");
String username = "user%' or '1'='1'#";
String id = "2";
String sql = "SELECT * FROM user where id=?";
if(!CommonUtils.isEmptyStr(username))
sql += "and username like '%"+username+"%'";
System.out.println(sql);
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1,id);
rs = preparedStatement.executeQuery();

虽然采用了预编译的方式,但是username处代码为username like '%user%' or '1'='1'#%,会将user表中的所有数据都查询出来。

采用框架

框架例如Mybatis、Druid等

CVE-2019-9615

漏洞描述

1
An issue was discovered in OFCMS before 1.1.3. It allows admin/system/generate/create?sql= SQL injection, related to SystemGenerateController.java.

环境配置

源码地址:https://gitee.com/oufu/ofcms/repository/archive/V1.1.2?format=zip

通过maven导入,reload一下pom.xml,然后在src/main/resources/dev/conf/db.properties更改数据库配置

image-20211101231738293

创建ofcms数据库,导入doc/sql/ofcms-v1.1.2.sql中的数据

1
2
use ofcms;
source ~/doc/sql/ofcms-v1.1.2.sql

通过Tomcat Local或者maven的Tomcat启动即可

image-20211101232056559

(banner图片被我改了…)

漏洞分析

根据漏洞描述,漏洞代码出现在src/main/java/com/ofsoft/cms/admin/controller/system/SystemGenerateController.java

image-20211101232245476

在admin页面(登录账号密码:admin/123456)中找到对应位置

image-20211101232403416

通过报错注入进行回显

image-20211101232631274

payload

1
update+of_cms_ad+set+ad_name%3Dupdatexml(1%2Cconcat(0x7e%2Cdatabase()%2C0x7e)%2C1)+where+ad_id%3D1
CATALOG
  1. 1. 环境配置
  2. 2. SQL注入关键字
  3. 3. sql注入漏洞
    1. 3.1. 常见的sql注入存在的地方
  4. 4. Mybatis中的sql注入
    1. 4.1. Mybatis常见出现sql注入地方
  5. 5. 预防sql注入
    1. 5.1. 预编译sql语句
    2. 5.2. 采用框架
  6. 6. CVE-2019-9615
    1. 6.1. 漏洞描述
    2. 6.2. 环境配置
    3. 6.3. 漏洞分析