Java代码审计(7)Sql注入审计

1、基础

1.1 常见注入点

应用程序和数据交互的地方:
Authentication(认证页面) 

Search Fields (搜索页面) 

Post Fields (Post请求) 

Get Fields (Get请求)

HTTP Header(HTTP头部) 

Cookie

1.2 数据库特性

1.2.1 数据库特定表
  • and exists(select count(*) from msysobjects)

    mysysobjects表为access特有,一般返回权限不足

  • and exists(select count(*) from sysobjects)

    sysobjects表为SqlServer特有,一般返回正常

  • and (select count(*) from information_schema.TABLES)>0

    information_schema为MySQL 5.0 及以上版本特有

1.2.2 注释符
  • Mysql支持/*

    如果/**/返回错误,说明不是MySQL数据库

  • Sql Server

    – 返回正常,说明是MSSQL数据库或者Oracle
    ;-- 返回正常,说明是MSSQL;错误,基本就是Access数据库

1.2.3 数据库报错

在这里插入图片描述

1.2.4 MySQL 5.0 中information_schema表
  • information_schema.schemata 存放所有数据库名,schema_name为数据库名字段
  • information_schema.tables 存放所有数据库的表名,table_schema存放数据库名, table_name字段存放表名
  • information_schema.columns 存放所有数据库表的所有列名,table_schema 库名, table_name表名,column_name列

1.3 SQL注入靶场

SQL注入在线靶场:		http://redtiger.labs.overthewire.org/ 

DVWA:				https://dvwa.co.uk/

sqli-labs源码:		https://github.com/Audi-1/sqli-labs

1.4 框架

  • SSH组合是Struts+Spring+Hibernate

    基于MVC模式的开发,其中Struts2 对应前台的控制层,

    Spring负责实体bean的业务逻辑处理,

    Hibernate则是负责数据库的交接以及使用Dao接口来完成操作。

  • SSM组合是Spring-MVC+Spring+MyBatis

    标准的MVC模式,使用Spring MVC负责请求的转发和视图管理,

    Spring实现业务对象管理,

    Mybatis作为数据对象的持久化引擎。

  • SSH vs SSM

    SSM和SSH不同主要在MVC实现方式,以及ORM持久化方面不同(Hibernate与Mybatis)。

      SSM越来越轻量级配置,将注解开发发挥到极致,且ORM实现更加灵活,SQL优化更简便;
    
    
      SSH较注重配置开发,其中的Hibernate对JDBC的完整封装更面向对象,
    
      	对增删改查的数据维护更自动化,但SQL优化方面较弱,且入门门槛稍高。
    

2、JDBC初探

2.1 JDBC执行对象

执行对象是SQL的执行者。 目前常用的执行对象接口有三种: 

	Statement
	
	PreparedStatement
	
	CallableStatement

在这里插入图片描述

2.2 Statement

Statement 主要用于执行静态SQL语句,即内容固定不变的SQL语句。

Statement 每执行一次都要对传入的SQL语句编译一次,效率较低。
String name = "tom";

String sqlString = "select * from student_table where student_name = '" + name + "'"; Connection conn = open();

若 name 为用户可控参数,当用户传入 ’ or 1 = 1 # 则sqlString为:

select * from student_table where student_name = ' ' or 1 = 1 # '

可以看到程序输出 student_table 表中所有条目:
在这里插入图片描述

2.3 PreparedStatement(预编译)

  • PreparedStatement是预编译参数化查询执行SQL语句的方式。
String sql = "select * from student_table where name = ?";

Connection conn = open();

PreparedStatement pstmt = (PreparedStatement) conn.prepareStatement(sql); 
//对占位符进行初始化

pstmt.setString(1, "tom");

pstmt.executeQuery();

看到使用PreparedStatement之后,特殊符号被转义,无法按设想的SQL语句执行了。

在这里插入图片描述

2.4 CallableStatement

CallableStatement接口提供了执行存储过程的方法。

