Java代码审计篇 | ofcms系统审计思路讲解 - 篇3 | 文件上传漏洞审计
文章目录
- 0. 前言
- 1. 文件上传代码审计【有1处】
- 1.1 可疑点1【无漏洞】
- 1.1.1 直接搜索upload关键字
- 1.1.2 选择第一个,点进去分析一下
- 1.1.3 分析this.getFile()方法
- 1.1.4 分析new MultipartRequest(request, uploadPath)
- 1.1.5 分析isSafeFile()方法
- 1.1.6 分析request.getFiles()方法
- 1.1.7 验证文件的过滤方式,并尝试找到绕过之法(毕竟是黑名单\[\偷笑])
- 1.1.8 这里,这个点就到此结束,总结一下:
- 1.2 可疑点2【无漏洞】
- 1.3 可疑点3【跑偏的漏洞-路径遍历读取.xml文件】
- 1.3.1 搜索file关键字
- 1.3.2 分析getTemplates()方法
- 1.3.3 柳暗花明又一村
- 1.3.4 多点脑洞
- 1.4 可疑点4【有漏洞】
- 1.4.1 分析save()方法
- 1.4.2 利用漏洞写入jsp马
- 1.5 最后结尾
- 1.5.1 例1:SystemUtile类下
- 1.5.2 例2:GenUtils类下,都是创建固定名称的文件,并非文件上传
- 1.5.3 例3:换关键字write搜索,基本都是分析过的,要不就是无用的
0. 前言
我发现很多文章包括教程,大概套路是:只说有漏洞的点,将有漏洞的点指出,然后分析代码;或者黑盒测试出漏洞之后,然后分析代码。
我认为这是在分析漏洞代码,而非代码审计。代码审计文章或教程应该是从0开始找到漏洞所在,包括思路!
所以这里不管有没有漏洞,我都会把审计过程写出来,因此篇幅会很长,但我认为这样对你会很有帮助。
知其然亦知所以然。
由于篇幅较长,因此我会分几篇进行,本篇是整个系列的第3篇,讲解1个内容:
- 文件上传漏洞审计
本系列文章:
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇1 | 环境搭建、路由机制
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇2 | SQL注入漏洞审计
- Java代码审计篇 | ofcms系统审计思路讲解 - 篇3 | 文件上传漏洞审计
搭建好环境,确定好项目结构之后,按我思路是应该审计项目所使用框架漏洞的,这里关于框架漏洞就放最后篇章来说了,我们想了解下基础漏洞的审计~
文章中有错误点,或者思路上有什么问题的,欢迎师傅们留言指出~
1. 文件上传代码审计【有1处】
文件上传漏洞我们需要着重关注的是文件在被java代码解析到保存下来之间有无验证过滤,因此什么样的上传方式,什么样的保存方式都不重要,大家着重关注代码对文件的验证过滤手段即可。
文件上传代码审计常搜索的关键字如下:
file
upload
write
fileName
filePath
getPart
FileOutputStream
transferTo
getRealPath
FileItem
ServletFileUpload
DiskFileItemFactory
....
1.1 可疑点1【无漏洞】
1.1.1 直接搜索upload关键字

1.1.2 选择第一个,点进去分析一下
类名为UeditorAction
可以在当前页面搜索upload关键字,也可以同时参考该类的所有方法名称。

大概看一下,四个方法的写法是差不多的:
- getFile()方法的第2个参数不太相同,通过参数名称uploadPath可以大概判断出来,这个参数表示的是文件上传路径,也就是说调用不同的方法会保存到不同的目录。




通过下方的msg.put("url", "/upload/image/" + file.getFileName())也可以大体确定这一点;
当然msg.put不是用来保存文件用的,只是返回的信息而已。

以uploadImage()方法为例进行分析,可以看到,这个方法内部与保存文件相关的代码就前面两行(后面的都是关于返回的消息相关了),即
UploadFile file = this.getFile("file", "image");file.getFile().createNewFile();
我们先分析下this.getFile()方法
1.1.3 分析this.getFile()方法
点击进入看一下:

