文章目录
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇2 | SQL注入漏洞审计
- 1. 前言
- 2. SQL注入代码审计【有1处】
- 1)全局搜索`Statement`关键字,发现有几处,不过大多都是`preparStatement`预编译方式执行sql语句。
- 2)点进第一个看看
- 3)搜索executeSQL()方法的调用,查看sql语句怎么传递进来的
- 4)我们搜索的`Statement`关键字,所处位置都是安装工具类`InstallUtils`,所以全部忽略。
- 5)全局搜索`like "%`关键字,发现有1处,不过是注释,不需要管了。
- 6)全局搜索`in (${`关键字,无
- 7)全局搜索`select`关键字,很多,但是翻了一圈,没有和sql语句相关的
- 8)全局搜索`update`关键字,搜索到了很多貌似和sql有关系的语句
- 9)点进第一个看看,发现这个`ComnController`类里面的方法都和sql语句相关,那挨个看一下
- 10)先分析下query()方法
- 11)查看每个方法的调用,发现整个sql语句可控的情况
- 12)寻找对应的前端功能
- 13)验证漏洞
- 14)继续寻找其他sql语句可控的位置
Java代码审计篇 | ofcms系统审计思路讲解 - 篇2 | SQL注入漏洞审计
1. 前言
我发现很多文章包括教程,大概套路是:只说有漏洞的点,将有漏洞的点指出,然后分析代码;或者黑盒测试出漏洞之后,然后分析代码。
我认为这是在分析漏洞代码,而非代码审计。代码审计文章或教程应该是从0开始找到漏洞所在,包括思路!
所以这里不管有没有漏洞,我都会把审计过程写出来,因此篇幅会很长,但我认为这样对你会很有帮助。
知其然亦知所以然。
由于篇幅较长,因此我会分几篇进行,本篇是整个系列的第2篇,讲解1个内容:
- SQL注入漏洞审计
本系列文章:
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇1 | 环境搭建、路由机制
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇2 | SQL注入漏洞审计
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇3 | 文件上传漏洞审计
搭建好环境,确定好项目结构之后,按我思路是应该审计项目所使用框架漏洞的,这里关于框架漏洞就放最后篇章来说了,我们想了解下基础漏洞的审计~
文章中有错误点,或者思路上有什么问题的,欢迎师傅们留言指出~
2. SQL注入代码审计【有1处】
sql注入漏洞一般搜索的关键字:
Statement
createStatement
PreparStatement
like "%{
in (${
select
update
insert
...
1)全局搜索Statement
关键字,发现有几处,不过大多都是preparStatement
预编译方式执行sql语句。
那要不要点击去看看?答案是需要!因为可能会有绕过方式…
2)点进第一个看看
核心代码已框出,就是预编译执行sql语句~哦,戏不大。
不过大家可以思考一下:如果整个sql语句都可控呢?是不是可以绕过预编译限制呢?
所以我们不要放弃,接下来看一下sql语句怎么来的。
3)搜索executeSQL()方法的调用,查看sql语句怎么传递进来的
在方法上右击,然后“Find Usages”或Alt+F7查看方法的调用:
发现有两个,如下
有办法注入吗?貌似没有,原因有2:
- sql语句是写死的
- 参数是单独传入的,但是后期是需要经过预处理的
其实这里还有一个点,就是这两个方法是在安装工具类InstallUtils
下,因此即使有sql注入点,也无法利用,毕竟你不可能去重新安装该项目吧。
所以,接下来,安装工具类InstallUtils
下的代码我们就不需要看了。
4)我们搜索的Statement
关键字,所处位置都是安装工具类InstallUtils
,所以全部忽略。
接下来换关键字搜索:
5)全局搜索like "%
关键字,发现有1处,不过是注释,不需要管了。
6)全局搜索in (${
关键字,无
7)全局搜索select
关键字,很多,但是翻了一圈,没有和sql语句相关的
8)全局搜索update
关键字,搜索到了很多貌似和sql有关系的语句
并且可以发现一个共同点,大部分都是Db.update
调用的。
9)点进第一个看看,发现这个ComnController
类里面的方法都和sql语句相关,那挨个看一下
10)先分析下query()方法
这里发现,Db这个是什么,点进去看一下,发现是专门用来操作数据库的类:
自己写的吗?不不不,可以看到,该文件是Db.class,可以下载源码
经过分析查看,这个Db
是com.jfinal.plugin.activerecord
目录下的一个类,原来是使用的jfinal
框架~ 是我孤陋寡闻了。
通过分析Db的源码,发现每个方法都使用了预编译处理~ 有漏洞的可能性不大了
但是还有一种情况,就是前面所说的,整个sql语句可控,那么可能会存在sql注入~
11)查看每个方法的调用,发现整个sql语句可控的情况
当我们找到update(String sql)
方法的调用情况,SystemGenerateController
类的create()方法时,发现此处的sql语句是通过getPara()
方法直接获取的,并没有传递什么参数
这里大概率可以判定为sql语句可控,当然也不一定,需要看一下getPara()
方法是怎么实现的:
点击进入看一下,发现是通过request.getParameter(name)
直接获取的参数内容!
这个时候可以断定,这里99.9%存在sql注入,因为整个sql语句可控。
12)寻找对应的前端功能
既然得知,SystemGenerateController
类的create()
方法可以触发该sql执行,那么找一下前端哪个功能可以触发该方法,这里需要根据前面所说的路由机制来判断。
可以看到类名上存在一个@Action(path = "/system/generate")
注解,并且方法名是create
,并且该类在admin目录下
因此,可以推断出,前端请求的路径是/admin/system/generate/create.json
那么接下来去前端搜索一下:
- 注意点1:搜索的时候不要搜全,因为路径可能是拼接出来的
- 注意点2:这些路径大部分都是在js文件中,所以直接搜不一定搜出来,因为有些js文件可能没加载呢,所以搜索的时候,需要不断的点击不同功能来获取到不同的js文件(这里可以根据路径判断大体的功能点)。
当我们点击到“代码生成”-“新建”的时候,出现了我们搜索的路径(真费时呀)。
再通过参数名,可以再进一步验证该功能是正确的,如下图:都为sql参数名。
13)验证漏洞
接下来,根据这个功能可以验证该漏洞了。
但是这个功能是用来创建表的,通过源码,我们可以得出可以使用的sql指令是update。
既然只能使用update,那这里我的思路大概就是:报错注入
那么接下来试一下,报错注入,使用update报错注入需要知道表名和列名,那我们可以去数据库看一下~(注意:这里是代码审计,不是黑盒,所以是可以得到数据库信息的)
那就随机找个表名字段名~
构造报错注入语句:
update of_cms_field set is_disabled=updatexml(1,concat(0x5e,database(),0x5e),3) where field_id=2
点击新增,成功执行!
14)继续寻找其他sql语句可控的位置
好吧,找了其他的方法对应的调用,发现,不是sql语句固定,就是语句通过预编译,没有完全可控的sql语句了。ok,sql注入的代码审计到此结束。