From abd3df5b63f49c5efd05c696d3bd3dafa848a43b Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Tue, 20 Sep 2022 17:48:14 +0100 Subject: [PATCH 1/7] Created Hardcoded Base64 Usage query --- codeql | 2 +- java/CWE-798/HardcodedBase64Usage.ql | 54 +++++++++++++++++++ java/github/Base64.qll | 44 +++++++++++++++ .../base64/HardcodedBase64Usage.expected | 26 +++++++++ .../CWE-798/base64/HardcodedBase64Usage.java | 38 +++++++++++++ .../CWE-798/base64/HardcodedBase64Usage.qlref | 1 + tests/java-tests/qlpack.lock.yml | 4 ++ tests/java-tests/qlpack.yml | 8 +++ 8 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 java/CWE-798/HardcodedBase64Usage.ql create mode 100644 java/github/Base64.qll create mode 100644 tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected create mode 100644 tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java create mode 100644 tests/java-tests/CWE-798/base64/HardcodedBase64Usage.qlref create mode 100644 tests/java-tests/qlpack.lock.yml create mode 100644 tests/java-tests/qlpack.yml diff --git a/codeql b/codeql index d0e3edf7adf..b49487cf420 160000 --- a/codeql +++ b/codeql @@ -1 +1 @@ -Subproject commit d0e3edf7adf7cac22753aafa875b4e477eb14205 +Subproject commit b49487cf420ce87f14107f527c704ae4fc940b63 diff --git a/java/CWE-798/HardcodedBase64Usage.ql b/java/CWE-798/HardcodedBase64Usage.ql new file mode 100644 index 00000000000..7d946c977da --- /dev/null +++ b/java/CWE-798/HardcodedBase64Usage.ql @@ -0,0 +1,54 @@ +/** + * @name Base64 Hardcoded Password + * @description Static hardcoded base64 password / key + * @kind path-problem + * @problem.severity error + * @security-severity 8.0 + * @precision low + * @sub-severity high + * @id java/hardcoded-password + * @tags security + * external/cwe/cwe-798 + */ + +import java +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking2 +import DataFlow::PathGraph +import semmle.code.java.security.HardcodedCredentials +// Internal +import github.Base64 + +class HardcodedPasswordBase64 extends DataFlow::Configuration { + HardcodedPasswordBase64() { this = "HardcodedPasswordBase64" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof HardcodedExpr and + not source.asExpr().getEnclosingCallable() instanceof ToStringMethod + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Base64::Decoding } + + override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + // String.getBytes() + node1.asExpr().getType() instanceof TypeString and + exists(MethodAccess ma | ma.getMethod().hasName(["getBytes", "toCharArray"]) | + node2.asExpr() = ma and + ma.getQualifier() = node1.asExpr() + ) + or + // byte[].toString() + node1.asExpr().getType() instanceof Array and + exists(MethodAccess ma | ma.getMethod().hasName(["toString"]) | + node2.asExpr() = ma and + ma.getQualifier() = node1.asExpr() + ) + } +} + +// ========== Query ========== +from DataFlow::PathNode source, DataFlow::PathNode sink, HardcodedPasswordBase64 config +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Sensative data is being logged $@.", source.getNode(), + "user-provided value" diff --git a/java/github/Base64.qll b/java/github/Base64.qll new file mode 100644 index 00000000000..00c8021e491 --- /dev/null +++ b/java/github/Base64.qll @@ -0,0 +1,44 @@ +import java +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking2 + +module Base64 { + abstract class Encoding extends DataFlow::Node { } + + abstract class Decoding extends DataFlow::Node { } + + // codeql/java/ql/lib/semmle/code/java/security/HardcodedCredentialsApiCallQuery.qll + class Encoders extends Base64::Encoding { + Encoders() { + exists(MethodAccess ma | + ma.getMethod() + .hasQualifiedName([ + "java.util", "cn.hutool.core.codec", "org.apache.shiro.codec", + "apache.commons.codec.binary", "org.springframework.util" + ], ["Base64$Encoder", "Base64$Decoder", "Base64", "Base64Utils"], + [ + "encode", "encodeToString", "encodeBase64", "encodeBase64Chunked", + "encodeBase64String", "encodeBase64URLSafe", "encodeBase64URLSafeString" + ]) + | + this.asExpr() = ma.getArgument(0) + ) + } + } + + class Decoders extends Base64::Decoding { + Decoders() { + exists(MethodAccess ma | + ma.getMethod() + .hasQualifiedName([ + "java.util", "cn.hutool.core.codec", "org.apache.shiro.codec", + "apache.commons.codec.binary", "org.springframework.util" + ], ["Base64$Encoder", "Base64$Decoder", "Base64", "Base64Utils"], + ["decode", "decodeBase64"]) + | + this.asExpr() = ma.getArgument(0) + ) + } + } +} diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected new file mode 100644 index 00000000000..c7660e83e55 --- /dev/null +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected @@ -0,0 +1,26 @@ +edges +| HardcodedPasswordBase64.java:4:26:4:28 | KEY : String | HardcodedPasswordBase64.java:9:58:9:66 | MyApp.KEY | +| HardcodedPasswordBase64.java:4:26:4:28 | KEY : String | HardcodedPasswordBase64.java:31:22:31:30 | MyApp.KEY : String | +| HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedPasswordBase64.java:4:26:4:28 | KEY : String | +| HardcodedPasswordBase64.java:5:26:5:29 | KEY2 : byte[] | HardcodedPasswordBase64.java:16:58:16:67 | MyApp.KEY2 | +| HardcodedPasswordBase64.java:5:26:5:29 | KEY2 : byte[] | HardcodedPasswordBase64.java:23:22:23:31 | MyApp.KEY2 : byte[] | +| HardcodedPasswordBase64.java:5:33:6:17 | new byte[] : byte[] | HardcodedPasswordBase64.java:5:26:5:29 | KEY2 : byte[] | +| HardcodedPasswordBase64.java:23:22:23:31 | MyApp.KEY2 : byte[] | HardcodedPasswordBase64.java:24:58:24:60 | key | +| HardcodedPasswordBase64.java:31:22:31:30 | MyApp.KEY : String | HardcodedPasswordBase64.java:32:58:32:60 | key | +nodes +| HardcodedPasswordBase64.java:4:26:4:28 | KEY : String | semmle.label | KEY : String | +| HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | semmle.label | "VGVzdFBhc3N3b3Jk" : String | +| HardcodedPasswordBase64.java:5:26:5:29 | KEY2 : byte[] | semmle.label | KEY2 : byte[] | +| HardcodedPasswordBase64.java:5:33:6:17 | new byte[] : byte[] | semmle.label | new byte[] : byte[] | +| HardcodedPasswordBase64.java:9:58:9:66 | MyApp.KEY | semmle.label | MyApp.KEY | +| HardcodedPasswordBase64.java:16:58:16:67 | MyApp.KEY2 | semmle.label | MyApp.KEY2 | +| HardcodedPasswordBase64.java:23:22:23:31 | MyApp.KEY2 : byte[] | semmle.label | MyApp.KEY2 : byte[] | +| HardcodedPasswordBase64.java:24:58:24:60 | key | semmle.label | key | +| HardcodedPasswordBase64.java:31:22:31:30 | MyApp.KEY : String | semmle.label | MyApp.KEY : String | +| HardcodedPasswordBase64.java:32:58:32:60 | key | semmle.label | key | +subpaths +#select +| HardcodedPasswordBase64.java:9:58:9:66 | MyApp.KEY | HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedPasswordBase64.java:9:58:9:66 | MyApp.KEY | Sensative data is being logged $@. | HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | user-provided value | +| HardcodedPasswordBase64.java:16:58:16:67 | MyApp.KEY2 | HardcodedPasswordBase64.java:5:33:6:17 | new byte[] : byte[] | HardcodedPasswordBase64.java:16:58:16:67 | MyApp.KEY2 | Sensative data is being logged $@. | HardcodedPasswordBase64.java:5:33:6:17 | new byte[] | user-provided value | +| HardcodedPasswordBase64.java:24:58:24:60 | key | HardcodedPasswordBase64.java:5:33:6:17 | new byte[] : byte[] | HardcodedPasswordBase64.java:24:58:24:60 | key | Sensative data is being logged $@. | HardcodedPasswordBase64.java:5:33:6:17 | new byte[] | user-provided value | +| HardcodedPasswordBase64.java:32:58:32:60 | key | HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedPasswordBase64.java:32:58:32:60 | key | Sensative data is being logged $@. | HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | user-provided value | diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java new file mode 100644 index 00000000000..26a2cab9323 --- /dev/null +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java @@ -0,0 +1,38 @@ +import java.util.Base64; + +class MyApp { + public static String KEY = "VGVzdFBhc3N3b3Jk"; + public static byte[] KEY2 = new byte[] { 'V', 'G', 'V', 'z', 'd', 'F', 'B', 'h', 'c', '3', 'N', '3', 'b', '3', 'J', + 'k' }; + + public String getDecoderString() { + byte[] decodedBytes = Base64.getDecoder().decode(MyApp.KEY); + + String decodedString = new String(decodedBytes); + return decodedString; + } + + public String getDecoderBytes() { + byte[] decodedBytes = Base64.getDecoder().decode(MyApp.KEY2); + + String decodedString = new String(decodedBytes); + return decodedString; + } + + public String getDecoderConvertString() { + String key = MyApp.KEY2.toString(); + byte[] decodedBytes = Base64.getDecoder().decode(key); + + String decodedString = new String(decodedBytes); + return decodedString; + } + + public String getDecoderConvertBytes() { + byte[] key = MyApp.KEY.getBytes(); + byte[] decodedBytes = Base64.getDecoder().decode(key); + + String decodedString = new String(decodedBytes); + return decodedString; + } + +} \ No newline at end of file diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.qlref b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.qlref new file mode 100644 index 00000000000..557cb85bb08 --- /dev/null +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.qlref @@ -0,0 +1 @@ +CWE-798/HardcodedBase64Usage.ql \ No newline at end of file diff --git a/tests/java-tests/qlpack.lock.yml b/tests/java-tests/qlpack.lock.yml new file mode 100644 index 00000000000..a046f6d9786 --- /dev/null +++ b/tests/java-tests/qlpack.lock.yml @@ -0,0 +1,4 @@ +--- +dependencies: {} +compiled: false +lockVersion: 1.0.0 \ No newline at end of file diff --git a/tests/java-tests/qlpack.yml b/tests/java-tests/qlpack.yml new file mode 100644 index 00000000000..d960cc9f3ca --- /dev/null +++ b/tests/java-tests/qlpack.yml @@ -0,0 +1,8 @@ +name: github-queries-java-tests +groups: [java, test] +dependencies: + codeql/java-all: "*" + github-queries-java: "*" + +extractor: java +tests: . \ No newline at end of file From e54937ba29e6912579760d6225d4215d1ef7552f Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Tue, 20 Sep 2022 17:49:17 +0100 Subject: [PATCH 2/7] Update base64 lib --- java/github/Base64.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/java/github/Base64.qll b/java/github/Base64.qll index 00c8021e491..4faf017cbdb 100644 --- a/java/github/Base64.qll +++ b/java/github/Base64.qll @@ -16,7 +16,7 @@ module Base64 { .hasQualifiedName([ "java.util", "cn.hutool.core.codec", "org.apache.shiro.codec", "apache.commons.codec.binary", "org.springframework.util" - ], ["Base64$Encoder", "Base64$Decoder", "Base64", "Base64Utils"], + ], ["Base64$Encoder", "Base64", "Base64Utils"], [ "encode", "encodeToString", "encodeBase64", "encodeBase64Chunked", "encodeBase64String", "encodeBase64URLSafe", "encodeBase64URLSafeString" @@ -34,8 +34,7 @@ module Base64 { .hasQualifiedName([ "java.util", "cn.hutool.core.codec", "org.apache.shiro.codec", "apache.commons.codec.binary", "org.springframework.util" - ], ["Base64$Encoder", "Base64$Decoder", "Base64", "Base64Utils"], - ["decode", "decodeBase64"]) + ], ["Base64$Decoder", "Base64", "Base64Utils"], ["decode", "decodeBase64"]) | this.asExpr() = ma.getArgument(0) ) From 87372c1513782edc50967fdec4e13783243852fb Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Tue, 20 Sep 2022 18:00:24 +0100 Subject: [PATCH 3/7] Update query and rename lib comps --- java/CWE-798/HardcodedBase64Usage.ql | 6 +-- java/github/{Base64.qll => Encoding.qll} | 0 .../base64/HardcodedBase64Usage.expected | 47 ++++++++++--------- 3 files changed, 28 insertions(+), 25 deletions(-) rename java/github/{Base64.qll => Encoding.qll} (100%) diff --git a/java/CWE-798/HardcodedBase64Usage.ql b/java/CWE-798/HardcodedBase64Usage.ql index 7d946c977da..b1924eed1f5 100644 --- a/java/CWE-798/HardcodedBase64Usage.ql +++ b/java/CWE-798/HardcodedBase64Usage.ql @@ -18,9 +18,9 @@ import semmle.code.java.dataflow.TaintTracking2 import DataFlow::PathGraph import semmle.code.java.security.HardcodedCredentials // Internal -import github.Base64 +import github.Encoding -class HardcodedPasswordBase64 extends DataFlow::Configuration { +class HardcodedPasswordBase64 extends TaintTracking::Configuration { HardcodedPasswordBase64() { this = "HardcodedPasswordBase64" } override predicate isSource(DataFlow::Node source) { @@ -30,7 +30,7 @@ class HardcodedPasswordBase64 extends DataFlow::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof Base64::Decoding } - override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { // String.getBytes() node1.asExpr().getType() instanceof TypeString and exists(MethodAccess ma | ma.getMethod().hasName(["getBytes", "toCharArray"]) | diff --git a/java/github/Base64.qll b/java/github/Encoding.qll similarity index 100% rename from java/github/Base64.qll rename to java/github/Encoding.qll diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected index c7660e83e55..465f635ac92 100644 --- a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected @@ -1,26 +1,29 @@ edges -| HardcodedPasswordBase64.java:4:26:4:28 | KEY : String | HardcodedPasswordBase64.java:9:58:9:66 | MyApp.KEY | -| HardcodedPasswordBase64.java:4:26:4:28 | KEY : String | HardcodedPasswordBase64.java:31:22:31:30 | MyApp.KEY : String | -| HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedPasswordBase64.java:4:26:4:28 | KEY : String | -| HardcodedPasswordBase64.java:5:26:5:29 | KEY2 : byte[] | HardcodedPasswordBase64.java:16:58:16:67 | MyApp.KEY2 | -| HardcodedPasswordBase64.java:5:26:5:29 | KEY2 : byte[] | HardcodedPasswordBase64.java:23:22:23:31 | MyApp.KEY2 : byte[] | -| HardcodedPasswordBase64.java:5:33:6:17 | new byte[] : byte[] | HardcodedPasswordBase64.java:5:26:5:29 | KEY2 : byte[] | -| HardcodedPasswordBase64.java:23:22:23:31 | MyApp.KEY2 : byte[] | HardcodedPasswordBase64.java:24:58:24:60 | key | -| HardcodedPasswordBase64.java:31:22:31:30 | MyApp.KEY : String | HardcodedPasswordBase64.java:32:58:32:60 | key | +| HardcodedBase64Usage.java:4:26:4:28 | KEY : String | HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | +| HardcodedBase64Usage.java:4:26:4:28 | KEY : String | HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | +| HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedBase64Usage.java:4:26:4:28 | KEY : String | +| HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | +| HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | HardcodedBase64Usage.java:23:22:23:31 | MyApp.KEY2 : byte[] | +| HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | +| HardcodedBase64Usage.java:23:22:23:31 | MyApp.KEY2 : byte[] | HardcodedBase64Usage.java:24:58:24:60 | key | +| HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | +| HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | HardcodedBase64Usage.java:32:58:32:60 | key | +| HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | HardcodedBase64Usage.java:32:58:32:60 | key | nodes -| HardcodedPasswordBase64.java:4:26:4:28 | KEY : String | semmle.label | KEY : String | -| HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | semmle.label | "VGVzdFBhc3N3b3Jk" : String | -| HardcodedPasswordBase64.java:5:26:5:29 | KEY2 : byte[] | semmle.label | KEY2 : byte[] | -| HardcodedPasswordBase64.java:5:33:6:17 | new byte[] : byte[] | semmle.label | new byte[] : byte[] | -| HardcodedPasswordBase64.java:9:58:9:66 | MyApp.KEY | semmle.label | MyApp.KEY | -| HardcodedPasswordBase64.java:16:58:16:67 | MyApp.KEY2 | semmle.label | MyApp.KEY2 | -| HardcodedPasswordBase64.java:23:22:23:31 | MyApp.KEY2 : byte[] | semmle.label | MyApp.KEY2 : byte[] | -| HardcodedPasswordBase64.java:24:58:24:60 | key | semmle.label | key | -| HardcodedPasswordBase64.java:31:22:31:30 | MyApp.KEY : String | semmle.label | MyApp.KEY : String | -| HardcodedPasswordBase64.java:32:58:32:60 | key | semmle.label | key | +| HardcodedBase64Usage.java:4:26:4:28 | KEY : String | semmle.label | KEY : String | +| HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | semmle.label | "VGVzdFBhc3N3b3Jk" : String | +| HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | semmle.label | KEY2 : byte[] | +| HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | semmle.label | new byte[] : byte[] | +| HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | semmle.label | MyApp.KEY | +| HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | semmle.label | MyApp.KEY2 | +| HardcodedBase64Usage.java:23:22:23:31 | MyApp.KEY2 : byte[] | semmle.label | MyApp.KEY2 : byte[] | +| HardcodedBase64Usage.java:24:58:24:60 | key | semmle.label | key | +| HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | semmle.label | MyApp.KEY : String | +| HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | semmle.label | getBytes(...) : byte[] | +| HardcodedBase64Usage.java:32:58:32:60 | key | semmle.label | key | subpaths #select -| HardcodedPasswordBase64.java:9:58:9:66 | MyApp.KEY | HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedPasswordBase64.java:9:58:9:66 | MyApp.KEY | Sensative data is being logged $@. | HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | user-provided value | -| HardcodedPasswordBase64.java:16:58:16:67 | MyApp.KEY2 | HardcodedPasswordBase64.java:5:33:6:17 | new byte[] : byte[] | HardcodedPasswordBase64.java:16:58:16:67 | MyApp.KEY2 | Sensative data is being logged $@. | HardcodedPasswordBase64.java:5:33:6:17 | new byte[] | user-provided value | -| HardcodedPasswordBase64.java:24:58:24:60 | key | HardcodedPasswordBase64.java:5:33:6:17 | new byte[] : byte[] | HardcodedPasswordBase64.java:24:58:24:60 | key | Sensative data is being logged $@. | HardcodedPasswordBase64.java:5:33:6:17 | new byte[] | user-provided value | -| HardcodedPasswordBase64.java:32:58:32:60 | key | HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedPasswordBase64.java:32:58:32:60 | key | Sensative data is being logged $@. | HardcodedPasswordBase64.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | user-provided value | +| HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | Sensative data is being logged $@. | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | user-provided value | +| HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | Sensative data is being logged $@. | HardcodedBase64Usage.java:5:33:6:17 | new byte[] | user-provided value | +| HardcodedBase64Usage.java:24:58:24:60 | key | HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | HardcodedBase64Usage.java:24:58:24:60 | key | Sensative data is being logged $@. | HardcodedBase64Usage.java:5:33:6:17 | new byte[] | user-provided value | +| HardcodedBase64Usage.java:32:58:32:60 | key | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedBase64Usage.java:32:58:32:60 | key | Sensative data is being logged $@. | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | user-provided value | From 188205e8262d7580dfd094528ef4d6b90f7e1ee5 Mon Sep 17 00:00:00 2001 From: Mathew Payne Date: Wed, 21 Sep 2022 10:16:25 +0100 Subject: [PATCH 4/7] Remove taint steps --- java/CWE-798/HardcodedBase64Usage.ql | 16 ---------------- .../CWE-798/base64/HardcodedBase64Usage.expected | 9 +++++---- .../CWE-798/base64/HardcodedBase64Usage.java | 2 +- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/java/CWE-798/HardcodedBase64Usage.ql b/java/CWE-798/HardcodedBase64Usage.ql index b1924eed1f5..0fbb91f4975 100644 --- a/java/CWE-798/HardcodedBase64Usage.ql +++ b/java/CWE-798/HardcodedBase64Usage.ql @@ -29,22 +29,6 @@ class HardcodedPasswordBase64 extends TaintTracking::Configuration { } override predicate isSink(DataFlow::Node sink) { sink instanceof Base64::Decoding } - - override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - // String.getBytes() - node1.asExpr().getType() instanceof TypeString and - exists(MethodAccess ma | ma.getMethod().hasName(["getBytes", "toCharArray"]) | - node2.asExpr() = ma and - ma.getQualifier() = node1.asExpr() - ) - or - // byte[].toString() - node1.asExpr().getType() instanceof Array and - exists(MethodAccess ma | ma.getMethod().hasName(["toString"]) | - node2.asExpr() = ma and - ma.getQualifier() = node1.asExpr() - ) - } } // ========== Query ========== diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected index 465f635ac92..1cceb5e95ce 100644 --- a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected @@ -3,11 +3,11 @@ edges | HardcodedBase64Usage.java:4:26:4:28 | KEY : String | HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedBase64Usage.java:4:26:4:28 | KEY : String | | HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | -| HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | HardcodedBase64Usage.java:23:22:23:31 | MyApp.KEY2 : byte[] | +| HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | HardcodedBase64Usage.java:23:33:23:42 | MyApp.KEY2 : byte[] | | HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | -| HardcodedBase64Usage.java:23:22:23:31 | MyApp.KEY2 : byte[] | HardcodedBase64Usage.java:24:58:24:60 | key | +| HardcodedBase64Usage.java:23:22:23:43 | new String(...) : String | HardcodedBase64Usage.java:24:58:24:60 | key | +| HardcodedBase64Usage.java:23:33:23:42 | MyApp.KEY2 : byte[] | HardcodedBase64Usage.java:23:22:23:43 | new String(...) : String | | HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | -| HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | HardcodedBase64Usage.java:32:58:32:60 | key | | HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | HardcodedBase64Usage.java:32:58:32:60 | key | nodes | HardcodedBase64Usage.java:4:26:4:28 | KEY : String | semmle.label | KEY : String | @@ -16,7 +16,8 @@ nodes | HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | semmle.label | new byte[] : byte[] | | HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | semmle.label | MyApp.KEY | | HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | semmle.label | MyApp.KEY2 | -| HardcodedBase64Usage.java:23:22:23:31 | MyApp.KEY2 : byte[] | semmle.label | MyApp.KEY2 : byte[] | +| HardcodedBase64Usage.java:23:22:23:43 | new String(...) : String | semmle.label | new String(...) : String | +| HardcodedBase64Usage.java:23:33:23:42 | MyApp.KEY2 : byte[] | semmle.label | MyApp.KEY2 : byte[] | | HardcodedBase64Usage.java:24:58:24:60 | key | semmle.label | key | | HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | semmle.label | MyApp.KEY : String | | HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | semmle.label | getBytes(...) : byte[] | diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java index 26a2cab9323..5463470684a 100644 --- a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java @@ -20,7 +20,7 @@ public String getDecoderBytes() { } public String getDecoderConvertString() { - String key = MyApp.KEY2.toString(); + String key = new String(MyApp.KEY2); byte[] decodedBytes = Base64.getDecoder().decode(key); String decodedString = new String(decodedBytes); From 14a214ce1bf57d832aa71ff27fb343eac0cd5743 Mon Sep 17 00:00:00 2001 From: Mathew Payne <2772944+GeekMasher@users.noreply.github.com> Date: Tue, 20 Jun 2023 13:38:00 +0100 Subject: [PATCH 5/7] Update HardcodedBase64Usage.ql --- java/CWE-798/HardcodedBase64Usage.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/CWE-798/HardcodedBase64Usage.ql b/java/CWE-798/HardcodedBase64Usage.ql index 0fbb91f4975..5fb58ceaf71 100644 --- a/java/CWE-798/HardcodedBase64Usage.ql +++ b/java/CWE-798/HardcodedBase64Usage.ql @@ -34,5 +34,5 @@ class HardcodedPasswordBase64 extends TaintTracking::Configuration { // ========== Query ========== from DataFlow::PathNode source, DataFlow::PathNode sink, HardcodedPasswordBase64 config where config.hasFlowPath(source, sink) -select sink.getNode(), source, sink, "Sensative data is being logged $@.", source.getNode(), +select sink.getNode(), source, sink, "Sensitive data is being logged $@.", source.getNode(), "user-provided value" From 0813d96cd7e2de60c687703700c9ff63ded05d78 Mon Sep 17 00:00:00 2001 From: Mathew Payne <2772944+GeekMasher@users.noreply.github.com> Date: Tue, 20 Jun 2023 12:44:55 +0000 Subject: [PATCH 6/7] Update to latest CLI --- codeql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codeql b/codeql index b49487cf420..ff78ac98d27 160000 --- a/codeql +++ b/codeql @@ -1 +1 @@ -Subproject commit b49487cf420ce87f14107f527c704ae4fc940b63 +Subproject commit ff78ac98d27c7b9f1adffcf235c56855f8348ad0 From f20bff3cb90d33d91c2b67e3ebe0f46a1687e79b Mon Sep 17 00:00:00 2001 From: Mathew Payne <2772944+GeekMasher@users.noreply.github.com> Date: Tue, 20 Jun 2023 13:40:22 +0000 Subject: [PATCH 7/7] Update lib, query, and tests - Add Hardcoded lib - Update query to use lib - Update tests --- java/CWE-798/HardcodedBase64Usage.ql | 7 +--- java/github/Hardcoded.qll | 14 +++++++ .../base64/HardcodedBase64Usage.expected | 40 +++++-------------- .../CWE-798/base64/HardcodedBase64Usage.java | 7 ++++ .../CWE-798/base64/HardcodedBase64Usage.ql | 12 ++++++ .../CWE-798/base64/HardcodedBase64Usage.qlref | 1 - 6 files changed, 45 insertions(+), 36 deletions(-) create mode 100644 java/github/Hardcoded.qll create mode 100644 tests/java-tests/CWE-798/base64/HardcodedBase64Usage.ql delete mode 100644 tests/java-tests/CWE-798/base64/HardcodedBase64Usage.qlref diff --git a/java/CWE-798/HardcodedBase64Usage.ql b/java/CWE-798/HardcodedBase64Usage.ql index 5fb58ceaf71..7e3341a26ce 100644 --- a/java/CWE-798/HardcodedBase64Usage.ql +++ b/java/CWE-798/HardcodedBase64Usage.ql @@ -16,17 +16,14 @@ import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.TaintTracking2 import DataFlow::PathGraph -import semmle.code.java.security.HardcodedCredentials // Internal import github.Encoding +import github.Hardcoded class HardcodedPasswordBase64 extends TaintTracking::Configuration { HardcodedPasswordBase64() { this = "HardcodedPasswordBase64" } - override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof HardcodedExpr and - not source.asExpr().getEnclosingCallable() instanceof ToStringMethod - } + override predicate isSource(DataFlow::Node source) { source instanceof Hardcoded } override predicate isSink(DataFlow::Node sink) { sink instanceof Base64::Decoding } } diff --git a/java/github/Hardcoded.qll b/java/github/Hardcoded.qll new file mode 100644 index 00000000000..1e1e91abf6e --- /dev/null +++ b/java/github/Hardcoded.qll @@ -0,0 +1,14 @@ + +private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.security.HardcodedCredentials + + +abstract class Hardcoded extends DataFlow::Node { } + +class HCExpr extends Hardcoded { + HCExpr() { + this.asExpr() instanceof HardcodedExpr and + not this.asExpr().getEnclosingCallable() instanceof ToStringMethod + } +} + diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected index 1cceb5e95ce..ae2d2e082c1 100644 --- a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.expected @@ -1,30 +1,10 @@ -edges -| HardcodedBase64Usage.java:4:26:4:28 | KEY : String | HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | -| HardcodedBase64Usage.java:4:26:4:28 | KEY : String | HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | -| HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedBase64Usage.java:4:26:4:28 | KEY : String | -| HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | -| HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | HardcodedBase64Usage.java:23:33:23:42 | MyApp.KEY2 : byte[] | -| HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | -| HardcodedBase64Usage.java:23:22:23:43 | new String(...) : String | HardcodedBase64Usage.java:24:58:24:60 | key | -| HardcodedBase64Usage.java:23:33:23:42 | MyApp.KEY2 : byte[] | HardcodedBase64Usage.java:23:22:23:43 | new String(...) : String | -| HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | -| HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | HardcodedBase64Usage.java:32:58:32:60 | key | -nodes -| HardcodedBase64Usage.java:4:26:4:28 | KEY : String | semmle.label | KEY : String | -| HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | semmle.label | "VGVzdFBhc3N3b3Jk" : String | -| HardcodedBase64Usage.java:5:26:5:29 | KEY2 : byte[] | semmle.label | KEY2 : byte[] | -| HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | semmle.label | new byte[] : byte[] | -| HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | semmle.label | MyApp.KEY | -| HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | semmle.label | MyApp.KEY2 | -| HardcodedBase64Usage.java:23:22:23:43 | new String(...) : String | semmle.label | new String(...) : String | -| HardcodedBase64Usage.java:23:33:23:42 | MyApp.KEY2 : byte[] | semmle.label | MyApp.KEY2 : byte[] | -| HardcodedBase64Usage.java:24:58:24:60 | key | semmle.label | key | -| HardcodedBase64Usage.java:31:22:31:30 | MyApp.KEY : String | semmle.label | MyApp.KEY : String | -| HardcodedBase64Usage.java:31:22:31:41 | getBytes(...) : byte[] | semmle.label | getBytes(...) : byte[] | -| HardcodedBase64Usage.java:32:58:32:60 | key | semmle.label | key | -subpaths -#select -| HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | Sensative data is being logged $@. | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | user-provided value | -| HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | Sensative data is being logged $@. | HardcodedBase64Usage.java:5:33:6:17 | new byte[] | user-provided value | -| HardcodedBase64Usage.java:24:58:24:60 | key | HardcodedBase64Usage.java:5:33:6:17 | new byte[] : byte[] | HardcodedBase64Usage.java:24:58:24:60 | key | Sensative data is being logged $@. | HardcodedBase64Usage.java:5:33:6:17 | new byte[] | user-provided value | -| HardcodedBase64Usage.java:32:58:32:60 | key | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" : String | HardcodedBase64Usage.java:32:58:32:60 | key | Sensative data is being logged $@. | HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | user-provided value | +sources +| HardcodedBase64Usage.java:4:32:4:49 | "VGVzdFBhc3N3b3Jk" | +| HardcodedBase64Usage.java:5:33:6:17 | new byte[] | +| HardcodedBase64Usage.java:39:58:39:71 | "U2VjcmV0S2V5" | +sinks +| HardcodedBase64Usage.java:9:58:9:66 | MyApp.KEY | +| HardcodedBase64Usage.java:16:58:16:67 | MyApp.KEY2 | +| HardcodedBase64Usage.java:24:58:24:60 | key | +| HardcodedBase64Usage.java:32:58:32:60 | key | +| HardcodedBase64Usage.java:39:58:39:71 | "U2VjcmV0S2V5" | diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java index 5463470684a..a61e149f2f0 100644 --- a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.java @@ -35,4 +35,11 @@ public String getDecoderConvertBytes() { return decodedString; } + public String simpleDecoderString() { + byte[] decodedBytes = Base64.getDecoder().decode("U2VjcmV0S2V5"); + + String decodedString = new String(decodedBytes); + return decodedString; + } + } \ No newline at end of file diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.ql b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.ql new file mode 100644 index 00000000000..3430f324c73 --- /dev/null +++ b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.ql @@ -0,0 +1,12 @@ +import java +import semmle.code.java.security.HardcodedCredentials +import github.Encoding +import github.Hardcoded + +query predicate sources(DataFlow::Node sources) { + sources instanceof Hardcoded +} + +query predicate sinks(DataFlow::Node sinks) { + sinks instanceof Base64::Decoding +} diff --git a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.qlref b/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.qlref deleted file mode 100644 index 557cb85bb08..00000000000 --- a/tests/java-tests/CWE-798/base64/HardcodedBase64Usage.qlref +++ /dev/null @@ -1 +0,0 @@ -CWE-798/HardcodedBase64Usage.ql \ No newline at end of file