-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[java] CodeQL query, Increase fastjson detection. Improve RemoteFlowSource class, support SpringMvc. #3665
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
[java] CodeQL query, Increase fastjson detection. Improve RemoteFlowSource class, support SpringMvc. #3665
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
java/ql/src/Security/CWE/CWE-502/UnsafeDeserSpringMvc.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import com.alibaba.fastjson.JSON; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.yaml.snakeyaml.Yaml; | ||
|
||
import javax.servlet.http.HttpServletRequest; | ||
|
||
@RestController | ||
public class UnsafeDeserSpringMvc { | ||
|
||
@GetMapping(value = "index") | ||
public void index(HttpServletRequest request){ | ||
Yaml yaml = new Yaml(); | ||
yaml.load(request.getParameter("str")); | ||
Runtime runtime = Runtime.getRuntime(); | ||
HttpServletRequest request1 = request; | ||
} | ||
|
||
@GetMapping(value = "fastjson") | ||
public void fastjson(HttpServletRequest request){ | ||
JSON.parseObject(request.getParameter("str")); | ||
} | ||
|
||
@GetMapping(value = "test") | ||
public void fastjson1(String request){ | ||
String temp = request; | ||
JSON.parseObject(temp); | ||
} | ||
|
||
@GetMapping(value = "test1") | ||
public void fastjson2(String request){ | ||
System.out.println(request); | ||
JSON.parseObject(request); | ||
} | ||
|
||
@GetMapping(value = "test2") | ||
public void fastjson3(@RequestBody String request){ | ||
JSON.parseObject(request); | ||
} | ||
|
||
public void fastjson4(@RequestBody String request){ | ||
JSON.parseObject(request); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
/** | ||
* Provides classes representing various flow sources for taint tracking. | ||
*/ | ||
|
||
import java | ||
import semmle.code.java.dataflow.DataFlow | ||
import semmle.code.java.dataflow.TaintTracking | ||
import semmle.code.java.dataflow.DefUse | ||
import semmle.code.java.frameworks.Jdbc | ||
import semmle.code.java.frameworks.Networking | ||
import semmle.code.java.frameworks.Properties | ||
import semmle.code.java.frameworks.Rmi | ||
import semmle.code.java.frameworks.Servlets | ||
import semmle.code.java.frameworks.ApacheHttp | ||
import semmle.code.java.frameworks.android.XmlParsing | ||
import semmle.code.java.frameworks.android.WebView | ||
import semmle.code.java.frameworks.JaxWS | ||
import semmle.code.java.frameworks.android.Intent | ||
import semmle.code.java.frameworks.SpringWeb | ||
import semmle.code.java.frameworks.Guice | ||
import semmle.code.java.frameworks.struts.StrutsActions | ||
import semmle.code.java.frameworks.Thrift | ||
import semmle.code.java.frameworks.SpringMVC | ||
|
||
/** A data flow source of remote user input. */ | ||
abstract class RemoteFlowSource extends DataFlow::Node { | ||
/** Gets a string that describes the type of this remote flow source. */ | ||
abstract string getSourceType(); | ||
} | ||
|
||
private class RemoteTaintedMethodAccessSource extends RemoteFlowSource { | ||
RemoteTaintedMethodAccessSource() { | ||
this.asExpr().(MethodAccess).getMethod() instanceof RemoteTaintedMethod | ||
} | ||
|
||
override string getSourceType() { result = "network data source" } | ||
} | ||
|
||
private class RmiMethodParameterSource extends RemoteFlowSource { | ||
RmiMethodParameterSource() { | ||
exists(RemoteCallableMethod method | | ||
method.getAParameter() = this.asParameter() and | ||
( | ||
getType() instanceof PrimitiveType or | ||
getType() instanceof TypeString | ||
) | ||
) | ||
} | ||
|
||
override string getSourceType() { result = "RMI method parameter" } | ||
} | ||
|
||
private class JaxWsMethodParameterSource extends RemoteFlowSource { | ||
JaxWsMethodParameterSource() { | ||
exists(JaxWsEndpoint endpoint | | ||
endpoint.getARemoteMethod().getAParameter() = this.asParameter() | ||
) | ||
} | ||
|
||
override string getSourceType() { result = "Jax WS method parameter" } | ||
} | ||
|
||
private class JaxRsMethodParameterSource extends RemoteFlowSource { | ||
JaxRsMethodParameterSource() { | ||
exists(JaxRsResourceClass service | | ||
service.getAnInjectableCallable().getAParameter() = this.asParameter() or | ||
service.getAnInjectableField().getAnAccess() = this.asExpr() | ||
) | ||
} | ||
|
||
override string getSourceType() { result = "Jax Rs method parameter" } | ||
} | ||
|
||
private predicate variableStep(Expr tracked, VarAccess sink) { | ||
exists(VariableAssign def | | ||
def.getSource() = tracked and | ||
defUsePair(def, sink) | ||
) | ||
} | ||
|
||
private class ReverseDnsSource extends RemoteFlowSource { | ||
ReverseDnsSource() { | ||
// Try not to trigger on `localhost`. | ||
exists(MethodAccess m | m = this.asExpr() | | ||
m.getMethod() instanceof ReverseDNSMethod and | ||
not exists(MethodAccess l | | ||
(variableStep(l, m.getQualifier()) or l = m.getQualifier()) and | ||
l.getMethod().getName() = "getLocalHost" | ||
) | ||
) | ||
} | ||
|
||
override string getSourceType() { result = "reverse DNS lookup" } | ||
} | ||
|
||
private class MessageBodyReaderParameterSource extends RemoteFlowSource { | ||
MessageBodyReaderParameterSource() { | ||
exists(MessageBodyReaderRead m | | ||
m.getParameter(4) = this.asParameter() or | ||
m.getParameter(5) = this.asParameter() | ||
) | ||
} | ||
|
||
override string getSourceType() { result = "MessageBodyReader parameter" } | ||
} | ||
|
||
private class SpringMultipartFileSource extends RemoteFlowSource { | ||
SpringMultipartFileSource() { | ||
exists(MethodAccess ma, Method m | | ||
ma = this.asExpr() and | ||
m = ma.getMethod() and | ||
m.getDeclaringType().hasQualifiedName("org.springframework.web.multipart", "MultipartFile") and | ||
m.getName().matches("get%") | ||
) | ||
} | ||
|
||
override string getSourceType() { result = "Spring MultipartFile getter" } | ||
} | ||
|
||
private class SpringServletInputParameterSource extends RemoteFlowSource { | ||
SpringServletInputParameterSource() { | ||
this.asParameter().getAnAnnotation() instanceof SpringServletInputAnnotation | ||
} | ||
|
||
override string getSourceType() { result = "Spring servlet input parameter" } | ||
} | ||
|
||
private class SpringMVC extends RemoteFlowSource { | ||
SpringMVC() { | ||
this.asParameter().getCallable().getAnAnnotation() instanceof SpringMvcAnnotation | ||
} | ||
|
||
override string getSourceType() { result = "SpringMVC input parameter" } | ||
} | ||
|
||
private class GuiceRequestParameterSource extends RemoteFlowSource { | ||
GuiceRequestParameterSource() { | ||
exists(GuiceRequestParametersAnnotation a | | ||
a = this.asParameter().getAnAnnotation() or | ||
a = this.asExpr().(FieldRead).getField().getAnAnnotation() | ||
) | ||
} | ||
|
||
override string getSourceType() { result = "Guice request parameter" } | ||
} | ||
|
||
private class Struts2ActionSupportClassFieldReadSource extends RemoteFlowSource { | ||
Struts2ActionSupportClassFieldReadSource() { | ||
exists(Struts2ActionSupportClass c | | ||
c.getASetterMethod().getField() = this.asExpr().(FieldRead).getField() | ||
) | ||
} | ||
|
||
override string getSourceType() { result = "Struts2 ActionSupport field" } | ||
} | ||
|
||
private class ThriftIfaceParameterSource extends RemoteFlowSource { | ||
ThriftIfaceParameterSource() { | ||
exists(ThriftIface i | i.getAnImplementingMethod().getAParameter() = this.asParameter()) | ||
} | ||
|
||
override string getSourceType() { result = "Thrift Iface parameter" } | ||
} | ||
|
||
/** Class for `tainted` user input. */ | ||
abstract class UserInput extends DataFlow::Node { } | ||
|
||
/** | ||
* DEPRECATED: Use `RemoteFlowSource` instead. | ||
* | ||
* Input that may be controlled by a remote user. | ||
*/ | ||
deprecated class RemoteUserInput extends UserInput { | ||
RemoteUserInput() { this instanceof RemoteFlowSource } | ||
} | ||
|
||
/** A node with input that may be controlled by a local user. */ | ||
abstract class LocalUserInput extends UserInput { } | ||
|
||
/** | ||
* A node with input from the local environment, such as files, standard in, | ||
* environment variables, and main method parameters. | ||
*/ | ||
class EnvInput extends LocalUserInput { | ||
EnvInput() { | ||
// Parameters to a main method. | ||
exists(MainMethod main | this.asParameter() = main.getParameter(0)) | ||
or | ||
// Args4j arguments. | ||
exists(Field f | this.asExpr() = f.getAnAccess() | | ||
f.getAnAnnotation().getType().getQualifiedName() = "org.kohsuke.args4j.Argument" | ||
) | ||
or | ||
// Results from various specific methods. | ||
this.asExpr().(MethodAccess).getMethod() instanceof EnvTaintedMethod | ||
or | ||
// Access to `System.in`. | ||
exists(Field f | this.asExpr() = f.getAnAccess() | f instanceof SystemIn) | ||
or | ||
// Access to files. | ||
this | ||
.asExpr() | ||
.(ConstructorCall) | ||
.getConstructedType() | ||
.hasQualifiedName("java.io", "FileInputStream") | ||
} | ||
} | ||
|
||
/** A node with input from a database. */ | ||
class DatabaseInput extends LocalUserInput { | ||
DatabaseInput() { this.asExpr().(MethodAccess).getMethod() instanceof ResultSetGetStringMethod } | ||
} | ||
|
||
private class RemoteTaintedMethod extends Method { | ||
RemoteTaintedMethod() { | ||
this instanceof ServletRequestGetParameterMethod or | ||
this instanceof ServletRequestGetParameterMapMethod or | ||
this instanceof ServletRequestGetParameterNamesMethod or | ||
this instanceof HttpServletRequestGetQueryStringMethod or | ||
this instanceof HttpServletRequestGetHeaderMethod or | ||
this instanceof HttpServletRequestGetPathMethod or | ||
this instanceof HttpServletRequestGetHeadersMethod or | ||
this instanceof HttpServletRequestGetHeaderNamesMethod or | ||
this instanceof HttpServletRequestGetRequestURIMethod or | ||
this instanceof HttpServletRequestGetRequestURLMethod or | ||
this instanceof HttpServletRequestGetRemoteUserMethod or | ||
this instanceof ServletRequestGetBodyMethod or | ||
this instanceof CookieGetValueMethod or | ||
this instanceof CookieGetNameMethod or | ||
this instanceof CookieGetCommentMethod or | ||
this instanceof URLConnectionGetInputStreamMethod or | ||
this instanceof SocketGetInputStreamMethod or | ||
this instanceof ApacheHttpGetParams or | ||
this instanceof ApacheHttpEntityGetContent or | ||
// In the setting of Android we assume that XML has been transmitted over | ||
// the network, so may be tainted. | ||
this instanceof XmlPullGetMethod or | ||
this instanceof XmlAttrSetGetMethod or | ||
// The current URL in a browser may be untrusted or uncontrolled. | ||
this instanceof WebViewGetUrlMethod | ||
} | ||
} | ||
|
||
private class EnvTaintedMethod extends Method { | ||
EnvTaintedMethod() { | ||
this instanceof MethodSystemGetenv or | ||
this instanceof PropertiesGetPropertyMethod or | ||
this instanceof MethodSystemGetProperty | ||
} | ||
} | ||
|
||
/** The type `java.net.InetAddress`. */ | ||
class TypeInetAddr extends RefType { | ||
TypeInetAddr() { this.getQualifiedName() = "java.net.InetAddress" } | ||
} | ||
|
||
/** A reverse DNS method. */ | ||
class ReverseDNSMethod extends Method { | ||
ReverseDNSMethod() { | ||
this.getDeclaringType() instanceof TypeInetAddr and | ||
( | ||
this.getName() = "getHostName" or | ||
this.getName() = "getCanonicalHostName" | ||
) | ||
} | ||
} | ||
|
||
/** Android `Intent` that may have come from a hostile application. */ | ||
class AndroidIntentInput extends DataFlow::Node { | ||
AndroidIntentInput() { | ||
exists(MethodAccess ma, AndroidGetIntentMethod m | | ||
ma.getMethod().overrides*(m) and | ||
this.asExpr() = ma | ||
) | ||
or | ||
exists(Method m, AndroidReceiveIntentMethod rI | | ||
m.overrides*(rI) and | ||
this.asParameter() = m.getParameter(1) | ||
) | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import java | ||
|
||
|
||
/** | ||
* The class `com.alibaba.fastjson.JSON` or `com.alibaba.fastjson.JSONObject`. | ||
*/ | ||
class FastJson extends RefType { | ||
FastJson() { | ||
this.hasQualifiedName("com.alibaba.fastjson", "JSON") or | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should probably either change this predicate or adjust the comment to include |
||
this.hasQualifiedName("com.alibaba.fastjson", "JSONObject") | ||
} | ||
} | ||
|
||
/** | ||
* Call the parsing method of `JSON` or `JSONObject`. | ||
* sink | ||
* */ | ||
class FastJsonParse extends MethodAccess { | ||
FastJsonParse() { | ||
exists(Method m | | ||
m.getDeclaringType() instanceof FastJson and | ||
(m.hasName("parse") or m.hasName("parseObject")) and | ||
m = this.getMethod() | ||
) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels seems to be a duplicate of the existing
FlowSources.qll
file.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think so. The
FlowSources.qll
file is missing for SpringMVC for remote input. TheSpringServletInputParameterSource
class can only get the remote part of the user's input, for example the following code is in thesource
Won't get it.I added the
SpringMVC
class to theFlowSources.qll
file, mainly to verify whether the class annotation where the method parameters are obtained uses the ``Mapping``` and sub-annotations.You can try the above code with the following statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have two
FlowSources.qll
files in your commit.java/ql/src/semmle/code/java/dataflow/FlowSources.qll
and
java/ql/src/semmle/code/java/FlowSources.qll
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I have a problem with the project here and need to resubmit it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello
Sorry, I added pr.
Link to the PR:[#3674]
About fastjson introduction:
https://github.com/alibaba/fastjson
Fastjson deserializes through the parse and parseObject methods, and there may be command execution vulnerabilities in deserialization.
Vulnerabilities and fixes:
https://m.sangfor.com/source/blog-network-security/1516.html
https://github.com/alibaba/fastjson/issues