Files
codeql-workshop-sql-injecti…/session
2023-08-16 15:04:33 -07:00
..
2023-08-16 15:04:33 -07:00
2023-08-16 15:04:33 -07:00

SQL injection example

This directory contains the codeql session snapshots as well as the full query ./full-query-old-style.ql

The rest of this README contains a description of the query's development.

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

      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) Review of the results via SARIF file

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
  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
         ...