Spring Framework RCE,初期公告

工程 | Rossen Stoyanchev | 2022 年 3 月 31 日 | ...

更新

目錄

總覽

我想公告 Spring Framework 中的 RCE 漏洞,該漏洞在 CVE 發佈之前已洩露。此問題最初由 AntGroup FG 的 codeplutos、meizjm3i 在週二晚上深夜,格林威治標準時間午夜時分,回報給 VMware。週三,我們致力於調查、分析、找出修復方法、測試,同時目標是在週四緊急發佈。與此同時,同樣在週三,詳細資訊在網路上完整洩露,這就是為什麼我們要在發佈和 CVE 報告之前提供此更新。

漏洞

此漏洞會影響在 JDK 9+ 上執行的 Spring MVC 和 Spring WebFlux 應用程式。特定的漏洞利用需要將應用程式打包並部署為 Servlet 容器上的傳統 WAR 檔。如果應用程式以 Spring Boot 可執行 jar 檔(即預設值)部署,則不會受到此漏洞的影響。但是,此漏洞的本質更為廣泛,可能還有其他利用它的方法。

我是否受到影響?

以下是報告中特定情境的需求

其他註記

  • 此漏洞涉及 ClassLoader 存取,並取決於實際使用的 Servlet 容器。已知 Tomcat 10.0.19、9.0.61、8.5.77 和更早版本容易受到攻擊。Payara 和 Glassfish 也已知容易受到攻擊。其他 Servlet 容器也可能容易受到攻擊。
  • 此問題與資料綁定有關,資料綁定用於從請求參數(查詢參數或表單資料)填充物件。資料綁定用於使用 @ModelAttribute 註解或選擇性地不使用註解,且不使用任何其他 Spring Web 註解的控制器方法參數。
  • 此問題與 @RequestBody 控制器方法參數(例如 JSON 反序列化)無關。但是,如果此類方法具有另一個透過資料綁定從查詢參數填充的方法參數,則它們仍然可能容易受到攻擊。

狀態

  • 包含修復程式的 Spring Framework 5.3.18 和 5.2.20 已發佈。
  • 依賴 Spring Framework 5.3.18 的 Spring Boot 2.6.6 和 2.5.12 已發佈。
  • CVE-2022-22965 已發佈。
  • Apache Tomcat 已發佈版本 10.0.20、9.0.62 和 8.5.78,這些版本從 Tomcat 端封鎖了攻擊途徑,請參閱Spring Framework RCE,替代緩解措施

建議的解決方案

建議的回應是更新至 Spring Framework 5.3.185.2.20 或更高版本。如果您已完成此操作,則無需任何解決方案。但是,有些人可能處於無法快速升級的情況。因此,我們在下面提供了一些解決方案。

請注意,解決方案不一定是互斥的,因為安全最好「深入」完成。

升級 Tomcat

對於在 Tomcat 上執行且 Spring Framework 版本不受支援的舊版應用程式,升級至 Apache Tomcat 10.0.209.0.628.5.78 可提供足夠的保護。但是,這應視為一種戰術解決方案,主要目標應是盡快升級到目前受支援的 Spring Framework 版本。如果您採用這種方法,也應考慮設定禁止的欄位以進行深度防禦。

降級至 Java 8

如果您既無法升級 Spring Framework 也無法升級 Apache Tomcat,則降級至 Java 8 是一種可行的解決方案。

禁止的欄位

另一個可行的解決方案是透過在全域設定 WebDataBinder 上的 disallowedFields 來停用與特定欄位的繫結


@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class BinderControllerAdvice {

    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder) {
         String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
         dataBinder.setDisallowedFields(denylist);
    }

}

這通常有效,但作為集中應用的解決方案修復程式,可能會留下一些漏洞,特別是當控制器透過自己的 @InitBinder 方法在本機設定 disallowedFields 時,這會覆寫全域設定。

為了以更安全的方式應用解決方案,應用程式可以擴充 RequestMappingHandlerAdapter 以在所有其他初始化之後在最後更新 WebDataBinder。為了做到這一點,Spring Boot 應用程式可以宣告 WebMvcRegistrations Bean (Spring MVC) 或 WebFluxRegistrations Bean (Spring WebFlux)。

例如在 Spring MVC 中 (WebFlux 中類似)

package car.app;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.InitBinderDataBinderFactory;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;


@SpringBootApplication
public class MyApp {


	public static void main(String[] args) {
		SpringApplication.run(CarApp.class, args);
	}


	@Bean
	public WebMvcRegistrations mvcRegistrations() {
		return new WebMvcRegistrations() {
			@Override
			public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
				return new ExtendedRequestMappingHandlerAdapter();
			}
		};
	}


	private static class ExtendedRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {

		@Override
		protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> methods) {

			return new ServletRequestDataBinderFactory(methods, getWebBindingInitializer()) {

				@Override
				protected ServletRequestDataBinder createBinderInstance(
						Object target, String name, NativeWebRequest request) throws Exception {
					
					ServletRequestDataBinder binder = super.createBinderInstance(target, name, request);
					String[] fields = binder.getDisallowedFields();
					List<String> fieldList = new ArrayList<>(fields != null ? Arrays.asList(fields) : Collections.emptyList());
					fieldList.addAll(Arrays.asList("class.*", "Class.*", "*.class.*", "*.Class.*"));
					binder.setDisallowedFields(fieldList.toArray(new String[] {}));
					return binder;
				}
			};
		}
	}
}

對於沒有 Spring Boot 的 Spring MVC,應用程式可以從 @EnableWebMvc 切換為直接擴充 DelegatingWebMvcConfiguration,如文件進階設定章節中所述,然後覆寫 createRequestMappingHandlerAdapter 方法。

誤解

有人猜測圍繞著棄用 SerializationUtils 的提交。此類別在框架內只有一種用法,並且不會暴露於外部輸入。棄用與此漏洞無關。

對於Spring Cloud Function 的 CVE 存在混淆,該 CVE 在此漏洞報告之前發佈。它也無關。

取得 Spring 電子報

隨時掌握 Spring 電子報的最新消息

訂閱

領先一步

VMware 提供訓練和認證,以加速您的進展。

瞭解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

瞭解更多

即將舉行的活動

查看 Spring 社群中所有即將舉行的活動。

檢視全部