Michael Hohn
2023-08-16 14:17:31 -07:00
committed by =Michael Hohn
commit ddb5e545ff
16 changed files with 969 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*~
*.html

7
README.org Normal file
View File

@@ -0,0 +1,7 @@
* SQL injection example
This is an introductory codeql workshop for Java.
1. The problem and its source code are in [[./src]] along with a full description in
[[./src/README.org]].
2. The developed queries are in [[./solutions]] and their tests in [[./tests]]. The
derivation of those queries is described in [[./solutions/README.org]]

Binary file not shown.

10
java-demo.code-workspace Normal file
View File

@@ -0,0 +1,10 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"git.ignoreLimitWarning": true
}
}

366
solutions/README.html Normal file
View File

@@ -0,0 +1,366 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<!-- 2023-08-16 Wed 10:26 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>&lrm;</title>
<meta name="author" content="Michael Hohn" />
<meta name="generator" content="Org Mode" />
<style>
#content { max-width: 60em; margin: auto; }
.title { text-align: center;
margin-bottom: .2em; }
.subtitle { text-align: center;
font-size: medium;
font-weight: bold;
margin-top:0; }
.todo { font-family: monospace; color: red; }
.done { font-family: monospace; color: green; }
.priority { font-family: monospace; color: orange; }
.tag { background-color: #eee; font-family: monospace;
padding: 2px; font-size: 80%; font-weight: normal; }
.timestamp { color: #bebebe; }
.timestamp-kwd { color: #5f9ea0; }
.org-right { margin-left: auto; margin-right: 0px; text-align: right; }
.org-left { margin-left: 0px; margin-right: auto; text-align: left; }
.org-center { margin-left: auto; margin-right: auto; text-align: center; }
.underline { text-decoration: underline; }
#postamble p, #preamble p { font-size: 90%; margin: .2em; }
p.verse { margin-left: 3%; }
pre {
border: 1px solid #e6e6e6;
border-radius: 3px;
background-color: #f2f2f2;
padding: 8pt;
font-family: monospace;
overflow: auto;
margin: 1.2em;
}
pre.src {
position: relative;
overflow: auto;
}
pre.src:before {
display: none;
position: absolute;
top: -8px;
right: 12px;
padding: 3px;
color: #555;
background-color: #f2f2f299;
}
pre.src:hover:before { display: inline; margin-top: 14px;}
/* Languages per Org manual */
pre.src-asymptote:before { content: 'Asymptote'; }
pre.src-awk:before { content: 'Awk'; }
pre.src-authinfo::before { content: 'Authinfo'; }
pre.src-C:before { content: 'C'; }
/* pre.src-C++ doesn't work in CSS */
pre.src-clojure:before { content: 'Clojure'; }
pre.src-css:before { content: 'CSS'; }
pre.src-D:before { content: 'D'; }
pre.src-ditaa:before { content: 'ditaa'; }
pre.src-dot:before { content: 'Graphviz'; }
pre.src-calc:before { content: 'Emacs Calc'; }
pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
pre.src-fortran:before { content: 'Fortran'; }
pre.src-gnuplot:before { content: 'gnuplot'; }
pre.src-haskell:before { content: 'Haskell'; }
pre.src-hledger:before { content: 'hledger'; }
pre.src-java:before { content: 'Java'; }
pre.src-js:before { content: 'Javascript'; }
pre.src-latex:before { content: 'LaTeX'; }
pre.src-ledger:before { content: 'Ledger'; }
pre.src-lisp:before { content: 'Lisp'; }
pre.src-lilypond:before { content: 'Lilypond'; }
pre.src-lua:before { content: 'Lua'; }
pre.src-matlab:before { content: 'MATLAB'; }
pre.src-mscgen:before { content: 'Mscgen'; }
pre.src-ocaml:before { content: 'Objective Caml'; }
pre.src-octave:before { content: 'Octave'; }
pre.src-org:before { content: 'Org mode'; }
pre.src-oz:before { content: 'OZ'; }
pre.src-plantuml:before { content: 'Plantuml'; }
pre.src-processing:before { content: 'Processing.js'; }
pre.src-python:before { content: 'Python'; }
pre.src-R:before { content: 'R'; }
pre.src-ruby:before { content: 'Ruby'; }
pre.src-sass:before { content: 'Sass'; }
pre.src-scheme:before { content: 'Scheme'; }
pre.src-screen:before { content: 'Gnu Screen'; }
pre.src-sed:before { content: 'Sed'; }
pre.src-sh:before { content: 'shell'; }
pre.src-sql:before { content: 'SQL'; }
pre.src-sqlite:before { content: 'SQLite'; }
/* additional languages in org.el's org-babel-load-languages alist */
pre.src-forth:before { content: 'Forth'; }
pre.src-io:before { content: 'IO'; }
pre.src-J:before { content: 'J'; }
pre.src-makefile:before { content: 'Makefile'; }
pre.src-maxima:before { content: 'Maxima'; }
pre.src-perl:before { content: 'Perl'; }
pre.src-picolisp:before { content: 'Pico Lisp'; }
pre.src-scala:before { content: 'Scala'; }
pre.src-shell:before { content: 'Shell Script'; }
pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
/* additional language identifiers per "defun org-babel-execute"
in ob-*.el */
pre.src-cpp:before { content: 'C++'; }
pre.src-abc:before { content: 'ABC'; }
pre.src-coq:before { content: 'Coq'; }
pre.src-groovy:before { content: 'Groovy'; }
/* additional language identifiers from org-babel-shell-names in
ob-shell.el: ob-shell is the only babel language using a lambda to put
the execution function name together. */
pre.src-bash:before { content: 'bash'; }
pre.src-csh:before { content: 'csh'; }
pre.src-ash:before { content: 'ash'; }
pre.src-dash:before { content: 'dash'; }
pre.src-ksh:before { content: 'ksh'; }
pre.src-mksh:before { content: 'mksh'; }
pre.src-posh:before { content: 'posh'; }
/* Additional Emacs modes also supported by the LaTeX listings package */
pre.src-ada:before { content: 'Ada'; }
pre.src-asm:before { content: 'Assembler'; }
pre.src-caml:before { content: 'Caml'; }
pre.src-delphi:before { content: 'Delphi'; }
pre.src-html:before { content: 'HTML'; }
pre.src-idl:before { content: 'IDL'; }
pre.src-mercury:before { content: 'Mercury'; }
pre.src-metapost:before { content: 'MetaPost'; }
pre.src-modula-2:before { content: 'Modula-2'; }
pre.src-pascal:before { content: 'Pascal'; }
pre.src-ps:before { content: 'PostScript'; }
pre.src-prolog:before { content: 'Prolog'; }
pre.src-simula:before { content: 'Simula'; }
pre.src-tcl:before { content: 'tcl'; }
pre.src-tex:before { content: 'TeX'; }
pre.src-plain-tex:before { content: 'Plain TeX'; }
pre.src-verilog:before { content: 'Verilog'; }
pre.src-vhdl:before { content: 'VHDL'; }
pre.src-xml:before { content: 'XML'; }
pre.src-nxml:before { content: 'XML'; }
/* add a generic configuration mode; LaTeX export needs an additional
(add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
pre.src-conf:before { content: 'Configuration File'; }
table { border-collapse:collapse; }
caption.t-above { caption-side: top; }
caption.t-bottom { caption-side: bottom; }
td, th { vertical-align:top; }
th.org-right { text-align: center; }
th.org-left { text-align: center; }
th.org-center { text-align: center; }
td.org-right { text-align: right; }
td.org-left { text-align: left; }
td.org-center { text-align: center; }
dt { font-weight: bold; }
.footpara { display: inline; }
.footdef { margin-bottom: 1em; }
.figure { padding: 1em; }
.figure p { text-align: center; }
.equation-container {
display: table;
text-align: center;
width: 100%;
}
.equation {
vertical-align: middle;
}
.equation-label {
display: table-cell;
text-align: right;
vertical-align: middle;
}
.inlinetask {
padding: 10px;
border: 2px solid gray;
margin: 10px;
background: #ffffcc;
}
#org-div-home-and-up
{ text-align: right; font-size: 70%; white-space: nowrap; }
textarea { overflow-x: auto; }
.linenr { font-size: smaller }
.code-highlighted { background-color: #ffff00; }
.org-info-js_info-navigation { border-style: none; }
#org-info-js_console-label
{ font-size: 10px; font-weight: bold; white-space: nowrap; }
.org-info-js_search-highlight
{ background-color: #ffff00; color: #000000; font-weight: bold; }
.org-svg { }
</style>
</head>
<body>
<div id="content" class="content">
<div id="table-of-contents" role="doc-toc">
<h2>Table of Contents</h2>
<div id="text-table-of-contents" role="doc-toc">
<ul>
<li><a href="#org791c6f8">1. Develop the query bottom-up</a></li>
<li><a href="#orga2253a0">2. Optional: sarif file review of the results</a></li>
</ul>
</div>
</div>
<div id="outline-container-org791c6f8" class="outline-2">
<h2 id="org791c6f8"><span class="section-number-2">1.</span> Develop the query bottom-up</h2>
<div class="outline-text-2" id="text-1">
<ol class="org-ol">
<li><p>
Identify the <i>source</i> part of the
</p>
<pre class="example">
System.console().readLine();
</pre>
<p>
expression, the <code>buf</code> argument.
Start from a <code>from..where..select</code>, then convert to a predicate.
</p></li>
<li><p>
Identify the <i>sink</i> part of the
</p>
<pre class="example">
conn.createStatement().executeUpdate(query);
</pre>
<p>
expression, the <code>query</code> argument. Again start from <code>from..where..select</code>,
then convert to a predicate.
</p></li>
<li><p>
Fill in the <i>taintflow configuration</i> boilerplate
</p>
<div class="org-src-container">
<pre class="src src-java"><span style="color: #a020f0;">class</span> <span style="color: #228b22;">SqliFlowConfig</span> <span style="color: #a020f0;">extends</span> <span style="color: #228b22;">TaintTracking</span>::Configuration {
SqliFlowConfig() { <span style="color: #a020f0;">this</span> = <span style="color: #8b2252;">"SqliFlow"</span> }
override <span style="color: #228b22;">predicate</span> <span style="color: #0000ff;">isSource</span>(DataFlow::Node node) {
none()
}
override <span style="color: #228b22;">predicate</span> <span style="color: #0000ff;">isSink</span>(DataFlow::Node node) {
none()
}
}
</pre>
</div></li>
</ol>
<p>
The final query (without <code>isAdditionalTaintStep</code>) is
</p>
<div class="org-src-container">
<pre class="src src-java"><span style="color: #8b2252;">/**</span>
<span style="color: #8b2252;"> * </span><span style="color: #008b8b;">@name</span><span style="color: #8b2252;"> SQLI Vulnerability</span>
<span style="color: #8b2252;"> * </span><span style="color: #008b8b;">@description</span><span style="color: #8b2252;"> Using untrusted strings in a sql query allows sql injection attacks.</span>
<span style="color: #8b2252;"> * </span><span style="color: #008b8b;">@kind</span><span style="color: #8b2252;"> path-problem</span>
<span style="color: #8b2252;"> * </span><span style="color: #008b8b;">@id</span><span style="color: #8b2252;"> java/SQLIVulnerable</span>
<span style="color: #8b2252;"> * </span><span style="color: #008b8b;">@problem</span><span style="color: #8b2252;">.severity warning</span>
<span style="color: #8b2252;"> */</span>
<span style="color: #a020f0;">import</span> <span style="color: #228b22;">java</span>
<span style="color: #a020f0;">import</span> <span style="color: #008b8b;">semmle</span>.<span style="color: #008b8b;">code</span>.<span style="color: #008b8b;">java</span>.<span style="color: #008b8b;">dataflow</span>.<span style="color: #228b22;">TaintTracking</span>
<span style="color: #a020f0;">import</span> <span style="color: #228b22;">DataFlow</span>::PathGraph
<span style="color: #a020f0;">class</span> SqliFlowConfig <span style="color: #a020f0;">extends</span> <span style="color: #228b22;">TaintTracking</span>::Configuration {
SqliFlowConfig() { <span style="color: #a020f0;">this</span> = <span style="color: #8b2252;">"SqliFlow"</span> }
override <span style="color: #228b22;">predicate</span> <span style="color: #0000ff;">isSource</span>(DataFlow::Node source) {
<span style="color: #b22222;">// </span><span style="color: #b22222;">System.console().readLine();</span>
exists(<span style="color: #228b22;">Call</span> <span style="color: #0000ff;">read</span> |
read.getCallee().getName() = <span style="color: #8b2252;">"readLine"</span> and
read = source.asExpr()
)
}
override <span style="color: #228b22;">predicate</span> <span style="color: #0000ff;">isSink</span>(DataFlow::Node sink) {
<span style="color: #b22222;">// </span><span style="color: #b22222;">conn.createStatement().executeUpdate(query);</span>
exists(<span style="color: #228b22;">Call</span> <span style="color: #0000ff;">exec</span> |
exec.getCallee().getName() = <span style="color: #8b2252;">"executeUpdate"</span> and
exec.getArgument(0) = sink.asExpr()
)
}
}
from <span style="color: #228b22;">SqliFlowConfig</span> <span style="color: #a0522d;">conf</span>, <span style="color: #a0522d;">DataFlow</span>::PathNode source, <span style="color: #0000ff;">DataFlow</span>::PathNode sink
where conf.hasFlowPath(source, sink)
select sink, source, sink, <span style="color: #8b2252;">"Possible SQL injection"</span>
</pre>
</div>
</div>
</div>
<div id="outline-container-orga2253a0" class="outline-2">
<h2 id="orga2253a0"><span class="section-number-2">2.</span> Optional: sarif file review of the results</h2>
<div class="outline-text-2" id="text-2">
<p>
Query results are available in several output formats using the cli. The
following produces the sarif format, a json-based result description.
</p>
<div class="org-src-container">
<pre class="src src-sh"><span style="color: #b22222;"># </span><span style="color: #b22222;">The setup information from before</span>
<span style="color: #483d8b;">export</span> <span style="color: #a0522d;">PATH</span>=$<span style="color: #a0522d;">HOME</span>/local/vmsync/codeql250:<span style="color: #8b2252;">"$PATH"</span>
<span style="color: #a0522d;">SRCDIR</span>=$<span style="color: #a0522d;">HOME</span>/local/codeql-training-material.java-sqli/java/codeql-dataflow-sql-injection
<span style="color: #a0522d;">DB</span>=$<span style="color: #a0522d;">SRCDIR</span>/java-sqli-$(<span style="color: #ff00ff;">cd $SRCDIR &amp;&amp; git rev-parse --short HEAD</span>)
<span style="color: #b22222;"># </span><span style="color: #b22222;">Check paths</span>
<span style="color: #483d8b;">echo</span> $<span style="color: #a0522d;">DB</span>
<span style="color: #483d8b;">echo</span> $<span style="color: #a0522d;">SRCDIR</span>
<span style="color: #b22222;"># </span><span style="color: #b22222;">To see the help</span>
codeql database analyze -h
<span style="color: #b22222;"># </span><span style="color: #b22222;">Run a query</span>
codeql database analyze <span style="color: #8b2252;">\</span>
-v <span style="color: #8b2252;">\</span>
--ram=14000 <span style="color: #8b2252;">\</span>
-j12 <span style="color: #8b2252;">\</span>
--rerun <span style="color: #8b2252;">\</span>
--search-path ~/local/vmsync/ql <span style="color: #8b2252;">\</span>
--format=sarif-latest <span style="color: #8b2252;">\</span>
--output java-sqli.sarif <span style="color: #8b2252;">\</span>
-- <span style="color: #8b2252;">\</span>
$<span style="color: #a0522d;">DB</span> <span style="color: #8b2252;">\</span>
$<span style="color: #a0522d;">SRCDIR</span>/SqlInjection.ql
<span style="color: #b22222;"># </span><span style="color: #b22222;">Examine the file in an editor</span>
edit java-sqli.sarif
</pre>
</div>
<p>
An example of using the sarif data is in the the jq script <a href="./sarif-summary.jq">./sarif-summary.jq</a>.
When run against the sarif input via
</p>
<div class="org-src-container">
<pre class="src src-sh">jq --raw-output --join-output -f sarif-summary.jq &lt; java-sqli.sarif &gt; java-sqli.txt
</pre>
</div>
<p>
it produces output in a form close to that of compiler error messages:
</p>
<div class="org-src-container">
<pre class="src src-text">query-id: message line
Path
...
Path
...
</pre>
</div>
</div>
</div>
</div>
<div id="postamble" class="status">
<p class="author">Author: Michael Hohn</p>
<p class="date">Created: 2023-08-16 Wed 10:26</p>
<p class="validation"><a href="https://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
</body>
</html>

119
solutions/README.org Normal file
View File

@@ -0,0 +1,119 @@
* 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
[[file:~/local/codeql-workshop-dataflow-c/exercises/Exercise16.ql::module InputTypesToTypeValidation = DataFlow::Make<InputTypesToTypeValidationConfig>;]]
or
[[file:~/local/codeql-workshop-dataflow-c/solutions/Exercise16.ql::module InputTypesToTypeValidation = DataFlow::Make<InputTypesToTypeValidationConfig>;]]
#+BEGIN_SRC java
class SqliFlowConfig extends TaintTracking::Configuration {
SqliFlowConfig() { this = "SqliFlow" }
override predicate isSource(DataFlow::Node node) {
none()
}
override predicate isSink(DataFlow::Node node) {
none()
}
}
#+END_SRC
The final query (without =isAdditionalTaintStep=) is
#+BEGIN_SRC java
/**
,* @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"
#+END_SRC
* 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.
#+BEGIN_SRC sh
# 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
#+END_SRC
An example of using the sarif data is in the the jq script [[./sarif-summary.jq]].
When run against the sarif input via
#+BEGIN_SRC sh
jq --raw-output --join-output -f sarif-summary.jq < java-sqli.sarif > java-sqli.txt
#+END_SRC
it produces output in a form close to that of compiler error messages:
#+BEGIN_SRC text
query-id: message line
Path
...
Path
...
#+END_SRC

6
solutions/qlpack.yml Normal file
View File

@@ -0,0 +1,6 @@
---
library: false
name: codeql-workshop/java-sql-injection
version: 0.0.1
dependencies:
codeql/java-all: "*"

45
src/AddUser.java Normal file
View File

@@ -0,0 +1,45 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class AddUser {
public static Connection connect() {
Connection conn = null;
try {
String url = "jdbc:sqlite:users.sqlite";
conn = DriverManager.getConnection(url);
System.out.println("Connected...");
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return conn;
}
static String get_user_info() {
System.out.println("Enter name:");
return System.console().readLine();
}
static void write_info(int id, String info) {
try (Connection conn = connect()) {
String query = String.format("INSERT INTO users VALUES (%d, '%s')", id, info);
conn.createStatement().executeUpdate(query);
System.err.printf("Sent: %s", query);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
static int get_new_id() {
return (int)(Math.random()*100000);
}
public static void main(String[] args) {
String info;
int id;
info = get_user_info();
id = get_new_id();
write_info(id, info);
}
}

26
src/Makefile Normal file
View File

@@ -0,0 +1,26 @@
add-user: add-user.c
clang -Wall add-user.c -lsqlite3 -o add-user
clean:
rm -f README.html add-user cpp-sqli.sarif cpp-sqli.txt users.log
rm -f users.sqlite *.bak *~ cpp-sqli-demo.zip
ZIPLIST := \
Makefile \
README.org \
SqlInjection.ql \
add-user.c \
add-user.sh \
admin \
build.sh \
codeql-dataflow-sql-injection.md \
codeql-overview-for-workshop.pdf \
cpp-sqli.code-workspace \
dataflow-cropped.pdf \
qlpack.yml \
sarif-summary.jq \
session.ql
demo-zip:
rm -f cpp-sqli-demo.zip
zip cpp-sqli-demo.zip $(ZIPLIST)

218
src/README.org Normal file
View File

@@ -0,0 +1,218 @@
* SQL injection example
** Setup and sample run
The jdbc connector at https://github.com/xerial/sqlite-jdbc, from [[https://github.com/xerial/sqlite-jdbc/releases/download/3.36.0.1/sqlite-jdbc-3.36.0.1.jar][here]] is
included in the git repository.
#+BEGIN_SRC sh
# Use a simple headline prompt
PS1='
\033[32m---- SQL injection demo ----\[\033[33m\033[0m\]
$?:$ '
# Build
./build.sh
# Prepare db
./admin -r
./admin -c
./admin -s
# Add regular user interactively
./add-user 2>> users.log
First User
# Check
./admin -s
# Add Johnny Droptable
./add-user 2>> users.log
Johnny'); DROP TABLE users; --
# And the problem:
./admin -s
# Check the log
tail users.log
#+END_SRC
** Identify the problem
=./add-user= is reading from =STDIN=, and writing to a database; looking at the code in
[[./AddUser.java]] leads to
: System.console().readLine();
for the read and
: conn.createStatement().executeUpdate(query);
for the write.
This problem is thus a dataflow problem; in codeql terminology we have
- a /source/ at the =System.console().readLine();=
- a /sink/ at the =conn.createStatement().executeUpdate(query);=
We write codeql to identify these two, and then connect them via
- a /dataflow configuration/ -- for this problem, the more general /taintflow
configuration/.
** Build codeql database
To get started, build the codeql database (adjust paths to your setup):
#+BEGIN_SRC sh
# Build the db with source commit id.
export PATH=$HOME/local/vmsync/codeql250:"$PATH"
SRCDIR=$(pwd)
DB=$SRCDIR/java-sqli-$(cd $SRCDIR && git rev-parse --short HEAD)
echo $DB
test -d "$DB" && rm -fR "$DB"
mkdir -p "$DB"
cd $SRCDIR && codeql database create --language=java -s . -j 8 -v $DB --command='./build.sh'
# Check for AddUser in the db
unzip -v $DB/src.zip | grep AddUser
#+END_SRC
Then add this database directory to your VS Code =DATABASES= tab.
** Build codeql database in steps
For larger projects, using a single command to build everything is costly when
any part of the build fails.
To build a database in steps, use the following sequence, adjusting paths to
your setup:
#+BEGIN_SRC sh
# Build the db with source commit id.
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
# Prepare db directory
test -d "$DB" && rm -fR "$DB"
mkdir -p "$DB"
# Run the build
cd $SRCDIR
codeql database init --language=java -s . -v $DB
# Repeat trace-command as needed to cover all targets
codeql database trace-command -v $DB -- make
codeql database finalize -j4 $DB
#+END_SRC
Then add this database directory to your VS Code =DATABASES= tab.
** 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
#+BEGIN_SRC java
class SqliFlowConfig extends TaintTracking::Configuration {
SqliFlowConfig() { this = "SqliFlow" }
override predicate isSource(DataFlow::Node node) {
none()
}
override predicate isSink(DataFlow::Node node) {
none()
}
}
#+END_SRC
The final query (without =isAdditionalTaintStep=) is
#+BEGIN_SRC java
/**
,* @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"
#+END_SRC
** 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.
#+BEGIN_SRC sh
# 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
#+END_SRC
An example of using the sarif data is in the the jq script [[./sarif-summary.jq]].
When run against the sarif input via
#+BEGIN_SRC sh
jq --raw-output --join-output -f sarif-summary.jq < java-sqli.sarif > java-sqli.txt
#+END_SRC
it produces output in a form close to that of compiler error messages:
#+BEGIN_SRC text
query-id: message line
Path
...
Path
...
#+END_SRC

44
src/SqlInjection.ql Normal file
View File

@@ -0,0 +1,44 @@
/**
* @name SQLI Vulnerability
* @description Using untrusted strings in a sql query allows sql injection attacks.
* @kind path-problem
* @id cpp/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 isSanitizer(DataFlow::Node sanitizer) { none() }
override predicate isAdditionalTaintStep(DataFlow::Node into, DataFlow::Node out) {
// Extra taint step
// String.format("INSERT INTO users VALUES (%d, '%s')", id, info);
// Not needed here, but may be needed for larger libraries.
none()
}
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"

3
src/add-user Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
java -cp ".:sqlite-jdbc-3.36.0.1.jar" AddUser $@

60
src/admin Executable file
View File

@@ -0,0 +1,60 @@
#!/bin/bash
set -e
script=$(basename "$0")
GREEN='\033[0;32m'
MAGENTA='\033[0;95m'
NC='\033[0m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
help() {
echo -e "Usage: ./${script} [options]" \
"\n${YELLOW}Options: ${NC}" \
"\n\t -h ${GREEN}Show Help ${NC}" \
"\n\t -c ${MAGENTA}Creates a users table ${NC}" \
"\n\t -s ${MAGENTA}Shows all records in the users table ${NC}" \
"\n\t -r ${RED}Removes users table ${NC}"
}
remove-db () {
rm users.sqlite
}
create-db () {
echo '
CREATE TABLE users (
user_id INTEGER not null,
name TEXT NOT NULL
);
' | sqlite3 users.sqlite
}
show-db () {
echo '
SELECT * FROM users;
' | sqlite3 users.sqlite
}
if [ $# == 0 ]; then
help
exit 0
fi
while getopts "h?csr" option
do
case "${option}"
in
h|\?)
help
exit 0
;;
c) create-db
;;
s) show-db
;;
r) remove-db
;;
esac
done

3
src/build.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
javac AddUser.java

60
src/sarif-summary.jq Normal file
View File

@@ -0,0 +1,60 @@
# -*- sh -*-
.runs | .[] | .results | .[] |
( (.ruleId, ": ",
(.message.text | split("\n") | ( .[0], " [", length-1 , " more]")),
"\n")
,
(if (.codeFlows != null) then
(.codeFlows | .[] |
(" Path\n"
,
( .threadFlows | .[] | .locations | .[] | .location | " "
,
( .physicalLocation | ( .artifactLocation.uri, ":", .region.startLine, ":"))
,
(.message.text, " ")
,
"\n"
)))
else
(.locations | .[] |
( " "
,
(.physicalLocation | ( .artifactLocation.uri, ":", .region.startLine, ":"))
))
,
# .message.text,
"\n"
end)
) | tostring
# This script extracts the following parts of the sarif output:
#
# # problem
# "runs" : [ {
# "results" : [ {
# "ruleId" : "cpp/UncheckedErrorCode",
# # path problem
# "runs" : [ {
# "tool" : {
# "driver" : {
# "rules" : [ {
# "properties" : {
# "kind" : "path-problem",
# "runs" : [ {
# "results" : [ {
# "ruleId" : "cpp/DangerousArithmetic",
# "ruleIndex" : 6,
# "message" : {
# "text" : "Potential overflow (conversion: int -> unsigned int)\nPotential overflow (con
# "runs" : [ {
# "results" : [ {
# "codeFlows" : [ {
# "threadFlows" : [ {
# "locations" : [ {
# "location" : {
# "message" : {
# "text" : "buff"

Binary file not shown.