From e51e4c030c4ff1ec53df1276af4f72cb4390eb96 Mon Sep 17 00:00:00 2001 From: Malte Kraus Date: Thu, 1 Apr 2021 12:41:29 +0200 Subject: [PATCH 1/2] add a query for disabled ssl certificate checks in java --- .../scala/io/joern/scanners/QueryTags.scala | 1 + .../scanners/java/CertificateChecks.scala | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/main/scala/io/joern/scanners/java/CertificateChecks.scala diff --git a/src/main/scala/io/joern/scanners/QueryTags.scala b/src/main/scala/io/joern/scanners/QueryTags.scala index 6d5a493..12d708b 100644 --- a/src/main/scala/io/joern/scanners/QueryTags.scala +++ b/src/main/scala/io/joern/scanners/QueryTags.scala @@ -4,6 +4,7 @@ object QueryTags { val alloc = "alloc" val badfn = "badfn" + val badimpl = "badimpl" val setxid = "setxid" val metrics = "metrics" val uaf = "uaf" diff --git a/src/main/scala/io/joern/scanners/java/CertificateChecks.scala b/src/main/scala/io/joern/scanners/java/CertificateChecks.scala new file mode 100644 index 0000000..3587f27 --- /dev/null +++ b/src/main/scala/io/joern/scanners/java/CertificateChecks.scala @@ -0,0 +1,66 @@ +package io.joern.scanners.java + +import io.joern.scanners.{Crew, QueryTags} +import io.shiftleft.codepropertygraph.generated._ +import io.shiftleft.console._ +import io.shiftleft.macros.QueryMacros._ +import io.shiftleft.semanticcpg.language._ +import overflowdb.traversal.Traversal + +object CertificateChecks extends QueryBundle { + + implicit val resolver: ICallResolver = NoResolve + + @q + def certChecks(): Query = + Query.make( + name = "ineffective-certificate-check", + author = Crew.malte, + title = + "Ineffective Certificate Validation: The validation result is always positive", + description = + """ + |A certificate validation function is implemented as a function that only consists of a prologue where local + |variables are initialized to arguments, followed by a (positive) return statement. + |""".stripMargin, + score = 6, + withStrRep({ cpg => + val validators = Map( + // javax.net.ssl.HostnameVerifier + "verify" -> "boolean(java.lang.String,javax.net.ssl.SSLSession)", + // javax.net.ssl.X509ExtendedTrustManager + "checkClientTrusted" -> "void(java.security.cert.X509Certificate[],java.lang.String,java.net.Socket)", + "checkClientTrusted" -> "void(java.security.cert.X509Certificate[],java.lang.String,javax.net.ssl.SSLEngine)", + "checkServerTrusted" -> "void(java.security.cert.X509Certificate[],java.lang.String,java.net.Socket)", + "checkServerTrusted" -> "void(java.security.cert.X509Certificate[],java.lang.String,javax.net.ssl.SSLEngine)", + ) + + // skip over arguments getting copied to local variables + def isPrologue(node: nodes.CfgNode): Boolean = node match { + case id: nodes.Identifier => + id.refsTo.forall(_.isInstanceOf[nodes.Local]) + case c: nodes.Call => + c.methodFullName == Operators.assignment && c.argument.forall( + isPrologue + ) + case _ => false + } + def skipPrologue(node: nodes.CfgNode): Traversal[nodes.CfgNode] = + node.repeat(_.cfgNext)(_.until(_.filter(!isPrologue(_)))) + + cpg.method + .nameExact(validators.keys.toSeq: _*) + .signatureExact(validators.values.toSeq: _*) + .cfgFirst + .flatMap(skipPrologue) + .filter { + case lit: nodes.Literal => // return true: + lit.code == "1" && lit.cfgNext + .forall(_.isInstanceOf[nodes.Return]) + case _: nodes.Return => true // void return + case _ => false + } + }), + tags = List(QueryTags.badimpl) + ) +} From ea7a2e3ad49eaa0de43ed773ddfdab2a315e9ea9 Mon Sep 17 00:00:00 2001 From: Malte Kraus Date: Thu, 1 Apr 2021 17:23:49 +0200 Subject: [PATCH 2/2] reformat for copy/paste-ability --- .../io/joern/scanners/java/CertificateChecks.scala | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/scala/io/joern/scanners/java/CertificateChecks.scala b/src/main/scala/io/joern/scanners/java/CertificateChecks.scala index 3587f27..a537933 100644 --- a/src/main/scala/io/joern/scanners/java/CertificateChecks.scala +++ b/src/main/scala/io/joern/scanners/java/CertificateChecks.scala @@ -48,18 +48,20 @@ object CertificateChecks extends QueryBundle { def skipPrologue(node: nodes.CfgNode): Traversal[nodes.CfgNode] = node.repeat(_.cfgNext)(_.until(_.filter(!isPrologue(_)))) - cpg.method - .nameExact(validators.keys.toSeq: _*) - .signatureExact(validators.values.toSeq: _*) - .cfgFirst - .flatMap(skipPrologue) - .filter { + // format: off + cpg.method. + nameExact(validators.keys.toSeq: _*). + signatureExact(validators.values.toSeq: _*). + cfgFirst. + flatMap(skipPrologue). + filter { case lit: nodes.Literal => // return true: lit.code == "1" && lit.cfgNext .forall(_.isInstanceOf[nodes.Return]) case _: nodes.Return => true // void return case _ => false } + // format: on }), tags = List(QueryTags.badimpl) )