Java代码审计(一)-SQL注入
SQL Injection - JDBC
SQLI(SQL Injection), SQL注入是因为程序未能正确对用户的输入进行检查,将用户的输入以拼接的方式带入SQL语句,导致了SQL注入的产生。攻击者可通过SQL注入直接获取数据库信息,造成信息泄漏。JDBC有两个方法执行SQL语句,分别是PrepareStatement和Statement。
一、PrepareStatement和Statement的区别
# 当使用Statement对象时,每次执行一个SQL命令时,都会对它进行解析和编译。 # 当使用PreparedStatement对象时,无论多少次地使用同一个SQL命令,都只会解析和编译一次。 |
二、简单漏洞例子
1、漏洞代码 - 语句拼接(Statement),没有对语句进行过滤直接拼接
1 | // 采用原始的Statement拼接语句,导致漏洞产生 |
安全代码 - 过滤方法
1 | // 采用黑名单过滤危险字符,同时也容易误伤(次方案) |
2、漏洞代码 - 语句拼接(PrepareStatement)
1 | // PrepareStatement会对SQL语句进行预编译,但有时开发者为了便利,直接采取拼接的方式构造SQL,此时进行预编译也无用。 |
安全代码 - 预编译
1 | // 正确的使用PrepareStatement可以有效避免SQL注入,使用?作为占位符,进行参数化查询 |
3、安全代码 - ESAPI安全框架
1 | // ESAPI (OWASP企业安全应用程序接口)是一个免费、开源的、网页应用程序安全控件库,它使程序员能够更容易写出更低风险的程序 |
三、漏洞类型
POST型注入
1 | String sql = "select * from users where username = '"+username+"' and password = '"+password+"' "; |
Like型注入
1 | String name = req.getParameter("name"); |
Header注入
1 | String referer = req.getHeader("referer"); |
四、小结
代码审计时,若发现存在使用JDBC连接数据库可进一步跟踪其代码,在没有使用预编译的情况下且未定义过滤方法,则可能存在SQL注入。
SQL Injection - MyBatis框架
Mybatis 是一个基于 Java 的持久层框架,它内部封装了 jdbc,开发者只需要关注 sql 语句本身,不需要花费时间和精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。MyBatis 框架底层已经实现了对 SQL 注入的防御,但存在使用不当的情况下,仍然存在 SQL 注入的风险。
一、Mybatis特性
Mybatis 获取值有两种方法,${}
和 #{}
,一般情况下 Mybatis 使用 #{} 获取值,因为能避免 SQL 注入漏洞的产生,若直接使用 ${} 获取值则不能有效的避免注入。
#{} 解析的是占位符问号,可以防止SQL注入,使用了预编译。 ${} 直接获取值 |
二、漏洞类型
1、like注入
以下语句在运行时会报错
1 | Select * from news where title like '%#{title}%' |
该语句能正常运行,但由于使用了${}获取值,产生了SLQ语句拼接,即使使用了预编译,但若没有对语句进行过滤也会产生SQL注入漏洞
1 | select * from user where name like '%${name}%' |
正确语句
1 | select * from user where name like #{name} |
2、in后的参数注入
以下语句在运行时会报错
1 | Select * from news where id in (#{id}) |
该语句则能正常运行,但由于使用了${}获取值,产生了SLQ语句拼接,即使使用了预编译,但没有对语句进行过滤则也会产生SQL注入漏洞
1 | Select * from news where id in (${id}) |
正确语句,使用forrach
1 | <foreach collection="ids" item="item" open="("separatosr="," close=")"> |
3、order by 注入
以下语句在运行时会报错
1 | Select * from news where title ='新闻' order by #{time} asc |
该语句则能正常运行,但由于使用了${}获取值,产生了SLQ语句拼接,即使使用了预编译,但没有对语句进行过滤则也会产生SQL注入漏洞
1 | Select * from news where title ='新闻' order by ${time} asc |
正确语句
1 | Select * from news where title ='新闻' order by #{time} asc |
三、靶场学习
1、环境搭建
1 | [+] IDEA 2021.1 |
2、IDEA搭建网站
● IDEA配置Maven,下载Maven,版本选择尽量不要最新
1 | https://archive.apache.org/dist/maven/maven-3/ |
配置Maven环境变量,cmd打开:sysdm.cpl
测试是否成功安装
1 | mvn -v |
配置阿里镜像和jdk,在Maven解压的地方创建一个新文件夹responsitory
,打开Maven文件夹下的conf中的settings.xml的<settings>
标签内添加以下内容
配置jdk1.8
1 | <profiles> |
配置阿里镜像源
1 | <mirrors> |
将配置的Maven适配到IDEA,File -》 Settings -》 Build,Execution,Deployment -》 Maven
● IDEA配置JDK,File -》 Project Structure -》 Project -》 Project SDK
● IDEA 添加 pom.xml 文件为 Maven 文件,由于部署环境不一样,我们需先修改 pom.xml 文件部分内容,首先将<systemPath>
中的 basedir 修改为 pom.basedir ,共四处
添加 plugin 版本号
● 导入数据至 MYSQL
,利用 phpstudy
导入程序数据库,注意由于数据库文件中有效时间填写为 0000-00-00 00:00:00
,但 timestamp
有效时间在:1970-01-01 00:00:00
到 2037-12-31 23:59:59
,所以需要将所有的 0000-00-00 00:00:00
修改为有效时间内,否则导入文件会报错。
注意数据库名必须与 src/resources/project.properties
相同,否则网站数据会缺失,按照以下操作避免出现错误
导入数据
● 配置inxedu项目信息src/resources/project.properties
● 项目运行前,配置相关 Maven 信息,File-》Project Settings -》Artifacts -》Web Application:Archive -》Empty
● 配置 Run/Debug Configurations
,配置 Tomcat
配置Maven
注意,若在过程中出现报错,修改了相关配置,记得 clean && install
清理一下缓存,否则 Run 会出现错误,网站无法起来。
● 编译运行
编译成功
● Run 启动网站,点击右上角运行符号运行,虽然有报错,但不影响运行
3、审计开始
| 目录结构 | 作用 | | ------------------ | ----------------------------------------------------- | | src/main/java | java的代码目录 | | src/main/resources | 资源目录,存放一些配置文件,如properties、spring-mvc.xml等 | | src/main/webapp | 传统项目的WebContent目录 | | target | 编译后的文件 | |
审计代码为 scr
目录下的代码,先查看其 web.xml
,分析其使用了哪些框架。 web.xml
提供了设置初始化参数的功能,开发者会将一些配置信息写到里面去,通读 web.xml
可以了解系统使用的框架等基本信息,有时候开发者还会把账号信息等情况写在里面。
通过分析,该网站使用了 SSM
框架,即 Spring+Spring Mvc+Mybatis
查看其目录结构
4、审计SQL注入
文件清楚看到系统的结构,点开dao文件下的任意文件,看看Mybatis是使用了注解开发还是配置文件开发。
1 | 注解开发:即可不使用任何的xml配置文件来开发java web,直接在代码中体现,不需要单独编写xml文件 |
文件只定义了一些方法,并没有详细的Mybatis的注解,所以该 CMS 使用了 XML 配置方法
寻找 XML 配置文件,XML 配置的映射文件会和 dao 的接口在同层目录下 resource/mybatis/index/article
根据上面的知识点可知,若使用了 ${}
则可能存在 SQL 注入,直接在 XML 配置文件寻找 $
符号,发现deleteArticleByIds
使用了 ${}
,符合上面知识点 in 参数后注入。
dao文件夹找寻XML配置文件对应映射的 deleteArticleByIds
接口
Ctrl + 鼠标左键选中 deleteArticleByIds
查看代码中哪些类调用了该方法,初步发现代码没有进行过滤处理
跟进代码的 Controller(控制器),选择 deleteArticleByIds
,Ctrl+Alt+H快捷键去查询调用层次,去看Controller的位置
查看 Controller
文件,寻找到目录路径为:/admin/article
查看具体调用位置,位置为:/delete
所以漏洞具体位置为: http://192.168.114.131:82/admin/article/delete
, 访问后发现为后台注入,靶场密码为:admin/111111
再次访问 http://192.168.114.131:82/admin/article/delete
网站页面自动跳转至下面以下链接http://192.168.114.131:82/admin/article/showlist?
点击删除抓取数据包
通过sqlmap成功跑出数据,复现成功
坑点
1、数据库名称必须为 demo_inxedu_v2_0_open
,否则会报错
2、IDEA 搭建网站中会出现各种报错无法进行下一步操作,当找到解决方案后,记得清理缓存(clean && install)
再 Run,否则会出现网站无法启动的情况
3、若 phpstudy
创建 demo_inxedu_v2_0_open
数据库提示数据库已存在时,进入root数据库查看是否已经存在这个数据库,然后进行删除,再次导入即可
参考文章
https://github.com/j3ers3/Hello-Java-Sec
https://theoyu.top/2022/04/27/Java-Prepstatementared.html
https://www.cnblogs.com/nice0e3/p/13647511.html#0x01-jdbc-%E6%B3%A8%E5%85%A5%E5%88%86%E6%9E%90
https://mp.weixin.qq.com/s?__biz=MjM5OTk2MTMxOQ==&mid=2727827368&idx=1&sn=765d0835f0069b5145523c31e8229850&mpshare=1&scene=1&srcid=0926a6QC3pGbQ3Pznszb4n2q