-
Notifications
You must be signed in to change notification settings - Fork 1.9k
JS: add method name injection query #503
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
JS: add method name injection query #503
Conversation
xiemaisi
left a comment
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.
Broadly lgtm, a few suggestions.
|
|
||
| <recommendation> | ||
| <p> | ||
| Avoid invoking user-controlled methods on the global object or on any function object. |
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 is a little vague. Could we suggest something more concrete, like checking the name of the function to be invoked against a whitelist?
| * @name Method name injection | ||
| * @description Invoking user-controlled methods on a arbitrary objects can lead to remote code execution. | ||
| * @kind path-problem | ||
| * @problem.severity warning |
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.
Only warning? It seems dangerous enough to warrant severity error.
| /** | ||
| * Gets the flow label relevant for this source. | ||
| */ | ||
| DataFlow::FlowLabel getFlowLabel() { |
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 this used anywhere?
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.
Ah, good catch. It was supposed to be used in isSource.
| @@ -0,0 +1,148 @@ | |||
| /** | |||
| * Provides a taint tracking configuration for reasoning about method invocations | |||
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.
"taint-tracking"
| * Holds if a property of the given object is an unsafe function. | ||
| */ | ||
| predicate isUnsafeBaseObject(DataFlow::SourceNode node) { | ||
| // eval an friends can be accessed from the global object. |
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.
s/an/and/
| } | ||
|
|
||
| /** | ||
| * A binary expression that sanitzes a value for method name injection. That |
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.
s/sanitzes/sanitizes/
javascript/ql/src/semmle/javascript/security/dataflow/MethodNameInjection.qll
Outdated
Show resolved
Hide resolved
| </p> | ||
|
|
||
| <sample src="examples/MethodNameInjection.js" /> | ||
| </example> |
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.
We generally try to give a suggestion for how to fix the problematic example. The current example is hard to fix in general, but could we perhaps modify it slightly so that it could be fixed by whitelisting the name of the invoked method?
| private predicate isCoveredByMethodNameInjection(DataFlow::SourceNode node) { | ||
| node = DataFlow::globalObjectRef() | ||
| or | ||
| node.analyze().getAValue() instanceof AbstractCallable |
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.
Do we also want to whitelist nodes that have an invocation here? (And could we share this predicate with the other query?)
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.
Added a common library to share this predicate, and also ConcatSanitizer which was originally stolen from there.
|
PTAL |
javascript/ql/src/semmle/javascript/security/dataflow/MethodNameInjection.qll
Outdated
Show resolved
Hide resolved
| | Enabling Node.js integration for Electron web content renderers (`js/enabling-electron-renderer-node-integration`) | security, frameworks/electron, external/cwe/cwe-094 | Highlights Electron web content renderer preferences with Node.js integration enabled, indicating a violation of [CWE-94](https://cwe.mitre.org/data/definitions/94.html). Results are not shown on LGTM by default. | | ||
| | File data in outbound network request | security, external/cwe/cwe-200 | Highlights locations where file data is sent in a network request. Results are not shown on LGTM by default. | | ||
| | Host header poisoning in email generation | security, external/cwe/cwe-640 | Highlights code that generates emails with links that can be hijacked by HTTP host header poisoning, indicating a violation of [CWE-640](https://cwe.mitre.org/data/definitions/640.html). Results shown on LGTM by default. | | ||
| | Method name injection (`js/method-name-injection` ) | security, external/cwe/cwe-094 | Highlights code that invokes a user-controlled method on an object with unsafe methods. | |
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 like the name, but I wonder whether we could somehow emphasise the unsafe method bit? As you know we've had customer interest in a slightly different kind of situation where method name injection results not in code injection but in a crash. That is different enough in terms of implementation and severity to warrant a separate query, and we'd need to different names and IDs for both.
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.
Unsafe dynamic method access?
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.
Yes, that's nice.
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 is done
xiemaisi
left a comment
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.
Looking good; a few more thoughts.
| <sample src="examples/MethodNameInjection.js" /> | ||
|
|
||
| <p> | ||
| Instead of storing the API methods in the global scope, put them in an API object. It is also good |
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.
We could also suggest using a Map instead of a plain object.
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.
Added Map to the qhelp file, although I didn't use it in the example as I found the difference in style to be distracting from what the example is showing.
For example, if we replace function play() with:
api.put("play", (data) => {
// ...
});any manual calls to the play function would have to be changed to api.get("play")(...) which isn't really an attractive option.
javascript/ql/src/semmle/javascript/security/dataflow/MethodNameInjection.qll
Show resolved
Hide resolved
| */ | ||
| predicate hasUnsafeMethods(DataFlow::SourceNode node) { | ||
| // eval and friends can be accessed from the global object. | ||
| node = DataFlow::globalObjectRef() |
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.
How about document (for accessing document.write)?
Co-Authored-By: asger-semmle <42069257+asger-semmle@users.noreply.github.com>
…/ql into unsafe-global-object-access
|
Ping @mc-semmle for doc review. |
| | Enabling Node.js integration for Electron web content renderers (`js/enabling-electron-renderer-node-integration`) | security, frameworks/electron, external/cwe/cwe-094 | Highlights Electron web content renderer preferences with Node.js integration enabled, indicating a violation of [CWE-94](https://cwe.mitre.org/data/definitions/94.html). Results are not shown on LGTM by default. | | ||
| | File data in outbound network request | security, external/cwe/cwe-200 | Highlights locations where file data is sent in a network request. Results are not shown on LGTM by default. | | ||
| | Host header poisoning in email generation | security, external/cwe/cwe-640 | Highlights code that generates emails with links that can be hijacked by HTTP host header poisoning, indicating a violation of [CWE-640](https://cwe.mitre.org/data/definitions/640.html). Results shown on LGTM by default. | | ||
| | Unsafe dynamic method access (`js/unsafe-dynamic-method-access` ) | security, external/cwe/cwe-094 | Highlights code that invokes a user-controlled method on an object with unsafe methods. | |
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.
Are the results shown or not shown on LGTM by default?
|
|
||
| <overview> | ||
| <p> | ||
| Invoking a user-controlled method on certain objects can lead to invocation of unsafe functions, |
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.
Invoking/invocation - would it be possible for you to use a synonym for one of the instances to avoid repetition in the same sentence?
| <p> | ||
| Invoking a user-controlled method on certain objects can lead to invocation of unsafe functions, | ||
| such as <code>eval</code> or the <code>Function</code> constructor. In particular, the global object | ||
| contains the <code>eval</code> function, and any function object contains the <code>Function</code> constructor |
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 don't understand this sentence (In particular, the global object contains the <code>eval</code> function, and any function object contains the <code>Function</code> constructor in its <code>constructor</code> property.) and how it links to what you've said previously. I am not a developer so feel free to ignore if you think this is clear enough to the intended audience.
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 technical explanation of what was meant by "certain objects" in the previous sentence. I think it would make sense to most JavaScript developers.
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.
@asger-semmle - this LGTM. I've made a couple of comments on the qhelp file, and I think you need to add a sentence to the change note to let users know whether the results of this new query are shown on LGTM by default.
Hope this helps.
|
Thanks for the review @mc-semmle. |
mchammer01
left a comment
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.
Thanks for the updates to the documentation @asger-semmle
This is good to go from my perspective
|
Query LGTM; how is the evaluation coming along? |
I had to restart due to that dist-compare PR I put up today, so it's not very far. |
| hasUnsafeMethods(read.getBase().getALocalSource()) and | ||
| src = read.getPropertyNameExpr().flow() and | ||
| dst = read and | ||
| srclabel = taint() 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.
On second (or third) thought: shouldn't we also allow srclabel = data() here and below?
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 right - for some reason I thought data implied that taint would also be present.
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 an interesting question. I experimented with adding this sort of additional lattice structure on taint kinds, but it turned out to be tricky to get right in general.
|
@asger-semmle, has the evaluation finished yet? |
|
No, I keep botching it. I have the query results here but no performance yet. |
|
I have retargetted this at rc/1.19 since it was reviewed and approved before feature freeze and is only blocked on testing. |
|
As discussed earlier, the evaluation results look reasonable, so in the interest of getting this PR into the current LGTM.com upgrade I'm merging it. |
This adds a query for a special case of what "Remote property injection" would find, but with higher
precisionvalue and classified as a code-injection alert. In aims to only flag cases that can lead to code injection.It's mostly a special case of the aforementioned query, although the coverage is slightly higher in some cases:
Performance evaluation is under way.