Java代码审计篇 | ofcms系统审计思路讲解 - 篇3 | 文件上传漏洞审计

0. 前言

我发现很多文章包括教程,大概套路是:只说有漏洞的点,将有漏洞的点指出,然后分析代码;或者黑盒测试出漏洞之后,然后分析代码。

我认为这是在分析漏洞代码,而非代码审计。代码审计文章或教程应该是从0开始找到漏洞所在,包括思路!

所以这里不管有没有漏洞,我都会把审计过程写出来,因此篇幅会很长,但我认为这样对你会很有帮助。

知其然亦知所以然。

由于篇幅较长,因此我会分几篇进行,本篇是整个系列的第3篇,讲解1个内容:

  • 文件上传漏洞审计

本系列文章:

搭建好环境,确定好项目结构之后,按我思路是应该审计项目所使用框架漏洞的,这里关于框架漏洞就放最后篇章来说了,我们想了解下基础漏洞的审计~

文章中有错误点,或者思路上有什么问题的,欢迎师傅们留言指出~

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-INFfile_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搜索,基本都是分析过的,要不就是无用的

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

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值