/** * @name Deserialization of user-controlled data (Apache Struts) * @description Deserializing user-controlled data may allow attackers to * execute arbitrary code. * @kind path-problem * @problem.severity error * @precision high * @id java/unsafe-deserialization * @tags security * external/cwe/cwe-502 */ import java import UnsafeDeserialization import semmle.code.java.dataflow.DataFlow3::DataFlow3 as DF import DF::PathGraph /** The interface `org.apache.struts2.rest.handler.ContentTypeHandler`. */ class ContentTypeHandler extends RefType { ContentTypeHandler() { this.hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler") } } /** A `toObject` method on a subtype of `org.apache.struts2.rest.handler.ContentTypeHandler`. */ class ContentTypeHandlerDeserialization extends Method { ContentTypeHandlerDeserialization() { this.getDeclaringType().getASupertype*() instanceof ContentTypeHandler and this.hasName("toObject") } } /** * The first parameter of a `toObject` method on a `ContentTypeHandler`, which is * a source of tainted user data. */ class ContentTypeHandlerInput extends DF::Node { ContentTypeHandlerInput() { this.asParameter() = any(ContentTypeHandlerDeserialization des).getParameter(0) } } /** * Configuration that tracks the flow of taint from the first parameter of * `ContentTypeHandler.toObject` to an instance of unsafe deserialization. */ class StrutsUnsafeDeserializationConfig extends DF::Configuration { StrutsUnsafeDeserializationConfig() { this = "StrutsUnsafeDeserializationConfig" } override predicate isSource(DF::Node source) { source instanceof ContentTypeHandlerInput } override predicate isSink(DF::Node sink) { sink instanceof UnsafeDeserializationSink } } from DF::PathNode source, DF::PathNode sink, StrutsUnsafeDeserializationConfig conf where conf.hasFlowPath(source, sink) and sink.getNode() instanceof UnsafeDeserializationSink select sink.getNode().(UnsafeDeserializationSink).getMethodAccess(), source, sink, "Unsafe deserialization of $@.", source, "user input"