mirror of
https://github.com/github/codeql.git
synced 2025-12-23 20:26:32 +01:00
Partial Path Traversal split into 2 queries
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.environment.SystemProperty
|
||||
|
||||
class MethodStringStartsWith extends Method {
|
||||
MethodStringStartsWith() {
|
||||
this.getDeclaringType() instanceof TypeString and
|
||||
this.hasName("startsWith")
|
||||
}
|
||||
}
|
||||
|
||||
class MethodFileGetCanonicalPath extends Method {
|
||||
MethodFileGetCanonicalPath() {
|
||||
this.getDeclaringType() instanceof TypeFile and
|
||||
this.hasName("getCanonicalPath")
|
||||
}
|
||||
}
|
||||
|
||||
class MethodAccessFileGetCanonicalPath extends MethodAccess {
|
||||
MethodAccessFileGetCanonicalPath() { this.getMethod() instanceof MethodFileGetCanonicalPath }
|
||||
}
|
||||
|
||||
abstract class FileSeparatorExpr extends Expr { }
|
||||
|
||||
class SystemPropFileSeparatorExpr extends FileSeparatorExpr {
|
||||
SystemPropFileSeparatorExpr() { this = getSystemProperty("file.separator") }
|
||||
}
|
||||
|
||||
class StringLiteralFileSeparatorExpr extends FileSeparatorExpr, StringLiteral {
|
||||
StringLiteralFileSeparatorExpr() {
|
||||
this.getValue().matches("%/") or this.getValue().matches("%\\")
|
||||
}
|
||||
}
|
||||
|
||||
class CharacterLiteralFileSeparatorExpr extends FileSeparatorExpr, CharacterLiteral {
|
||||
CharacterLiteralFileSeparatorExpr() { this.getValue() = "/" or this.getValue() = "\\" }
|
||||
}
|
||||
|
||||
class FileSeparatorAppend extends AddExpr {
|
||||
FileSeparatorAppend() { this.getRightOperand() instanceof FileSeparatorExpr }
|
||||
}
|
||||
|
||||
predicate isSafe(Expr expr) {
|
||||
DataFlow::localExprFlow(any(Expr e |
|
||||
e instanceof FileSeparatorAppend or e instanceof FileSeparatorExpr
|
||||
), expr)
|
||||
}
|
||||
|
||||
class PartialPathTraversalMethodAccess extends MethodAccess {
|
||||
PartialPathTraversalMethodAccess() {
|
||||
this.getMethod() instanceof MethodStringStartsWith and
|
||||
DataFlow::localExprFlow(any(MethodAccessFileGetCanonicalPath gcpma), this.getQualifier()) and
|
||||
not isSafe(this.getArgument(0))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
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
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -10,57 +10,7 @@
|
||||
* external/cwe/cwe-023
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.environment.SystemProperty
|
||||
import semmle.code.java.security.PartialPathTraversal
|
||||
|
||||
class MethodStringStartsWith extends Method {
|
||||
MethodStringStartsWith() {
|
||||
this.getDeclaringType() instanceof TypeString and
|
||||
this.hasName("startsWith")
|
||||
}
|
||||
}
|
||||
|
||||
class MethodFileGetCanonicalPath extends Method {
|
||||
MethodFileGetCanonicalPath() {
|
||||
this.getDeclaringType() instanceof TypeFile and
|
||||
this.hasName("getCanonicalPath")
|
||||
}
|
||||
}
|
||||
|
||||
class MethodAccessFileGetCanonicalPath extends MethodAccess {
|
||||
MethodAccessFileGetCanonicalPath() { this.getMethod() instanceof MethodFileGetCanonicalPath }
|
||||
}
|
||||
|
||||
abstract class FileSeparatorExpr extends Expr { }
|
||||
|
||||
class SystemPropFileSeparatorExpr extends FileSeparatorExpr {
|
||||
SystemPropFileSeparatorExpr() { this = getSystemProperty("file.separator") }
|
||||
}
|
||||
|
||||
class StringLiteralFileSeparatorExpr extends FileSeparatorExpr, StringLiteral {
|
||||
StringLiteralFileSeparatorExpr() {
|
||||
this.getValue().matches("%/") or this.getValue().matches("%\\")
|
||||
}
|
||||
}
|
||||
|
||||
class CharacterLiteralFileSeparatorExpr extends FileSeparatorExpr, CharacterLiteral {
|
||||
CharacterLiteralFileSeparatorExpr() { this.getValue() = "/" or this.getValue() = "\\" }
|
||||
}
|
||||
|
||||
class FileSeparatorAppend extends AddExpr {
|
||||
FileSeparatorAppend() { this.getRightOperand() instanceof FileSeparatorExpr }
|
||||
}
|
||||
|
||||
predicate isSafe(Expr expr) {
|
||||
DataFlow::localExprFlow(any(Expr e |
|
||||
e instanceof FileSeparatorAppend or e instanceof FileSeparatorExpr
|
||||
), expr)
|
||||
}
|
||||
|
||||
from MethodAccess ma
|
||||
where
|
||||
ma.getMethod() instanceof MethodStringStartsWith and
|
||||
DataFlow::localExprFlow(any(MethodAccessFileGetCanonicalPath gcpma), ma.getQualifier()) and
|
||||
not isSafe(ma.getArgument(0))
|
||||
from PartialPathTraversalMethodAccess ma
|
||||
select ma, "Partial Path Traversal Vulnerability due to insufficient guard against path traversal"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @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
|
||||
* @id java/partial-path-traversal-from-remote
|
||||
* @tags security
|
||||
* external/cwe/cwe-023
|
||||
*/
|
||||
|
||||
import semmle.code.java.security.PartialPathTraversalQuery
|
||||
|
||||
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"
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,14 @@ import java.nio.file.Files;
|
||||
|
||||
public class PartialPathTraversalTest {
|
||||
public void esapiExample(File dir, File parent) throws IOException {
|
||||
if (!dir.getCanonicalPath().startsWith(parent.getCanonicalPath())) {
|
||||
if (!dir.getCanonicalPath().startsWith(parent.getCanonicalPath())) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
void foo1(File dir, File parent) throws IOException {
|
||||
(dir.getCanonicalPath()).startsWith((parent.getCanonicalPath()));
|
||||
(dir.getCanonicalPath()).startsWith((parent.getCanonicalPath())); // $hasTaintFlow
|
||||
}
|
||||
|
||||
void foo2(File dir, File parent) throws IOException {
|
||||
@@ -26,31 +26,31 @@ public class PartialPathTraversalTest {
|
||||
|
||||
void foo3(File dir, File parent) throws IOException {
|
||||
String parentPath = parent.getCanonicalPath();
|
||||
if (!dir.getCanonicalPath().startsWith(parentPath)) {
|
||||
if (!dir.getCanonicalPath().startsWith(parentPath)) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
|
||||
void foo4(File dir) throws IOException {
|
||||
if (!dir.getCanonicalPath().startsWith("/usr" + "/dir")) {
|
||||
if (!dir.getCanonicalPath().startsWith("/usr" + "/dir")) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
|
||||
void foo5(File dir, File parent) throws IOException {
|
||||
String canonicalPath = dir.getCanonicalPath();
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) {
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
|
||||
void foo6(File dir, File parent) throws IOException {
|
||||
String canonicalPath = dir.getCanonicalPath();
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) {
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
String canonicalPath2 = dir.getCanonicalPath();
|
||||
if (!canonicalPath2.startsWith(parent.getCanonicalPath())) {
|
||||
if (!canonicalPath2.startsWith(parent.getCanonicalPath())) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
@@ -58,10 +58,10 @@ public class PartialPathTraversalTest {
|
||||
void foo7(File dir, File parent) throws IOException {
|
||||
String canonicalPath = dir.getCanonicalPath();
|
||||
String canonicalPath2 = dir.getCanonicalPath();
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) {
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
if (!canonicalPath2.startsWith(parent.getCanonicalPath())) {
|
||||
if (!canonicalPath2.startsWith(parent.getCanonicalPath())) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class PartialPathTraversalTest {
|
||||
|
||||
void foo8(File parent) throws IOException {
|
||||
String canonicalPath = getChild().getCanonicalPath();
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) {
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) {
|
||||
throw new IOException("Invalid directory: " + getChild().getCanonicalPath());
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ public class PartialPathTraversalTest {
|
||||
|
||||
void foo11(File dir, File parent) throws IOException {
|
||||
String parentCanonical = parent.getCanonicalPath();
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical)) {
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical)) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
@@ -99,10 +99,10 @@ public class PartialPathTraversalTest {
|
||||
void foo12(File dir, File parent) throws IOException {
|
||||
String parentCanonical = parent.getCanonicalPath();
|
||||
String parentCanonical2 = parent.getCanonicalPath();
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical)) {
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical)) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical2)) {
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical2)) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ public class PartialPathTraversalTest {
|
||||
|
||||
void foo14(File dir, File parent) throws IOException {
|
||||
String parentCanonical = parent.getCanonicalPath() + separatorChar;
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical)) {
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical)) {
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ public class PartialPathTraversalTest {
|
||||
|
||||
void foo19(File dir, File parent) throws IOException {
|
||||
String parentCanonical = parent.getCanonicalPath() + "/potato";
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical)) {
|
||||
if (!dir.getCanonicalPath().startsWith(parentCanonical)) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,7 @@ public class PartialPathTraversalTest {
|
||||
String filePath = sb.toString();
|
||||
File encodedFile = new File(filePath);
|
||||
try {
|
||||
if (!encodedFile.getCanonicalPath().startsWith(cacheDir.getCanonicalPath())) {
|
||||
if (!encodedFile.getCanonicalPath().startsWith(cacheDir.getCanonicalPath())) { // $hasTaintFlow
|
||||
return null;
|
||||
}
|
||||
return Files.newInputStream(encodedFile.toPath());
|
||||
@@ -206,7 +206,7 @@ public class PartialPathTraversalTest {
|
||||
|
||||
void foo22(File dir, File dir2, File parent, boolean conditional) throws IOException {
|
||||
String canonicalPath = conditional ? dir.getCanonicalPath() : dir2.getCanonicalPath();
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) {
|
||||
if (!canonicalPath.startsWith(parent.getCanonicalPath())) { // $hasTaintFlow
|
||||
throw new IOException("Invalid directory: " + dir.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user