-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Vulnerability ID: LYZM-6GE9-8K14-4GLB
Application Name: CargoCats-contrast-cargo-cats-frontgateservice
Vulnerability Link: https://eval.contrastsecurity.com/Contrast/static/ng/index.html#/545a3bce-97c5-4732-af38-1ac459087b0a/applications/0f3e06e4-d3c5-47a3-a2ce-ce43b8dc3e17/vulns/LYZM-6GE9-8K14-4GLB
What Happened?
We tracked the following data from Request Body:
POST /api/addresses/import
[ HTTP body not captured ]
...which was accessed within the following code:
com.contrast.frontgateservice.controller.ApiController#importAddresses(), line 430
...and ended up being deserialized ({{#link}}https://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html$$LINK_DELIM$$ObjectInputStream{{/link}}) with code that looks like this:
obj = stream.readObject()
What's the risk?
The application deserializes Java objects from an untrusted source. Because the source is untrusted, the application must consider that it may not be the expected type. An attacker could submit an object whose type is any Java class on the application's classpath.
Attackers could choose a class with a Serializable#readObject() method that can be re-purposed towards malicious ends. There have been several commonly available classes can be used to effect remote code execution.
Recommendation
There are only a few options for securing the deserialization of untrusted objects. The first, and most safe option, is to remove the deserializing of untrusted input completely. Although the recommendations today appear to be totally effective, it's worth noting that attacks against serialization have been getting more effective for many years. The consensus amongst security researchers is that developers should be moving away from Java's serialization when possible.
If serialization must occur on untrusted data, the ObjectInputStream must be hardened to ensure only the expected classes are being deserialized. Here is an example of vulnerable code:
InputStream untrustedStream = request.getInputStream();
ObjectInputStream in = new ObjectInputStream(untrustedStream);
Acme acmeObject = (Acme)in.readObject();
By overriding the ObjectInputStream#resolveClass() method, we can ensure that only the expected classes are deserialized. In the following secure example, only the Acme and String classes will be allowed to be deserialized. Anything else seen will cause a SecurityException to be found:
InputStream untrustedStream = request.getInputStream();
List<Class> safeClasses = Arrays.asList(new Class[] { Acme.class, String.class });
ObjectInputStream in = new ObjectInputStream(untrustedStream) {
protected Class<?> resolveClass(ObjectStreamClass desc) {
Class<?> clazz = null;
try {
clazz = super.resolveClass(desc);
if (clazz.isArray() || clazz.isPrimitive() || safeClasses.contains(clazz) ) {
return clazz;
}
} catch (ClassNotFoundException | IOException e) {
throw new SecurityException("Attempt to deserialize unauthorized class: " + clazz.getName());
}
}
};
Acme acmeObject = (Acme)in.readObject();
Check out our AI-generated Intelligent Remediation Guidance! https://eval.contrastsecurity.com/Contrast/static/ng/index.html#/545a3bce-97c5-4732-af38-1ac459087b0a/vulns/LYZM-6GE9-8K14-4GLB/overview/recommendation
First Event
Stack:
org.apache.catalina.core.ApplicationPart.getInputStream(ApplicationPart.java:97)
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getInputStream(StandardMultipartHttpServletRequest.java:254)
com.contrast.frontgateservice.controller.ApiController.importAddresses(ApiController.java:429)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0()
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke()
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke()
java.base/java.lang.reflect.Method.invoke()
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
javax.servlet.http.HttpServlet.service(HttpServlet.java:555)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
Last Event
Stack:
java.base/java.io.ObjectInputStream.readObject()
com.contrast.frontgateservice.controller.ApiController.importAddresses(ApiController.java:430)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0()
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke()
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke()
java.base/java.lang.reflect.Method.invoke()
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
javax.servlet.http.HttpServlet.service(HttpServlet.java:555)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)HTTP Request
POST http://cargocats.localhost:80/api/addresses/import HTTP/1.1
Accept: /
Accept-Encoding: gzip, deflate
Content-Length: 3328
Content-Type: multipart/form-data; boundary=e360a79f45704334435a4f0b03a33c64
Cookie: JSESSIONID=903F43FB86C14239EC9DB486B26F6436
Host: cargocats.localhost
User-Agent: python-requests/2.31.0
X-Forwarded-Host: cargocats.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Scheme: http
X-Real-Ip: 10.1.5.76
X-Request-Id: 5190b4b86dcf33c9a2de87d44970a72c
X-Scheme: http
References
https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/
https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html
Session ID: eeb7a07a32284bacbd32ec513b0b4147
artifactHash: b91aebb6