From 36914dcb528db9e79fbb8658c20131e58038de83 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 18 Jul 2025 13:15:50 -0400 Subject: [PATCH] Add taint debug notes --- codeql-sqlite/TaintFlowDebugging.md | 65 +++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 codeql-sqlite/TaintFlowDebugging.md diff --git a/codeql-sqlite/TaintFlowDebugging.md b/codeql-sqlite/TaintFlowDebugging.md new file mode 100644 index 0000000..cc26d48 --- /dev/null +++ b/codeql-sqlite/TaintFlowDebugging.md @@ -0,0 +1,65 @@ +# Debugging with partial flow + +When there is a missing node on a path that you are trying to define there are 2 ways to figure out what the missing node is: + +1) Using the predicate `any()` in place of a sink. [QL documentation](https://codeql.github.com/docs/writing-codeql-queries/debugging-data-flow-queries-using-partial-flow/#partial-flow) explains the details of why this is not too performat, but it works fine when an application is small or you have a confident idea of what the missing piece is and really only need a small quick check to help out. + +2) [Partial flow](https://codeql.github.com/docs/writing-codeql-queries/debugging-data-flow-queries-using-partial-flow/#debugging-data-flow-queries-using-partial-flow) dataflow configuration is the preferred, more thorough solution for debugging dataflow. This configuration can allow you to see the partial pathes either forward or backward through the application and answer a question of "how far does the current path get?". This is extremely useful for cases where a node is missing in the dataflow graph, and an additional taint step is required to model the full problem. + + +The QL below demonstrates what partial debugging would look like, on [this Java SqlInjection sample](https://github.com/advanced-security/codeql-workshops-staging/tree/master/java/codeql-dataflow-sql-injection). + +``` +/** + * @name introduction workshop + * @description Sample SQL Injection problem + * @id test + * @kind path-problem + * @problem.severity warning + */ + +import java + +class ReadLineSource extends Source { + ReadLineSource() { this.getMethod().hasQualifiedName("java.io", "Console", "readLine") } +} + +abstract class Source extends MethodCall { } + +class Sink extends MethodCall { + Sink() { this.getMethod().hasQualifiedName("java.sql", "Statement", "executeUpdate") } +} + +import semmle.code.java.dataflow.TaintTracking + +module MyFlowConfiguration implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof Source } + + predicate isSink(DataFlow::Node sink) { + exists(Sink sink2 | sink.asExpr() = sink2.getArgument(_)) + //previous debug technique shown , not ideal though + //any() + } + + //this is the necessary flow step to close the gap + // predicate isAdditionalFlowStep(DataFlow::Node inNode, DataFlow::Node outNode) { + // exists(MethodCall mc | + // outNode.asExpr() = mc and + // mc.getMethod().hasQualifiedName("java.lang", "String", "format") and + // inNode.asExpr() = mc.getAnArgument() + // ) + // } +} + +int explorationLimit() { result = 100 } + +module MyFlow = DataFlow::Global; + +module MyPartialFlow = MyFlow::FlowExplorationFwd; + +import MyPartialFlow::PartialPathGraph + +from MyPartialFlow::PartialPathNode start, MyPartialFlow::PartialPathNode end +where MyPartialFlow::partialFlow(start, end, _) +select end, start, end, "Sql injection from $@", start, "here" +``` \ No newline at end of file