Files
codeql-workshop-sql-injecti…/solutions

Develop the query bottom-up

  1. Identify the source part of the

    System.console().readLine();
    

    expression, the buf argument. Start from a from..where..select, then convert to a predicate.

  2. Identify the sink part of the

    conn.createStatement().executeUpdate(query);
    

    expression, the query argument. Again start from from..where..select, then convert to a predicate.

  3. Fill in the taintflow configuration boilerplate XX: update for new module approach; See ~/local/codeql-workshop-dataflow-c/exercises/Exercise16.ql ~/local/codeql-workshop-dataflow-c/exercises/Exercise16.ql::module InputTypesToTypeValidation = DataFlow::Make<InputTypesToTypeValidationConfig>; or ~/local/codeql-workshop-dataflow-c/solutions/Exercise16.ql::module InputTypesToTypeValidation = DataFlow::Make<InputTypesToTypeValidationConfig>;

      class SqliFlowConfig extends TaintTracking::Configuration {
          SqliFlowConfig() { this = "SqliFlow" }
    
          override predicate isSource(DataFlow::Node node) {
              none()
                  }
    
          override predicate isSink(DataFlow::Node node) {
              none()
                  }
      }

The final query (without isAdditionalTaintStep) is

  /**
   ,* @name SQLI Vulnerability
   ,* @description Using untrusted strings in a sql query allows sql injection attacks.
   ,* @kind path-problem
   ,* @id java/SQLIVulnerable
   ,* @problem.severity warning
   ,*/

  import java
  import semmle.code.java.dataflow.TaintTracking
  import DataFlow::PathGraph

  class SqliFlowConfig extends TaintTracking::Configuration {
      SqliFlowConfig() { this = "SqliFlow" }

      override predicate isSource(DataFlow::Node source) {
         // System.console().readLine();
         exists(Call read |
             read.getCallee().getName() = "readLine" and
             read = source.asExpr()
         )
     }

      override predicate isSink(DataFlow::Node sink) {
         // conn.createStatement().executeUpdate(query);
         exists(Call exec |
             exec.getCallee().getName() = "executeUpdate" and
             exec.getArgument(0) = sink.asExpr()
         )
     }
  }

  from SqliFlowConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink
  where conf.hasFlowPath(source, sink)
  select sink, source, sink, "Possible SQL injection"

Optional: sarif file review of the results

Query results are available in several output formats using the cli. The following produces the sarif format, a json-based result description.

  # The setup information from before
  export PATH=$HOME/local/vmsync/codeql250:"$PATH"
  SRCDIR=$HOME/local/codeql-training-material.java-sqli/java/codeql-dataflow-sql-injection
  DB=$SRCDIR/java-sqli-$(cd $SRCDIR && git rev-parse --short HEAD)

  # Check paths
  echo $DB
  echo $SRCDIR

  # To see the help
  codeql database analyze -h

  # Run a query
  codeql database analyze                         \
         -v                                       \
         --ram=14000                              \
         -j12                                     \
         --rerun                                  \
         --search-path ~/local/vmsync/ql          \
         --format=sarif-latest                    \
         --output java-sqli.sarif                 \
         --                                       \
         $DB                                      \
         $SRCDIR/SqlInjection.ql

  # Examine the file in an editor
  edit java-sqli.sarif

An example of using the sarif data is in the the jq script ./sarif-summary.jq. When run against the sarif input via

  jq --raw-output --join-output  -f sarif-summary.jq < java-sqli.sarif > java-sqli.txt

it produces output in a form close to that of compiler error messages:

  query-id: message line 
      Path
         ...
      Path
         ...