环境配置 链接:https://pan.baidu.com/s/1jAXBe7_EqiPtSo1RUcoxLg 提取码:fd7a
创建数据库sec_sql
1 create database sec_sql charset utf8;
创建表admin
、userinfo
并插入数据
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 > <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
访问http://localhost:9090/sql
显示如下
如果要改映射路径/sql
的话可以在tomcat7的plugin中的configuration
增加
通过传入?id=1
即可进行查询
SQL注入关键字 1 2 3 4 5 6 7 8 Statement createStatement PrepareStatement like "%${ in (${ select update insert
sql注入漏洞 当传入的id没有进行过滤就与sql语句进行拼接带入数据库进行查询,就会造成sql注入漏洞,具体漏洞代码如下
在25行处,对用户传入的id与语句进行拼接后,通过executeQuery
执行sql语句,造成sql注入
payload:
1 ?id=1 union select 1 ,2 ,3 ,user (),database ()
常见的sql注入存在的地方
sql语句直接进行拼接
预编译使用不正确(语句本身有问题而不是方法问题)
order by注入
由于order by后面只能接数字或者字段名,因此不能用setString
进行预编译,常见形式如下
1 2 3 String sql = 'SELECT * FROM user ' + 'order by ' +id; PreparedStatement preparedStatement = conn.prepareStatement(sql); rs = preparedStatement.executeQuery();
模糊查询
在预编译的时候,如果使用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映射文件中的定义
order by 查询
1 2 3 4 # 安全 select * from user order by #{age} # 不安全 select * from user order by ${age}
like查询
1 2 3 4 # 安全 select * from users where name like '%#{user}%' # 不安全 select * from users where name like '%${user}%'
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
更改数据库配置
创建ofcms
数据库,导入doc/sql/ofcms-v1.1.2.sql
中的数据
1 2 use ofcms; source ~/doc/sql/ofcms-v1.1.2.sql
通过Tomcat Local或者maven的Tomcat启动即可
(banner图片被我改了…)
漏洞分析 根据漏洞描述,漏洞代码出现在src/main/java/com/ofsoft/cms/admin/controller/system/SystemGenerateController.java
在admin页面(登录账号密码:admin/123456)中找到对应位置
通过报错注入进行回显
payload
1 update+of_cms_ad+set+ad_name%3Dupdatexml(1%2Cconcat(0x7e%2Cdatabase()%2C0x7e)%2C1)+where+ad_id%3D1