经过本次分析学到了很多知识,仍有许多不足,欢迎师傅们提议意见或者建议,大家一起交流~
一、前置知识
本文主要讲解基础的代码审计思路与方法技巧,适合有一定java基础,无审计经验的同学学习。
二、漏洞挖掘
1、配置信息
首先了解pom.xml文件,了解该项目使用了哪些依赖和版本。从而快速确认是否存在漏洞。图中mybatis版本较低,可能存在sql注入漏洞,同时还发现fastjson和commons-fileupload版本都比较低,都可能存在漏洞
2、Mybatis的SQL注入
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎 所有的JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。在Mybatis中拼接SQL语句有两种方式:一种是占位符 #{},另一种是拼接符 ${}。
占位符 #{} :对传入的参数进行预编译转义处理。类似JDBC中的 PreparedStatement
拼接符 ${} :对传入的参数不做处理,直接拼接,进而会造成SQL注入漏洞
#{}可以有效防止SQL注入漏洞。${}则无法防止SQL注入漏洞。因此在我们对JavaWeb整合Mybatis系统进行代码审计时,应着重审计SQL语句拼接的地方。除非开发人员的粗心对拼接语句使用了 ${} 方式造成的SQL注入漏洞。在Mybatis中有几种场景是不能使用预编译方式的,比如:order by、in、like 。然后全局搜索"${",可看到疑似有漏洞的地方如下图所示: 可以看到,下面的接口使用了${}字符串拼接。
然后我们需要找到是哪个控制器使用了这个接口,可以发现在这个配置中,'namespace' 属性定义了映射器接口的完整路径,以便MyBatis可以找到并执行相应的SQL 语句。在这个特定的例子中,映射器可能用于处理与地址相关的数据库操作。
我们跟踪一下这个接口,发现直接跳转到相对应的接口下
除了allDirector这个函数,没有发现其他什么信息,跟进去这个函数,如下图所示
跟到了控制层,发现了接口,及前面用来拼接的参数,且没有对它们进行过滤处理,所以该处存在SQL注入漏洞
通过以上分析成功找到是那个控制器使用了该处接口,接下来就是构造数据包尝试sql注入漏洞复现。然后构造数据如下:
POST /outaddresspaging HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0
Accept: text/html, */*; q=0.01
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 27
Origin: http://127.0.0.1:9999
Connection: keep-alive
Referer: http://127.0.0.1:9999/addrmanage
Cookie: JSESSIONID=A011C3FEFE13FBE498BB68176794D84C
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Priority: u=1
baseKey=1'&outtype=1&alph=1
可以看到控制台成功返回报错的信息
最后也是通过sqlmap进行验证(其中的三个参数都存在注入漏洞):
3、文件上传漏洞
在配置信息中发现commons-fileupload,可能存在文件上传漏洞。首先全局搜索"upload"函数,可以看到疑似有漏洞的地方如下图所示:然后我们观看这段代码,首先定义一个公开的方法"uploadfile",并且接受几个参数,包括MultipartFile对象,一个路径id,一个HttpSession对象和一个Model对象。MultipartFile是用来处理上传的文件,Session对象用来存储用户的ID,Model对象则用于添加新的属性到当前的视图模型。这个方法的主要功能如下:
1.从session中获取用户ID,并使用该ID从数据库中获取对应的用户信息2.根据提供的路径ID从数据库中获取对应的文件路径信息3.使用提供的文件和用户信息,以及文件路径信息,将文件保存到文件系统中。保存过程中需要检查文件是否已经被其他进程使用(使用'savefile'方法的第二个参数来决定是否需要检查)4.将上传的文件列表信息打印到控制台5.将路径ID添加到视图模型中,以便在返回时可以将此ID传递给前端页面6.最后,方法返回一个字符串 'forward:/filetest',这通常表示将用户重定向到'/filetest'页面
接着跟随savefile函数,发现代码使用了FilenameUtils.getExtension(file.getOriginalFilename()) 来获取上传文件的扩展名,这样会返回文件扩展名,例如 ".jpg" 或 ".mp3"。将此扩展名与一个随机生成的UUID(UUID.randomUUID().toString().toLowerCase())拼接在一起,生成一个新的文件名。然后使用tmp = "/"+tmp + "/" + newFileName;构建一个新的路径,其中tmp是当前目录路径,newFileName是新的文件名。最后创建一个file对象File targetFile = new File(savepath, newFileName);保存到savepath指定位置。调用transferTo(targetFile)将原始文件移动到新的位置。
接下来就是如果构造数据包了,对代码分析发现传入三个参数,需要将上面的参数添加到请求包中。构造数据包如下:
POST /fileupload HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0
Content-Type: multipart/form-data; boundary=---------------------------363587425819504078521761715654
Content-Length: 340
Cookie: JSESSIONID=2CA07266D8454F67DF2142C2B0DE45C1
-----------------------------363587425819504078521761715654
Content-Disposition: form-data; name="file"; filename="1.png"
Content-Type: image/png
11111111
-----------------------------363587425819504078521761715654
Content-Disposition: form-data; name="pathid"
94
-----------------------------363587425819504078521761715654--
成功上传文件访问路径地址
http://127.0.0.1:9999/file/2024/07/admin/4ba3a1a2-56f7-412a-bc48-6c4fa4b29ea7.txt[3]
4、任意文件读取漏洞
4.1.原理介绍 通过用户输入,后端接收到参数直接拼接到指定路径下读取用户的文件名,看似正常,但是用户输入的参数不可控制,黑客将非法的特殊字符作为文件名的一部分,操作到其他路径下,甚至是跳转到服务器敏感目录,读取敏感的配置文件,例如服务器的密码文件,程序数据库,redis等核心配置文件,因此具有一定的风险。4.2.关键字
1.new FileInputStream( path2.new FileOutputStream( path 3.new File( path4.RandomAccessFile fp = new RandomAccessFile(fname,"r"); 5.mkdirs6.getOriginalFilename 7.entry.getName(
4.3 类和函数
1.sun.nio.ch.FileChannelImpl 2.java.io.File.list/listFiles 3.java.io.FileInputStream 4.java.io.FileOutputStream5.java.io.FileSystem/Win32FileSystem/WinNTFileSystem/UnixFileSystem 6.sun.nio.fs.UnixFileSystemProvider/WindowsFileSystemProvider 7.java.io.RandomAccessFile 8.sun.nio.fs.CopyFile 9.sun.nio.fs.UnixChannelFactory 10.sun.nio.fs.WindowsChannelFactory 11.java.nio.channels.AsynchronousFileChannel 12.FileUtil/IOUtil 13.filePath/download/deleteFile/move/getFile
在使用这些函数,关键字,类时,对用户传递来的文件对象/文件名/文件路径,是否进行了正确的处理:
•是否限制了可操作文件的路径,文件类型,文件所有者;•是否将敏感文件进行了排除;•查找getPath(),getAbsolutePath(),查看是否有错误的路径判断;•在排查程序的安全策略配置文件,全局搜索permission,Java.io.FilePermission,grant的字样,是否给程序的某部分路径赋予了读写权限;
通过对这些函数进行查找“new File(”发现在代码中有可疑的地方,然后跟踪到代码中进行查看接着跟踪rootpath函数,看到这段代码发现它定义了一个名为UserpanelController的方法,主要功能是获取项目的路径, 并将其存储在rootpath变量中。并且没有对用户输入的参数进行过滤。
•使用ResourceUtils类的getURL方法获取项目的路径,路径是从classpath开始的•使用getPath方法获取到完整的路径字符串•使用URLDecoder类的decode方法将得到的路径字符串进行解码,使用'utf-8'的字符集•最后打印解码之后的路径
接着就是构造数据包,尝试把这个漏洞复现出来。当时复现的时候一直出现错误。正常情况下使用../就可以成功绕过限制读取文件的,但是使用这个方法一直报错400
我又回到File f = new File(rootpath, path);处看到上面有个path定义的信息发现需要加下/show才能实现读取文件信息
最终构造的数据包如下:
GET /show/../show/../show/../show/../show/../show/1/1.txt HTTP/1.1
Host: 127.0.0.1:9999
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0
Cookie: JSESSIONID=96A7564DE31207D139967EE32CE058A3
四、总结
经过本次分析学到了很多知识,仍有许多不足,欢迎师傅们提议意见或者建议,大家一起交流~
References
[1]
: http://127.0.0.1:9999
[2]
: http://127.0.0.1:9999/addrmanage
[3]
: http://127.0.0.1:9999/file/2024/07/admin/4ba3a1a2-56f7-412a-bc48-6c4fa4b29ea7.txt
原文始发于微信公众号(云鸦安全):【笔记】java代码审计入门
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论