getFile()方法,首先调用了getFiles(uploadPath),跟进之下:就在上面
可以看到这里先做了个判断,判断request对象是否是MultipartRequest类型的对象,如果不是则创建一个新的MultipartRequest类型的对象,总之就是保证request对象是MultipartRequest类型的对象。
然后调用.getFiles()方法。
额外的:其中request对象就是HttpServletRequest,相关代码如下:
这里目前来看,需要有两个点需要分析:
- 1)
new MultipartRequest(request, uploadPath) - 2)
request.getFiles()
接下来先分析new MultipartRequest(request, uploadPath)
1.1.4 分析new MultipartRequest(request, uploadPath)
点击进入:

一个构造方法,先调用了父类,然后调用了wrapMultipartRequest()
- 父类可以点击去看看,其实没啥
- 着重看下
wrapMultipartRequest()
点击进入wrapMultipartRequest(),代码比较长,大概意思已标注:

其中我们需要关注的是文件的过滤代码,也就是图中红框位置:
if (isSafeFile(uploadFile)) {uploadFiles.add(uploadFile);
}
这里面调用了一个isSafeFile()方法,进去看一看:
1.1.5 分析isSafeFile()方法

发现这里有了验证过滤:
- 首先是对文件名去空白字符,然后转成小写
- 其次是文件名如果是
.jsp或者.jspx结尾则删除,返回false
师傅们可以想一下有无绕过手段
如果没有问题,则将文件add进入uploadFiles列表中。
1.1.6 分析request.getFiles()方法
然后接下来点进2.1.3步骤中的this.getFile()方法中的getFiles()方法进行分析

进来之后,发现方法中没有太多语句,只是直接返回了uploadFiles,也就是上一步所说的uploadFiles列表,这里面存放的是经过过滤的文件。

到此为止,其实已经差不多了,已经找到了文件的过滤方式:
- 首先是对文件名去空白字符,然后转成小写
- 其次是文件名如果是
.jsp或者.jspx结尾则删除,返回false
刚开始所说的
uploadImage()方法中的第2条语句 file.getFile().createNewFile();这里没什么,就是通过返回的经过过滤的file对象来创建一个新的文件。
那么接下来可以验证一下:
1.1.7 验证文件的过滤方式,并尝试找到绕过之法(毕竟是黑名单[\偷笑])
根据前面所说的路由机制,可以确定此uploadImage()方法的调用需要访问admin/ueditor/uploadImage.json

前端找一下呗。怎么找?搜呗…哎真麻烦,说实话好难找啊
根据路径大致判断范围:ueditor,貌似在哪见过这个词?
原来是个富文本编辑器,还好我“见多识广”哈哈

那就在前端找一下哪里有富文本,同时在控制台搜索着ueditor:

经过了九九八十一天,终于找到了。
那admin/ueditor/uploadImage.json应该就是在富文本上传图片时触发的吧:尝试一下
uploadImage()方法打上断点,yakit也开启抓包拦截

先来个普通图片试一试

大事不妙!之前分析的路由机制不太对,这里怎么是/admin/ueditor/handler.html?action=uploadImage
- 这里我懒得分析了,懂的师傅可以留个言~么么哒

不过没关系,放包!uploadImage()方法触发了。也就是功能和方法对上了!

在下面也可以看到上传路径在:D:\Program Files\tomcat\apache-tomcat-8.0.17\webapps\ofcms_admin_war\upload\image
当然在返回包中,也可以看到上传路径

访问一下,可以访问到。

接下来尝试绕过一下,已知文件过滤方式
- 首先是对文件名去空白字符,然后转成小写
- 其次是文件名如果是
.jsp或者.jspx结尾则删除,返回false
绞尽脑汁~貌似只有一个方式:文件名后面加.绕过,但是这种好像只适用于windows。
来都来了,试一下吧,谁让我现在用的电脑是windows。
这里我直接修改了数据包,将文件名改成了.jsp.,文件内容用的是冰蝎生成的jsp马子。

这里idea就先不debug了,直接放包,上传成功。
可以到目录中看一下,有没有上传成功:

嘿嘿,成功,同时后缀是.jsp。
接下来就是看看能不能连接了…
测试了下,不太行,虽然能上传,但是不能解析。
这里为了避免中文问题,我改成了webshell.jsp

怎么办?目录穿越试一试,哈哈哈

经过三天三夜的调试,找到了文件名处理的源码(这里过程就不粘出来了,自己可以调一下,如果想看过程,评论区留个言,给兄弟们安排上[\狗头])
- 先计算
/的位置 - 然后进行原始文件名的截取
即文件名为../../../webshell.jsp.,最终文件名也将变为webshell.jsp.