在线数据库练习平台:http://sqlfiddle.com/
create procedure sp_query @name varchar(50) as begin
	
	declare @sql nvarchar(500)
	
	set @sql = 'select * from ForgeRock where productName =''' + @name + '''' 
	
	exec(@sql)

end;

为@name赋值 ' or 1=1 --,语句成为 exec sp_query " ' or 1=1 -- ";

成功查询到该表中所有数据

注意:`--`后面需要有空格。

在这里插入图片描述

在存储过程中进行参数化查询

create procedure sp_query @name varchar(50) as begin
	
	select * from ForgeRock where productName = @name

end;
为@name赋值' or 1=1 -- ,语句成为 exec sp_query "' or 1=1 -- "; 
	
但此时没有返回任何数据,说明对SQL已有防御。

在这里插入图片描述

3、Mybatis框架安全

3.1 MyBatis使用

3.1.1 MyBatis了解
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
	
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 

或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,

普通老式 Java 对 象)为数据库中的记录。

官方教程:	https://mybatis.org/mybatis-3/zh/getting-started.html
3.1.2 MyBatis基本使用–基于xml实现
  • 实体类Student

    各个参数与数据库中目标表的列名一一对应,包括参数名、参数类型

  • Dao接口文件:

package mybatis.dao;

import mybatis.pojo.Student; public interface StudentDao {

	public Student selectStudent(@Param("name")String name); 

}

在这里插入图片描述

  • Mapper xml SQL语句映射文件

    StudentMapper.xml
    在这里插入图片描述

3.2 MyBatis中注入问题(重点)

3.2.1 动态 SQL

动态 SQL 是 mybatis 的主要特性之一,在 mapper 中定义的参数传到 xml 中之后,

在查询之前mybatis 会对其进行动态解析。 Mybatis框架中,接受用户参数有两种方式:

通过${param}方式 

通过#{param}方式

#{ }会自动传入值加上单引号, 而${ }不会。

即,“ ${} ”更容易导致存在sql注入
3.2.2 不安全的${ }
后端语句:
	
	select * from student_table where student_name = '${name}'

提交
	'or1=1#
	
最终执行:
		
	select * from student_table where student_name = '' or 1=1 #'

SQL注入防御 --> 使用 " #{} "

3.3 MyBatis中注入场景分析(重点)

3.3.1 like 模糊匹配

  • 后端代码是;

      select * from student_table where student_name like '%#{name}%'
    

    则传入一个“ ? ”很容易引起程序报错,

    因为引号内的?会被当作值处理,所以这里会报错找不到占位符。

  • 常见的解决方法

    把“ #{} ”换为“ ${} ”,如:

       select * from student_table where student_name like '%${name}%'
    
  • 新的问题

    但是这样又会容易引起注入,

  • 正确的做法(使用concat方法进行连接

    select * from student_table where student_name like concat('%', #{name}, '%')

3.3.2 IN语句

  • 后端代码

      select * from student_table where student_id in (#{id})
    

    提交 id=“1,2” ; 实际执行的语句如下:

      select * from student_table where student_id in ('1,2’)
    

    后果就是仅仅会查询 student_id = 1
    在这里插入图片描述

  • 常见的解决方法

    把“ #{} ”换为“ ${} ”,

  • 新的问题

    但是这样又会容易引起注入,

  • 正确的解决方法

    略微复杂,咱不记录。

3.3.3 order by(group by)语句

凡是字符串但又不能加引号的位置都不能预编译参数化,这种场景不仅order by,还有group by。
  • 防御

    这种场景下,通常采用白名单,只开放有限集合,使用间接对象引用,

    如果传来的参数不在白名单列表中,直接返回错误即可。

3.3.4 总结

Mybatis框架下易产生SQL注入漏洞的场景有:

  1. Like 模糊查询:

    Select * from student where name like ‘%${name}%’

  2. IN 查询:

    Select * from news where id in (${id})

  3. order by、group by 查询:

    select * from studentwhere id order by ${id}

4、Sql注入实战项目审计

inxedu 因酷教育软件v2.0:https://www.inxedu.com/downloadCode

4.1 环境搭建

将下载的源代码,按照源代码的教程先将数据库导入。然后将整个项目直接导入IDEA。

等待IDEA右下角的进度条跑完,继续按照教程将数据库链接的问题配置好,

在这里插入图片描述

然后右击项目,选择“重构模块”,等待进度条跑完,

在这里插入图片描述

这里我一开始报了一个错,
	
百度之后发现是jdk版本的问题,直接右击项目的设置,调整jdk版本为1.8

在这里插入图片描述

继续按照教程进行配置,

在这里插入图片描述

然后项目直接跑起来,

在这里插入图片描述

4.2 漏洞审计

根据项目的提示得到以下结论:

在这里插入图片描述

看到项目使用mybatis框架(resources下边),则使用“  ${  ”这种包括的sql语句都是可能存在注入的。

直接全局搜索,限制文件为“xml”,然后重点关注一些映射文件(Mapper),如下图标记的:

在这里插入图片描述

从上边,随意点进去一个,查看代码。

这里,我们可以先记住表名“ EDU_COURSE_FAVORITES ”。

在这里插入图片描述

然后根据这个“deleteCourseFavoritesById”关键词,

去查找对应的dao层定义该接口的代码,这里我们再次限制类型为“ .java ”,任意找到一处点击去看看,

在这里插入图片描述

看到接收到参数是 String ids,

在这里插入图片描述

然后搜索哪里调用过“ deleteCourseFavoritesById ”方法,

在这里插入图片描述

选择第一个结果前跟过去,

在这里插入图片描述

然后注意到这个237行的路由“/deleteFaveorite”,
	
在然后接着看该接口所属类最上边的路由“/webapp”,

在这里插入图片描述

即我们访问“ url/webapp/delectFaveorite ”路径,就可以走到上述实现接口的方法。

我们看到该方法,需要一个“id”参数,且对这个传入参数进行了一些为空判断等逻辑。

在不为空之后,就调用了我们最开始的“删除”方法,

在这里插入图片描述

我们使用burp抓包,修改路径,构造参数去请求,		、、经过测试,这里无需登陆也可以

后台注入立马变为前台注入。

在这里插入图片描述

另外,因为接收参数的方法是“ request.getParameter ”,所以我们使用GET/POST请求都可以。

在这里插入图片描述

这个sql语句,我们也可以在下边找到对应的记录。

此时我们也可以去看看表里对应的数据是否被删除。

在这里插入图片描述

在表内看到,确实被删除了,

在这里插入图片描述
这里有一个小知识点:

当我们在次构造传入语句“ 1 and sleep(2) ”会发现他沉睡了2S,		

//这里在实际的测试中,发现传入1S则沉睡19S,我们先假设沉睡的是1S。

在这里插入图片描述


但是我们构造语句如下图,第七行的payload,会发现他没有沉睡而直接秒返回,

这是因为拼接了第7行之后,sql语句变为第5行,而“ in ”会优先执行,即“  AAA   and  sleep(2)# ”

但是我们在表中id=1的已经被删除过,所以“ AAA ”是false,即 sleep(2)不会执行。

当然,此时我们可以不闭合或者将“ and ”改为“ or ”;在或者“ id=存在的参数 ”。

在这里插入图片描述

此时,在看下边那个方法,先构造路由,

在这里插入图片描述

尝试不同的参数,发现也存在注入,

在这里插入图片描述

4.3 小结(审计sql注入的思路)


先寻找疑似存在注入的dao层代码,“ ${ ”											
    			、、筛选“ .xml ”文件

根据dao层的id属性的值“ deleteCourseFavoritesById ”去查找这个方法在哪里定义的		
    			、、筛选“ .java ”文件

然后看看是哪里调用过“ deleteCourseFavoritesById ”								
    			、、直接右击“ 查找用法 ”

然后,根据调用的方法,构建路由进行测试
    			、、此时可以看看idea的日志,执行的sql语句是否为预想的。
    			
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

划水的小白白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值