-
Notifications
You must be signed in to change notification settings - Fork 2k
[JAVA] Partial Path Traversal Vuln Query #9742
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
Merged
smowton
merged 35 commits into
github:main
from
smehta23:feat/SM/java_partial_path_traversal_vulnerability
Aug 15, 2022
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
4c7d476
[JAVA] Partial Path Traversal Vuln Query
smehta23 7122f29
Finish Partial Path Traversal Query
smehta23 b5ca2c3
Add additional tests from real world query run
smehta23 955e614
Add documentation of the Partial Path Traversal vuln
smehta23 7ab8f02
Fix duplicate class header and better fix using toPath()
smehta23 1681407
Fix typo in .qhelp
smehta23 c6f2f61
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversalBad.java
smehta23 209a216
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversalGood.java
smehta23 300a14c
Add ESAPI reference
smehta23 1a41d4c
Add CVE number
smehta23 48e16e5
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversal.qhelp
smehta23 ebe48ec
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversal.qhelp
smehta23 391dd5b
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversalGood.java
smehta23 39f8854
Change log
smehta23 781a2a7
Merge branch 'main' into feat/SM/java_partial_path_traversal_vulnerab…
smehta23 65b9947
Incorporate jksco's feedback
smehta23 01cec04
Abbreviate qhelp
smowton a697063
Improve description
smowton b7e5227
Apply suggestions from code review
smehta23 09ec379
Partial Path Traversal split into 2 queries
smehta23 76cecc1
Fix documentation
smehta23 4f1bc30
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversalFromRemot…
smehta23 9d3e8ec
Update PartialPathTraversalFromRemote.qhelp
smehta23 50b4df5
Fixed precision labels
smehta23 af92fc3
Update PartialPathTraversalFromRemote.qhelp
smehta23 c2b670e
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversalFromRemot…
smehta23 7da0740
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversalFromRemot…
smehta23 4d80fd0
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversal.qhelp
smehta23 cf68a11
Update java/ql/src/Security/CWE/CWE-023/PartialPathTraversal.qhelp
smehta23 2ca0b0c
Inline qhelp overview
smowton 09e4c6b
Add dataflow path-graph
smowton e9df675
Autoformat ql
smowton 3cf871e
Apply docs suggestions
smowton 5677e38
Style edit
smowton 1a3dc1d
Remove extra closing tag
smowton 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
60 changes: 60 additions & 0 deletions
60
java/ql/lib/semmle/code/java/security/PartialPathTraversal.qll
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,60 @@ | ||
| /** Provides classes to reason about partial path traversal vulnerabilities. */ | ||
|
|
||
| import java | ||
| private import semmle.code.java.dataflow.DataFlow | ||
| private import semmle.code.java.environment.SystemProperty | ||
|
|
||
| private class MethodStringStartsWith extends Method { | ||
| MethodStringStartsWith() { | ||
| this.getDeclaringType() instanceof TypeString and | ||
| this.hasName("startsWith") | ||
| } | ||
| } | ||
|
|
||
| private class MethodFileGetCanonicalPath extends Method { | ||
| MethodFileGetCanonicalPath() { | ||
| this.getDeclaringType() instanceof TypeFile and | ||
| this.hasName("getCanonicalPath") | ||
| } | ||
| } | ||
|
|
||
| private class MethodAccessFileGetCanonicalPath extends MethodAccess { | ||
| MethodAccessFileGetCanonicalPath() { this.getMethod() instanceof MethodFileGetCanonicalPath } | ||
| } | ||
|
|
||
| abstract private class FileSeparatorExpr extends Expr { } | ||
|
|
||
| private class SystemPropFileSeparatorExpr extends FileSeparatorExpr { | ||
| SystemPropFileSeparatorExpr() { this = getSystemProperty("file.separator") } | ||
| } | ||
|
|
||
| private class StringLiteralFileSeparatorExpr extends FileSeparatorExpr, StringLiteral { | ||
| StringLiteralFileSeparatorExpr() { | ||
| this.getValue().matches("%/") or this.getValue().matches("%\\") | ||
| } | ||
| } | ||
|
|
||
| private class CharacterLiteralFileSeparatorExpr extends FileSeparatorExpr, CharacterLiteral { | ||
| CharacterLiteralFileSeparatorExpr() { this.getValue() = "/" or this.getValue() = "\\" } | ||
| } | ||
|
|
||
| private class FileSeparatorAppend extends AddExpr { | ||
| FileSeparatorAppend() { this.getRightOperand() instanceof FileSeparatorExpr } | ||
| } | ||
|
|
||
| private predicate isSafe(Expr expr) { | ||
| DataFlow::localExprFlow(any(Expr e | | ||
| e instanceof FileSeparatorAppend or e instanceof FileSeparatorExpr | ||
| ), expr) | ||
| } | ||
|
|
||
| /** | ||
| * A method access that returns a boolean that incorrectly guards against Partial Path Traversal. | ||
| */ | ||
| class PartialPathTraversalMethodAccess extends MethodAccess { | ||
| PartialPathTraversalMethodAccess() { | ||
| this.getMethod() instanceof MethodStringStartsWith and | ||
| DataFlow::localExprFlow(any(MethodAccessFileGetCanonicalPath gcpma), this.getQualifier()) and | ||
| not isSafe(this.getArgument(0)) | ||
| } | ||
| } |
23 changes: 23 additions & 0 deletions
23
java/ql/lib/semmle/code/java/security/PartialPathTraversalQuery.qll
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,23 @@ | ||
| /** Provides taint tracking configurations to be used in partial path traversal queries. */ | ||
|
|
||
| import java | ||
| import semmle.code.java.security.PartialPathTraversal | ||
| import semmle.code.java.dataflow.DataFlow | ||
| import semmle.code.java.dataflow.ExternalFlow | ||
| import semmle.code.java.dataflow.TaintTracking | ||
| import semmle.code.java.dataflow.FlowSources | ||
|
|
||
| /** | ||
| * A taint-tracking configuration for unsafe user input | ||
| * that is used to validate against path traversal, but is insufficient | ||
| * and remains vulnerable to Partial Path Traversal. | ||
| */ | ||
| class PartialPathTraversalFromRemoteConfig extends TaintTracking::Configuration { | ||
| PartialPathTraversalFromRemoteConfig() { this = "PartialPathTraversalFromRemoteConfig" } | ||
|
|
||
| override predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource } | ||
|
|
||
| override predicate isSink(DataFlow::Node node) { | ||
| any(PartialPathTraversalMethodAccess ma).getQualifier() = node.asExpr() | ||
| } | ||
| } |
15 changes: 15 additions & 0 deletions
15
java/ql/src/Security/CWE/CWE-023/PartialPathTraversal.qhelp
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,15 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
| <overview> | ||
| <p>A common way to check that a user-supplied path <code>SUBDIR</code> falls inside a directory <code>DIR</code> | ||
| is to use <code>getCanonicalPath()</code> to remove any path-traversal elements and then check that <code>DIR</code> | ||
| is a prefix. However, if <code>DIR</code> is not slash-terminated, this can unexpectedly allow access to siblings of <code>DIR</code>.</p> | ||
|
|
||
| <p>See also <code>java/partial-path-traversal-from-remote</code>, which is similar to this query but only flags instances with evidence of remote exploitability.</p> | ||
| </overview> | ||
|
|
||
| <include src="PartialPathTraversalRemainder.inc.qhelp"/> | ||
|
|
||
| </qhelp> | ||
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,16 @@ | ||
| /** | ||
| * @name Partial path traversal vulnerability | ||
| * @description A prefix used to check that a canonicalised path falls within another must be slash-terminated. | ||
| * @kind problem | ||
| * @problem.severity error | ||
| * @security-severity 9.3 | ||
| * @precision medium | ||
| * @id java/partial-path-traversal | ||
| * @tags security | ||
| * external/cwe/cwe-023 | ||
| */ | ||
|
|
||
| import semmle.code.java.security.PartialPathTraversal | ||
|
|
||
| from PartialPathTraversalMethodAccess ma | ||
| select ma, "Partial Path Traversal Vulnerability due to insufficient guard against path traversal" |
7 changes: 7 additions & 0 deletions
7
java/ql/src/Security/CWE/CWE-023/PartialPathTraversalBad.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,7 @@ | ||
| public class PartialPathTraversalBad { | ||
| public void example(File dir, File parent) throws IOException { | ||
| if (!dir.getCanonicalPath().startsWith(parent.getCanonicalPath())) { | ||
| throw new IOException("Invalid directory: " + dir.getCanonicalPath()); | ||
| } | ||
| } | ||
| } |
16 changes: 16 additions & 0 deletions
16
java/ql/src/Security/CWE/CWE-023/PartialPathTraversalFromRemote.qhelp
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,16 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
| <overview> | ||
| <p>A common way to check that a user-supplied path <code>SUBDIR</code> falls inside a directory <code>DIR</code> | ||
| is to use <code>getCanonicalPath()</code> to remove any path-traversal elements and then check that <code>DIR</code> | ||
| is a prefix. However, if <code>DIR</code> is not slash-terminated, this can unexpectedly allow accessing siblings of <code>DIR</code>.</p> | ||
|
|
||
| <p>See also <code>java/partial-path-traversal</code>, which is similar to this query, | ||
| but may also flag non-remotely-exploitable instances of partial path traversal vulnerabilities.</p> | ||
| </overview> | ||
|
|
||
| <include src="PartialPathTraversalRemainder.inc.qhelp"/> | ||
|
|
||
| </qhelp> |
19 changes: 19 additions & 0 deletions
19
java/ql/src/Security/CWE/CWE-023/PartialPathTraversalFromRemote.ql
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,19 @@ | ||
| /** | ||
| * @name Partial path traversal vulnerability from remote | ||
| * @description A prefix used to check that a canonicalised path falls within another must be slash-terminated. | ||
| * @kind path-problem | ||
| * @problem.severity error | ||
| * @security-severity 9.3 | ||
| * @precision high | ||
|
smehta23 marked this conversation as resolved.
|
||
| * @id java/partial-path-traversal-from-remote | ||
| * @tags security | ||
| * external/cwe/cwe-023 | ||
| */ | ||
|
|
||
| import semmle.code.java.security.PartialPathTraversalQuery | ||
| import DataFlow::PathGraph | ||
|
|
||
| from DataFlow::PathNode source, DataFlow::PathNode sink | ||
| where any(PartialPathTraversalFromRemoteConfig config).hasFlowPath(source, sink) | ||
| select sink.getNode(), source, sink, | ||
| "Partial Path Traversal Vulnerability due to insufficient guard against path traversal from user-supplied data" | ||
7 changes: 7 additions & 0 deletions
7
java/ql/src/Security/CWE/CWE-023/PartialPathTraversalGood.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,7 @@ | ||
| public class PartialPathTraversalGood { | ||
| public void example(File dir, File parent) throws IOException { | ||
| if (!dir.getCanonicalPath().toPath().startsWith(parent.getCanonicalPath().toPath())) { | ||
| throw new IOException("Invalid directory: " + dir.getCanonicalPath()); | ||
| } | ||
| } | ||
| } |
49 changes: 49 additions & 0 deletions
49
java/ql/src/Security/CWE/CWE-023/PartialPathTraversalRemainder.inc.qhelp
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,49 @@ | ||
| <!DOCTYPE qhelp PUBLIC | ||
| "-//Semmle//qhelp//EN" | ||
| "qhelp.dtd"> | ||
| <qhelp> | ||
|
|
||
| <recommendation> | ||
|
|
||
| <p>If the user should only access items within a certain directory <code>DIR</code>, ensure that <code>DIR</code> is slash-terminated | ||
| before checking that <code>DIR</code> is a prefix of the user-provided path, <code>SUBDIR</code>. Note, Java's <code>getCanonicalPath()</code> | ||
| returns a <b>non</b>-slash-terminated path string, so a slash must be added to <code>DIR</code> if that method is used.</p> | ||
|
|
||
| </recommendation> | ||
| <example> | ||
|
|
||
| <p> | ||
|
|
||
|
|
||
| In this example, the <code>if</code> statement checks if <code>parent.getCanonicalPath()</code> | ||
| is a prefix of <code>dir.getCanonicalPath()</code>. However, <code>parent.getCanonicalPath()</code> is | ||
| not slash-terminated. This means that users that supply <code>dir</code> may be also allowed to access siblings of <code>parent</code> | ||
| and not just children of <code>parent</code>, which is a security issue. | ||
|
|
||
| </p> | ||
|
|
||
| <sample src="PartialPathTraversalBad.java" /> | ||
|
|
||
| <p> | ||
|
|
||
| In this example, the <code>if</code> statement checks if <code>parent.getCanonicalPath() + File.separator </code> | ||
| is a prefix of <code>dir.getCanonicalPath()</code>. Because <code>parent.getCanonicalPath().toPath()</code> is | ||
| indeed slash-terminated, the user supplying <code>dir</code> can only access children of | ||
| <code>parent</code>, as desired. | ||
|
|
||
| </p> | ||
|
|
||
| <sample src="PartialPathTraversalGood.java" /> | ||
|
|
||
| </example> | ||
| <references> | ||
|
|
||
| <li>OWASP: | ||
| <a href="https://owasp.org/www-community/attacks/Path_Traversal">Partial Path Traversal</a>.</li> | ||
| <li>CVE-2022-23457: | ||
| <a href="https://github.com/ESAPI/esapi-java-legacy/blob/develop/documentation/GHSL-2022-008_The_OWASP_Enterprise_Security_API.md"> ESAPI Vulnerability Report</a>.</li> | ||
|
|
||
| </references> | ||
|
|
||
|
|
||
| </qhelp> |
5 changes: 5 additions & 0 deletions
5
java/ql/src/change-notes/2022-07-01-partial-path-traversal.md
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,5 @@ | ||
| --- | ||
| category: newQuery | ||
| --- | ||
| * A new query `java/partial-path-traversal` finds partial path traversal vulnerabilities resulting from incorrectly using | ||
| `String#startsWith` to compare canonical paths. |
16 changes: 16 additions & 0 deletions
16
java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversal.expected
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,16 @@ | ||
| | PartialPathTraversalTest.java:10:14:10:73 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:17:9:17:72 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:29:14:29:58 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:35:14:35:63 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:42:14:42:64 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:49:14:49:64 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:53:14:53:65 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:61:14:61:64 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:64:14:64:65 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:75:14:75:64 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:94:14:94:63 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:102:14:102:63 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:105:14:105:64 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:173:14:173:63 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:191:18:191:87 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | | ||
| | PartialPathTraversalTest.java:209:14:209:64 | startsWith(...) | Partial Path Traversal Vulnerability due to insufficient guard against path traversal | |
1 change: 1 addition & 0 deletions
1
java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversal.qlref
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 @@ | ||
| Security/CWE/CWE-023/PartialPathTraversal.ql |
Empty file.
17 changes: 17 additions & 0 deletions
17
java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.ql
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,17 @@ | ||
| import java | ||
| import TestUtilities.InlineFlowTest | ||
| import semmle.code.java.security.PartialPathTraversalQuery | ||
|
|
||
| class TestRemoteSource extends RemoteFlowSource { | ||
| TestRemoteSource() { this.asParameter().hasName(["dir", "path"]) } | ||
|
|
||
| override string getSourceType() { result = "TestSource" } | ||
| } | ||
|
|
||
| class Test extends InlineFlowTest { | ||
| override DataFlow::Configuration getValueFlowConfig() { none() } | ||
|
|
||
| override TaintTracking::Configuration getTaintFlowConfig() { | ||
| result instanceof PartialPathTraversalFromRemoteConfig | ||
| } | ||
| } |
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.
Uh oh!
There was an error while loading. Please reload this page.