-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Java: Add a query for SpEL injections #3291
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
Conversation
4709af1
to
01055e7
Compare
} | ||
} | ||
|
||
class NativeWebRequest extends RefType { |
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 one seems to not be used
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're absolutely right. At first, I thought that NativeWebRequest
may be used as an additional source but then it turned out that it doesn't bring much value. I've removed the class. Thanks!
01055e7
to
893acfb
Compare
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.
The QL code is generally looking very good, but I've made some inline comments.
/** | ||
* A configuration for safe evaluation context that may be used in expression evaluation. | ||
*/ | ||
class SafeEvaluationContextFlowConfig extends TaintTracking2::Configuration { |
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'd suggest changing TaintTracking2::Configuration
to DataFlow2::Configuration
, as data flow seems more appropriate for this check than taint flow.
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.
Yup, makes sense.
import semmle.code.java.dataflow.FlowSources | ||
import semmle.code.java.dataflow.TaintTracking2 | ||
import SpringFrameworkLib | ||
import DataFlow |
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.
It's a bit cleaner if this import is removed - most things appear to be referenced with their qualified names anyway.
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.
Yeah, this import is redundant.
ExpressionEvaluationSink() { | ||
exists(MethodAccess ma, Method m | m = ma.getMethod() | | ||
m instanceof ExpressionEvaluationMethod and | ||
(getExpr() = ma or getExpr() = ma.getQualifier()) and |
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.
Shouldn't this just be
(getExpr() = ma or getExpr() = ma.getQualifier()) and | |
getExpr() = ma.getQualifier() and |
m.getDeclaringType().getAnAncestor*() instanceof ExpressionParser and | ||
m.hasName("parseExpression") and | ||
ma.getAnArgument() = node1.asExpr() and | ||
(node2.asExpr() = ma.getQualifier() or node2.asExpr() = ma) |
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.
Is a call to parseExpression
supposed to taint the qualifier? Shouldn't this just be
(node2.asExpr() = ma.getQualifier() or node2.asExpr() = ma) | |
node2.asExpr() = ma |
predicate isSimpleEvaluationContextConstructorCall(Expr expr) { | ||
exists(ConstructorCall cc | | ||
cc.getConstructedType() instanceof SimpleEvaluationContext and | ||
(cc = expr or cc.getQualifier() = expr) |
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.
The qualifier of the constructor call? Surely this should just be
(cc = expr or cc.getQualifier() = expr) | |
cc = expr |
exists(MethodAccess ma, Method m | ma.getMethod() = m | | ||
m.getDeclaringType() instanceof SimpleEvaluationContextBuilder and | ||
m.hasName("build") and | ||
(ma = expr or ma.getQualifier() = expr) |
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'm less certain here, but including the qualifier looks superfluous to me?
(ma = expr or ma.getQualifier() = expr) | |
ma = expr |
m.hasName("getParameterNames") or | ||
m.hasName("getParameterMap") | ||
) and | ||
(ma = asExpr() or ma.getQualifier() = asExpr()) |
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.
Is there a reason to include the qualifier as the source instead of just the method result?
(ma = asExpr() or ma.getQualifier() = asExpr()) | |
ma = asExpr() |
predicate createMutablePropertyValuesStep(DataFlow::Node node1, DataFlow::Node node2) { | ||
exists(ConstructorCall cc | cc.getConstructedType() instanceof MutablePropertyValues | | ||
node1.asExpr() = cc.getAnArgument() and | ||
(node2.asExpr() = cc or node2.asExpr() = cc.getQualifier()) |
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.
(node2.asExpr() = cc or node2.asExpr() = cc.getQualifier()) | |
node2.asExpr() = cc |
This week I ran into CVE-2018-1260 which was found by the same researcher as CVE-2018-1273 |
@aschackmull Thanks for the review and suggestions for the qualifiers. Let me have a closer look. |
- Added experimental/Security/CWE/CWE-094/SpelInjection.ql and a couple of libraries - Added a qhelp file with a few examples - Added tests and stubs for Spring
893acfb
to
df3adee
Compare
@aschackmull There was a bit of mess with qualifiers - thanks for your suggestions! I've addressed the comments. |
I'm about to look at your latest changes, but this is made a bit more difficult than it ought to be due to the commits being squashed together. Please don't squash commits in the future once review has started. |
Here is a list of main updates:
experimental/Security/CWE/CWE-094/SpelInjection.ql
and a couple of libraries.The query finds CVE-2018-1273 that is an RCE with Spring Data Commons 1.13.10 due to a SpEL injection. To catch the issue, a database should contain both Spring Framework 4.3.14 and Spring Data Commons 1.13.10 because tainted data travels for a while inside the framework before it reaches a sink in
MapDataBinder
. It also looks like the CodeQL CLI doesn't recognize Lombok. Therefore, Spring Data Commons needs to be built with this hack.