diff --git a/console/src/main/scala/io/appthreat/console/Console.scala b/console/src/main/scala/io/appthreat/console/Console.scala index 65881c36..0197a953 100644 --- a/console/src/main/scala/io/appthreat/console/Console.scala +++ b/console/src/main/scala/io/appthreat/console/Console.scala @@ -520,7 +520,11 @@ class Console[T <: Project]( if !addedMethods.contains(c.methodFullName) then mtree .add( - c.methodFullName + (if c.callee(NoResolve).head.isExternal + c.methodFullName + (if c.callee( + NoResolve + ).head.nonEmpty && c.callee( + NoResolve + ).head.isExternal then " :right_arrow_curving_up:" else "") ) diff --git a/dataflowengineoss/README.md b/dataflowengineoss/README.md deleted file mode 100644 index f8815995..00000000 --- a/dataflowengineoss/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Data Flow Engine - -A taint-tracking system based on whole-program data-dependence -representation. External library calls can be defined by -semantic models (see `io.appthreat.dataflowengineoss.DefaultSemantics`). - -Basic usage: - -```scala -// If using Joern shell, imports and engine context will be pre-configured and available already -import io.shiftleft.semanticcpg.language._ -import io.appthreat.dataflowengineoss.language.toExtendedCfgNode - -def sink = cpg.call.argument.code(".*malicious_input.*") -def source = cpg.call(".*println.*") - -// Traverses data flow in the backwards direction -sink.reachableBy(source) -``` - -## Configuration - -To begin using the data flow engine on the CPG, we need the following: - -```scala - // (1) Imports to extend CFG nodes - import io.appthreat.dataflowengineoss.language.toExtendedCfgNode - import io.appthreat.dataflowengineoss.queryengine.{EngineContext, EngineConfig} - - import scala.util.{Failure, Success, Try} - import scala.io.{BufferedSource, Source} - - // (2) Optional: Configure the engine - val engineConfig = EngineConfig(maxCallDepth = 2, initialTable = None, disableCacheUse = false) - - // (3) Create execution context for the engine - implicit var context: EngineContext = EngineContext(config = engineConfig) -``` \ No newline at end of file diff --git a/docs/TRAVERSAL.md b/docs/TRAVERSAL.md new file mode 100644 index 00000000..dd36812b --- /dev/null +++ b/docs/TRAVERSAL.md @@ -0,0 +1,186 @@ +## Traversing an atom + +Traversal queries begin with `atom`, followed by a primary node type from the below list. + +| Name | Comment | +| ------------------- | ----------------------------------------------------------------------------------- | +| annotation | Entire annotation | +| annotationLiteral | Literatal values in an annotation | +| annotationParameter | Parameter values | +| call | Call nodes | +| configFile | Configuration files | +| file | File | +| identifier | Identifier nodes | +| imports | Import nodes | +| literal | Literal nodes | +| local | Local variables | +| method | Method nodes | +| ret | Return statements | +| tag | Tag nodes | +| typeDecl | Type declarations | +| typeRef | Type references | +| cfgNode | Wrapper for multiple nodes such as annotation, call, control_structure, method, etc | +| declaration | Wrapper for multiple noeds such as local, member, method, etc | + +Example: + +```scala +// List all annotations in the atom +atom.annotation.l + +// List all files in the atom +atom.file.l + +// Show the annotation list as json +atom.annotation.toJson +``` + +## annotation steps + +- argumentIndex(int) +- argumentName(pattern) +- code(pattern) +- name(pattern) +- fullName(pattern) + +## annotationLiteral steps + +- argumentIndex(int) +- argumentName(pattern) +- code(pattern) +- name(pattern) + +## annotationParameter steps + +- code(pattern) + +## call steps + +- argumentIndex(int) +- argumentName(pattern) +- code(pattern) +- name(pattern) +- methodFullName(pattern) +- signature(pattern) +- typeFullName(pattern) + +### call traversal + +- argument - All argument nodes +- callee - All callee methods + +## configFile steps + +- name(string) +- content(string) + +## file steps + +- name(string) + +## identifier steps + +- argumentIndex(int) +- argumentName(pattern) +- code(pattern) +- name(pattern) +- typeFullName(pattern) + +## import steps + +- code(pattern) +- importedAs(string) +- importedEntity(string) +- isExplicit(boolean) +- isWildcard(boolean) + +## literal steps + +- argumentIndex(int) +- argumentName(pattern) +- code(pattern) +- typeFullName(pattern) + +## local steps + +- code(pattern) +- name(pattern) +- typeFullName(pattern) + +## method steps + +- code(pattern) +- filename(pattern) +- name(pattern) +- fullName(pattern) +- isExternal(boolean) +- signature(pattern) + +### method traversal + +- parameter - All MethodParameterIn nodes of the given method. +- literal - All literal nodes in the method. +- caller - All callers of this method + +## ret steps + +- argumentIndex(int) +- argumentName(pattern) +- code(pattern) + +## tag steps + +- name(pattern) + +## typeDecl steps + +- code(pattern) +- filename(pattern) +- name(pattern) +- fullName(pattern) +- isExternal(boolean) + +## typeRef steps + +- argumentIndex(int) +- argumentName(pattern) +- code(pattern) +- typeFullName(pattern) + +## cfgNode steps + +- code(pattern) + +## declaration steps + +- name(pattern) + +## Helper step methods + +Step methods accepting an integer would have variations such as Gt, Gte, Lt, Lte and Not to support integer operations. + +Example: + +```scala +atom.annotation.argumentIndexGt(1).l +``` + +Step methods accepting a string would have variations such as Exact and Not. + +Example: + +```scala +atom.annotation.argumentNameNot("foo").l +``` + +## Chaining step methods + +If a step method return an iterator of type node then the method calls could be chained. + +Example: + +Parameters of all methods with the name `foo`. + +```scala +atom.method.name("foo").parameter.l +``` diff --git a/platform/frontends/c2cpg/lib/README.md b/platform/frontends/c2cpg/lib/README.md deleted file mode 100644 index 937016ec..00000000 --- a/platform/frontends/c2cpg/lib/README.md +++ /dev/null @@ -1,3 +0,0 @@ -org.eclipse.cdt jars were downloaded from - -https://download.eclipse.org/tools/cdt/releases/11.3/cdt-11.3.1/plugins/ diff --git a/platform/frontends/x2cpg/src/main/scala/io/appthreat/x2cpg/passes/taggers/CdxPass.scala b/platform/frontends/x2cpg/src/main/scala/io/appthreat/x2cpg/passes/taggers/CdxPass.scala index 875fa18e..a9503cfa 100644 --- a/platform/frontends/x2cpg/src/main/scala/io/appthreat/x2cpg/passes/taggers/CdxPass.scala +++ b/platform/frontends/x2cpg/src/main/scala/io/appthreat/x2cpg/passes/taggers/CdxPass.scala @@ -45,7 +45,8 @@ class CdxPass(atom: Cpg) extends CpgPass(atom): private def PY_REQUEST_PATTERNS = Array(".*views.py:.*") private def containsRegex(str: String) = - Pattern.quote(str) != str || str.contains("*") || str.contains("(") || str.contains(")") + val reChars = "[](){}*+&|?.,\\$" + str.exists(reChars.contains(_)) private val BOM_JSON_FILE = ".*(bom|cdx).json" diff --git a/platform/frontends/x2cpg/src/main/scala/io/appthreat/x2cpg/passes/taggers/ChennaiTagsPass.scala b/platform/frontends/x2cpg/src/main/scala/io/appthreat/x2cpg/passes/taggers/ChennaiTagsPass.scala index 5e6dbe05..7fe2373a 100644 --- a/platform/frontends/x2cpg/src/main/scala/io/appthreat/x2cpg/passes/taggers/ChennaiTagsPass.scala +++ b/platform/frontends/x2cpg/src/main/scala/io/appthreat/x2cpg/passes/taggers/ChennaiTagsPass.scala @@ -50,6 +50,10 @@ class ChennaiTagsPass(atom: Cpg) extends CpgPass(atom): ) private val HTTP_METHODS_REGEX = ".*(request|session)\\.(args|get|post|put|form).*" + private def containsRegex(str: String) = + val reChars = "[](){}*+&|?.,\\$" + str.exists(reChars.contains(_)) + private def tagCRoutes(dstGraph: DiffGraphBuilder): Unit = C_ROUTES_CALL_REGEXES.foreach { r => atom.method.fullName(r).parameter.newTagNode(FRAMEWORK_INPUT).store()( @@ -131,7 +135,7 @@ class ChennaiTagsPass(atom: Cpg) extends CpgPass(atom): atom.method.parameter.typeFullNameExact(pn).newTagNode(tagName).store()( dstGraph ) - if !pn.contains("[") && !pn.contains("*") then + if !containsRegex(pn) then atom.method.parameter.typeFullName( s".*${Pattern.quote(pn)}.*" ).newTagNode(tagName).store()(dstGraph) @@ -140,7 +144,7 @@ class ChennaiTagsPass(atom: Cpg) extends CpgPass(atom): val mn = methodName.asString.getOrElse("") if mn.nonEmpty then atom.method.fullNameExact(mn).newTagNode(tagName).store()(dstGraph) - if !mn.contains("[") && !mn.contains("*") then + if !containsRegex(mn) then atom.method.fullName(s".*${Pattern.quote(mn)}.*").newTagNode( tagName ).store()(dstGraph) @@ -151,7 +155,7 @@ class ChennaiTagsPass(atom: Cpg) extends CpgPass(atom): atom.method.parameter.typeFullNameExact(tn).newTagNode(tagName).store()( dstGraph ) - if !tn.contains("[") && !tn.contains("*") then + if !containsRegex(tn) then atom.method.parameter.typeFullName( s".*${Pattern.quote(tn)}.*" ).newTagNode(tagName).store()(dstGraph) @@ -165,7 +169,7 @@ class ChennaiTagsPass(atom: Cpg) extends CpgPass(atom): val fn = fileName.asString.getOrElse("") if fn.nonEmpty then atom.file.nameExact(fn).newTagNode(tagName).store()(dstGraph) - if !fn.contains("[") && !fn.contains("*") then + if !containsRegex(fn) then atom.file.name(s".*${Pattern.quote(fn)}.*").newTagNode(tagName).store()( dstGraph )