1.1.8 这里,这个点就到此结束,总结一下:
- 该位置的文件上传可以任意上传除
.jsp和.jspx的文件,但是没什么luan用。 - 当然如果是windows是可以通过加
.绕过的,不过解析不了。 - 尝试目录穿越,有代码会将路径截取掉。
成果:0day无,分析经验+1
1.2 可疑点2【无漏洞】
分析第二个ComnController类中的:

进来之后发现,写法和之前是差不多的,同样使用了getFile()方法,怎么办?放弃!
后面使用了
getFile()方法的,直接放弃就好了。

换目标!
这里多说一下,其实我们搜的这些,都是jfinal组件中的upload,漏洞基本没有,如果有,那就是组件0Day了。不过分析分析源码也是好的。

1.3 可疑点3【跑偏的漏洞-路径遍历读取.xml文件】
通过upload搜索的,翻了一圈,不是UeditorAction类,就是ComnController类,没有别的可疑的了。换关键字搜索。
1.3.1 搜索file关键字
找到一个TemplateController类中导入了File。进入看看

文件中搜索下file,85个,真不少

进来之后,大概浏览一遍,该类中其中两个方法getTemplates() 和save()方法中存在文件相关的功能代码,所以这里分开来分析下。先分析getTemplates()
【其实这里不需要分析的,因为它是获取文件用的,没有写入文件保存文件的功能,和文件上传无关】。
既然来都来了,看一下吧~

1.3.2 分析getTemplates()方法
方法代码如下:



首先看前面三行,getPara()方法获取参数值,获取不到,会有默认值:

点进getPara()方法,进来一看:欣喜若狂啊
直接通过request.getParameter(name)获取参数值,也就是说,目录可控啊~

继续往下分析
这一块就没啥了,就是将String类型的路径,封装一下,变成对象。顺便还做了一下验证处理。
- 其中画红框位置表示:pathFile.listFiles表示目录下的文件或目录,然后通过FileFilter做了一下验证,判断是否是目录,是目录的放入dirs列表中。

- 其中的
setAttr()方法,是将目录对象保存到request对象中。

继续向下分析:这里和之前的差不多,只不过是通过FileFilter限制了白名单文件,即将.html、.xml、.css、.js的文件放入到了files列表中。

继续向下分析:这段代码作用就是页面上默认显示的模版文件,传入的文件名如果没有则显示files列表中的第一个(所以没有任意文件读取~哈哈哈)

最后返回resource.html或者是index.html

没有文件上漏洞!
1.3.3 柳暗花明又一村
但是别急,回想下,最开始说该方法获取的前端参数可控,即目录可控,那我们能不能不去获取默认路径下的.html、.xml、.css、.js文件。
直接验证了,前端找到对应功能点,还是那个熟悉的模版~
随便点个模版,yakit拦截下~

默认参数是这样的:
- file_name=contact.html
- dir=/
- dir_name=/

对照下源码,dir是当前目录,file_name是查看的文件


那么修改一下,读取网站下的web.xml试一试

而默认读取的根目录是webapps\ofcms_admin_war\WEB-INF\page\default

所以我们构造dir=../../../../ROOT/WEB-INF和file_name=web.xml

成功读取!经验+1

1.3.4 多点脑洞
既然这里可以读取web.xml,并且下方可以保存,那我们是不是就可以修改web.xml文件了呢?
尝试修改保存一下,出现请求异常~

直接调试下,在save()方法处打个断点,发现是因为dirs参数值即dirName中存在../因此被拒绝了。

这里其实很好绕过,聪明的你一点发现了,前面还有个参数:res_path
我们可以修改res_path的值和dirs参数的值,来达到修改web.xml的目的。
这里师傅们可以自己尝试下,因为这里和下面的save()方法的分析是一样的,就放一起说了。
1.4 可疑点4【有漏洞】
从上一个分析,发现save()方法其实是有问题的,接下来着重分析一下。
1.4.1 分析save()方法
代码就这么长:

首先看:

这里从前端获取“res_path”的参数值,前面也说过,getPara()获取的值是可控的。
然后通过res_path的值决定pathFile是什么内容,这里其实不用管,因为不管res_path是什么,pathFile都是固定的,不是SystemUtile.getSiteTemplateResourcePath()就是SystemUtile.getSiteTemplatePath(),没有可变的地方。
接下来是这段,也是核心:

首先从前端获取“dirs”参数的值,不过这个值中不能存在../,也就是说这个参数不能是利用点了。
然后从前端获取“file_name”参数的值,没有任何限制。
最后从前端获取“file_content”参数的值,仅仅对<和>做了转义。
然后就是新建文件,调用FileUtils.writeString(file, fileContent)写入内容。
writeString方法如下:直接调用FileOutputStream.write()写的,没有别的过滤。

分析下来之后,可以利用的点为:file_name和file_content。
文件名和文件内容都可控,这不就是妥妥的任意文件写入(可以理解为任意文件上传)。
1.4.2 利用漏洞写入jsp马
那直接写个jsp马进去!当然,可能解析不了。
file_name和file_content都替换掉,最后别忘了file_content的值使用URL编码一下
- 这里我用的是冰蝎jsp马

成功写入:

访问连接:但是会发现连接失败,看来当前目录下不能直接访问,或者是jsp不解析

继续尝试别的目录:file_name=…/…/…/webshell.jsp

也是失败。
这里尝试在static目录,是可以的。file_name=../../../static/webshell.jsp

小tips:static目录是静态目录,一般文件是可以直接访问。

命令成功执行!撒花~

1.5 最后结尾
最后搜索了其他的类和关键字,没有可以分析利用的点了。师傅们看看就好。
1.5.1 例1:SystemUtile类下


1.5.2 例2:GenUtils类下,都是创建固定名称的文件,并非文件上传



1.5.3 例3:换关键字write搜索,基本都是分析过的,要不就是无用的

文件上传漏洞代码审计到此为止,希望师傅们有所收获,如有问题,评论区留言~
也可扫码加好友,一起进步~

