
Apache Struts 1 のクラスパラメータ操作(CVE-2014-0114)に関する技術分析と概念実証であり、Tomcat 上でのリモートコード実行と JBoss/Wildfly 上でのサービス拒否を実証しています。
POST または GET リクエストのパラメータは、フォームを基点として設定されるプロパティとして扱われます。パラメータは入れ子になったオブジェクトへのパスとなる可能性があります。
Apache Struts 1.x は Form Beans 上で getClass() を呼び出すよう操作される可能性があります。例えば、フォームのクラスローダーの属性を直接操作できます: https://example.com/?class.classLoader.defaultAssertionStatus=true。
内部的に、Apache Struts 1.x は commons-beanutils を使用していますが、バージョン 1.8 (およびそれ以前) では class 属性を除外していません。
Struts 2 にも同様の欠陥がありましたが、ここでは Struts 1.x に焦点を当てます。このフレームワークにはパッチが存在せず、最新バージョンは 2008 年にリリースされました (2013 年以降 EOL)。
アプリケーションが Tomcat (Catalina) で実行されている場合、ログを操作して攻撃者が JSP ファイルを作成し、サーバーにリクエストするとその JSP ファイルが実行されるようにすることが可能です。JSP ファイルは任意の Java コードを、Java プロセスを実行しているユーザーとして実行できます。
詳細は Julián Vilas のデモを参照してください。
(JBoss EAP 7.1 でテスト済み)
JBoss を完全にアクセス不能にし、再起動を必要とする最悪のケースを引き起こす可能性のある単純な DOS 攻撃方法があります。最良の場合でも JBoss の応答が遅くなります。
class 属性を介して Class#protectionDomain.codeSource.location にアクセスできます。JBoss では、これはプロトコル vfs を持つ URL オブジェクトです。
vfs:// タイプの URL に対して、JBoss は URLStreamHandler を登録しており、URL#getContent が呼び出されると org.jboss.vfs.VirtualFile 型のオブジェクトを返します。
class.protectionDomain.codeSource.location.content.pathName はディレクトリ <SÖKGVÄG>/<applikation>/WEB-INF/classes を指します。
parent を介して、1 つ上のレベルのディレクトリのオブジェクトにアクセスできます:
class.protectionDomain.codeSource.location.content.parent.pathName -> <SÖKVÄG>/<applikation>/WEB-INF
質問: ファイルシステムのルートに到達するには、いくつの parent 参照が必要ですか?
質問:
ファイルシステムのルートディレクトリに対して class.protectionDomain.codeSource.location.content.parent.parent.[...].childrenRecursively[0].pathName を要求するとどうなりますか?
回答:
JBoss はファイルシステム内のすべてのファイルを走査し、各ファイルとディレクトリに対して org.jboss.vfs.VirtualFile を割り当てます。
追加質問: 2 つのリクエストが同時にファイルシステム内のすべてのファイルを要求するとどうなりますか? 3 つ? 5 つ? 10 つ? 100 つ?
...
回答:
十分に待つと、次のエラーがログに記録されます
10:09:59,381 ERROR [io.undertow.request] (default task-13) UT005023: Exception handling request to /strutt/Login.do: javax.servlet.ServletException: javax.servlet.ServletException: BeanUtils.populate
at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:286)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:449)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1508)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:326)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:812)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.servlet.ServletException: BeanUtils.populate
at org.apache.struts.util.RequestUtils.populate(RequestUtils.java:475)
at org.apache.struts.chain.commands.servlet.PopulateActionForm.populate(PopulateActionForm.java:50)
at org.apache.struts.chain.commands.AbstractPopulateActionForm.execute(AbstractPopulateActionForm.java:60)
at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)
at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:305)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:191)
at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
... 42 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)