相关文章:
Java代码审计篇 | ofcms系统审计思路讲解 - 篇3 | 文件上传漏洞审计
文章目录 0. 前言1. 文件上传代码审计【有1处】1.1 可疑点1【无漏洞】1.1.1 直接搜索upload关键字1.1.2 选择第一个,点进去分析一下1.1.3 分析this.getFile()方法1.1.4 分析new MultipartRequest(request, uploadPath)1.1.5 分析isSafeFile()方法1.1.6 分析request.…...
【Kubernetes】常见面试题汇总(五)
目录 13.简述 Kubernetes Replica Set 和 Replication Controller 之间有什么区别? 14.简述 kube-proxy 作用? 15.简述 kube-proxy iptables 原理? 16.简述 kube-proxy ipvs 原理? 13.简述 Kubernetes Replica Set 和 Replicat…...
MySQL 解决时区相关问题
在使用 MySQL 的过程中,你可能会遇到时区相关问题,比如说时间显示错误、时区不是东八 区、程序取得的时间和数据库存储的时间不一致等等问题。其实,这些问题都与数据库时区设 置有关。 MySQL Server 中有 2 个环境变量和时区有关,…...
SpringSecurity Context 中 获取 和 更改 当前用户信息的问题
SpringSecurity Context 获取和更改用户信息的问题 SecurityContext 异步线程中获取用户信息 今天在做项目时遇到了一个问题,我需要获取当前用户的 ID。之前,前端并没有存储用户信息,我一直是在后端的 service 中通过 SecurityContext 来获…...
Makefile的四种赋值运算符
Makefile有四种赋值运算符:简单赋值(:)、递归赋值()、条件赋值(?)和追加赋值() 1. 简单赋值(:) 作用:覆盖之前的值。若在多次简单赋…...
framebuffer
framebuffer:帧缓冲、帧缓存 Linux内核为显示提供的一套应用程序接口(驱动内核支持) 分辨率:像素点的总和 像素点: 显示屏:800*600(横向有800个像素点,纵向有600个像素点&#x…...
7.科学计算模块Numpy(4)ndarray数组的常用操作(二)
引言 书接上回,numpy能作为python中最受欢迎的数据处理模块,脱离不了它最核心的部件——ndarray数组。那么,我们今天就来了解一下numpy中对ndarray的常用操作。 通过阅读本篇博客,你可以: 1.掌握ndarray数组的分割 …...
抖音评论区截流脚本软件详细使用教学,抖音私域获客引流的五种方法。
1.先说下什么是抖音截流玩法,截流顾名思义就是在别的博主的视频下面去截流评论潜在流量,然后用评论文案的形式或者其它方式吸引用户加我们的私域~ 玩截流一定不是主动去私信别人,这个就不叫截流了,且一个账号私信多了一定会降权和…...
Linux_kernel移植uboot07
一、移植 根据硬件平台的差异,将代码进行少量的修改,修改过后的代码在目标平台上运行起来 移植还需要考虑硬件环境,驱动只需要考虑内核的环境 二、移植内容 1、移植Uboot uboot属于bootloader的一种,还有其他的bootloader&#x…...
Day-04-QFile打开文件的两种方式
一、UI界面设置两个按键,并直接转到槽函数 二、两种代码展示 #include <QFile> #include <QDebug>//此两种方式中调用函数,应包含的头文件void Widget::on_btnReadFile01_clicked()//第一种打开方式 {//1. 打开文件QFile file;file.setFile…...
第三部分:4---进程地址空间
目录 数组的空间分配解析: 物理地址和虚拟地址: 虚拟地址空间: 进程地址空间的本质: 为什么要有进程地址空间? 页表对进程访问内存的检查: 进程地址空间和页表如何关联起来? 进程的独立…...
【Android】程序开发组件—探究Jetpack
引言 Jetpack是一个开发组件工具集,它的主要目的是帮助我们编写出更加简洁的代码,并简化我们的开发过程,在这么多的组件当中,最需要我们关注的其实还是架构组件,接下来就对Jetpack的主要架构组件进行学习!…...
pytorch torch.norm函数介绍
torch.norm 函数用于计算张量的范数(norm),可以理解为张量的“长度”或“大小”。根据范数的不同类型,它可以衡量不同的张量性质。该函数可以计算 向量 和 矩阵 的多种范数,如 L1范数、L2范数、无穷范数 等。 1. 函数…...
【lc_hot100】刷题心得
链表 二叉树 二叉树相关的题目基本都有个基本的框架,基本框架就是二叉树的四种遍历方法:前序遍历、中序遍历、后序遍历、层序遍历 往往常用的是前序遍历和中序遍历 图 图跟二叉树一样都有自己的的基本框架,基本框架就是图的两种遍历方法&am…...
FANUC 数控 A06B-6058-H227 伺服放大器
发那科伺服放大器是一种控制电机的电子装置,属于电机控制系统的一部分,用于将输入信号放大并转换成电动机可以理解的信号,从而实现运动控制和定位。 发那科伺服放大器的主要作用包括: 实现运动控制:通过控制…...
Python将表格文件中某些列的数据整体向上移动一行
本文介绍基于Python语言,针对一个文件夹下大量的Excel表格文件,对其中的每一个文件加以操作——将其中指定的若干列的数据部分都向上移动一行,并将所有操作完毕的Excel表格文件中的数据加以合并,生成一个新的Excel文件的方法。 首…...
基于YOLOv8的PCB缺陷检测算法,加入一种基于内容引导注意力(CGA)的混合融合方案(一)
💡💡💡本文内容:针对基于YOLOv8的PCB缺陷检测算法进行性能提升,加入各个创新点做验证性试验。 1)提出了一种基于内容引导注意力(CGA)的混合融合方案,mAP0.5由原始的0.966提升至0.975 1.PCB缺陷…...
如何在红米手机中恢复已删除的照片?(6 种方式可供选择)
凭借出色的相机和实惠的价格,小米红米系列已成为全球知名品牌。但是,最近有些人抱怨他们在 红米设备上丢失了许多珍贵的图片或视频,并希望弄清楚如何从小米手机恢复已删除的照片。好吧,在小米设备上恢复已删除的视频/照片并不难。…...
嵌入式实时操作系统(RTOS):原理、应用与发展
摘要:本文围绕嵌入式实时操作系统(RTOS)展开。首先介绍嵌入式系统与实时操作系统的概念,阐述嵌入式 RTOS 的体系结构。接着分析其关键特性,包含任务管理(如任务的创建与删除、调度、同步与通信)…...
C#里使用位图容器BitArray
由于经常需要操作一些位表示的数据结构,那么就需要采用位图的管理方式。 在C#里就是使用BitArray来管理位图数据结构,这样就比较方便处理。 这个类可以有多种构造函数,可以满足绝大部分的要求。 比如从网络协议里传送过来的字节流,就可以直接写入到里面,就可以直接获取…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

