mirror of
https://github.com/hohn/codeql-lab.git
synced 2025-12-16 09:53:04 +01:00
major revision
This commit is contained in:
committed by
=Michael Hohn
parent
b770486392
commit
a43b5a3df8
@@ -1,9 +1,14 @@
|
|||||||
* Using sqlite to illustrate models-as-data
|
* Using sqlite to illustrate models-as-data
|
||||||
This description uses / recycles a codeql workshop.
|
|
||||||
** Build the codeql database
|
This section demonstrates the use of the models-as-data system by analyzing a
|
||||||
To get started, build the codeql database (adjust paths to your setup):
|
small Java application that uses the SQLite JDBC driver. The example is adapted
|
||||||
|
from a CodeQL workshop.
|
||||||
|
|
||||||
|
** Build the CodeQL Database
|
||||||
|
|
||||||
|
To get started, build the CodeQL database for the SQLite-backed Java sample. Adjust paths as needed.
|
||||||
|
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
# Build the db with source commit id.
|
|
||||||
SRCDIR=$(pwd)
|
SRCDIR=$(pwd)
|
||||||
DB=$SRCDIR/java-sqlite-$(cd $SRCDIR && git rev-parse --short HEAD).db
|
DB=$SRCDIR/java-sqlite-$(cd $SRCDIR && git rev-parse --short HEAD).db
|
||||||
|
|
||||||
@@ -11,22 +16,29 @@
|
|||||||
test -d "$DB" && rm -fR "$DB"
|
test -d "$DB" && rm -fR "$DB"
|
||||||
mkdir -p "$DB"
|
mkdir -p "$DB"
|
||||||
|
|
||||||
# Use the correct codeql
|
# Ensure the correct CodeQL version is in your PATH
|
||||||
export PATH="$(cd ../codeql && pwd):$PATH"
|
export PATH="$(cd ../codeql && pwd):$PATH"
|
||||||
codeql database create --language=java -s . -j 8 -v $DB --command='./build.sh'
|
codeql database create --language=java -s . -j 8 -v $DB --command='./build.sh'
|
||||||
|
|
||||||
# Check for AddUser in the db
|
# Check for presence of AddUser.java in the resulting database
|
||||||
unzip -v $DB/src.zip | grep AddUser
|
unzip -v $DB/src.zip | grep AddUser
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Then add this database directory to your VS Code =DATABASES= tab.
|
Then add this database directory to your VS Code =DATABASES= tab.
|
||||||
** Tests using a default query
|
|
||||||
You can run the stdlib query
|
** Tests Using a Default Query
|
||||||
[[../ql/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql]] but will get no results.
|
|
||||||
It does point at classes to inspect -- in particular, the source and sink
|
You can run the standard SQL injection query:
|
||||||
classes. Run [[./Illustrations.ql]]; from the command line or vs studio code.
|
|
||||||
Via cli:
|
[[../ql/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql]]
|
||||||
|
|
||||||
|
but it will return no results. However, it does help identify which classes are being analyzed as potential sources and sinks. Instead, run the diagnostic query:
|
||||||
|
|
||||||
|
[[./Illustrations.ql]]
|
||||||
|
|
||||||
|
You can run it from the CLI:
|
||||||
|
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
# run query
|
|
||||||
codeql query run \
|
codeql query run \
|
||||||
-v \
|
-v \
|
||||||
--database java-sqlite-e2e555c.db \
|
--database java-sqlite-e2e555c.db \
|
||||||
@@ -35,61 +47,57 @@
|
|||||||
--ram=14000 \
|
--ram=14000 \
|
||||||
Illustrations.ql
|
Illustrations.ql
|
||||||
|
|
||||||
# format results
|
|
||||||
codeql bqrs decode --format=text result.bqrs | sed -n '/^Result set: #select/,$p'
|
codeql bqrs decode --format=text result.bqrs | sed -n '/^Result set: #select/,$p'
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
This shows
|
|
||||||
|
The result will look like:
|
||||||
|
|
||||||
#+BEGIN_SRC text
|
#+BEGIN_SRC text
|
||||||
Result set: #select
|
Result set: #select
|
||||||
| ui | qsi |
|
| ui | qsi |
|
||||||
+------+-------+
|
+------+-------+
|
||||||
| args | query |
|
| args | query |
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
In the editor, these link to
|
|
||||||
1. =main(ARGS)= and
|
|
||||||
2. =conn.createStatement().executeUpdate(QUERY);=
|
|
||||||
The second is correct, but =System.console().readLine();= is not found.
|
|
||||||
Thus, =SqlTainted.ql= will not find anything.
|
|
||||||
|
|
||||||
** TODO supplement sources via the model editor
|
In the editor, these correspond to:
|
||||||
- [ ] We have no flow
|
1. =main(String[] args)= — source-like
|
||||||
+ check source, sink
|
2. =conn.createStatement().executeUpdate(query)= — sink
|
||||||
+ we have a sink
|
|
||||||
+ but ActiveThreatModelSource finds no source
|
|
||||||
- [ ] We can supplement in different ways
|
|
||||||
** supplement codeql: Write full manual query: already in workshop
|
|
||||||
** TODO supplement codeql: Add to FlowSource or a subclass
|
|
||||||
|
|
||||||
Note: this /one area/ that just has to be known. Browsing source will *not*
|
However, =System.console().readLine()= is not detected as a source. Therefore, =SqlTainted.ql= cannot find a complete flow.
|
||||||
help you.
|
|
||||||
|
|
||||||
CodeQL reading hint:
|
** Supplement Sources via the Model Editor
|
||||||
: class ActiveThreatModelSource extends DataFlow::Node
|
|
||||||
uses
|
- [ ] We observe no flow from source to sink
|
||||||
: this.(SourceNode).getThreatModel()
|
- A sink exists (=executeUpdate=)
|
||||||
So following the cast (SourceNode) may be useful:
|
- But no recognized source is found
|
||||||
|
- [ ] There are two ways to fix this:
|
||||||
|
1. Add a new source in =Customizations.qll=
|
||||||
|
2. Add a new source in the models-as-data YAML format
|
||||||
|
|
||||||
|
** Supplement CodeQL: Write a Full Manual Query
|
||||||
|
|
||||||
|
A manual dataflow query is already available:
|
||||||
|
|
||||||
|
[[./full-query.ql]]
|
||||||
|
|
||||||
|
This can trace the data manually even when standard configuration fails.
|
||||||
|
|
||||||
|
** Supplement CodeQL: Add to FlowSource or a Subclass
|
||||||
|
|
||||||
|
Sometimes, the only way to identify how to extend a source is to understand how CodeQL internally resolves source nodes.
|
||||||
|
|
||||||
|
Key class hierarchies:
|
||||||
#+BEGIN_SRC java
|
#+BEGIN_SRC java
|
||||||
/**
|
|
||||||
,* A data flow source.
|
|
||||||
,*/
|
|
||||||
abstract class SourceNode extends DataFlow::Node
|
abstract class SourceNode extends DataFlow::Node
|
||||||
#+END_SRC
|
|
||||||
Following the =abstract class= is promising:
|
|
||||||
#+BEGIN_SRC java
|
|
||||||
abstract class RemoteFlowSource extends SourceNode
|
abstract class RemoteFlowSource extends SourceNode
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
and others.
|
|
||||||
|
|
||||||
In
|
Follow usage in:
|
||||||
[[../ql/java/ql/lib/Customizations.qll]]
|
- [[../ql/java/ql/lib/Customizations.qll]]
|
||||||
notice the comments mentioning RemoteFlowSource.
|
- [[../ql/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql]]
|
||||||
Use imports from [[../ql/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql]]
|
|
||||||
but note that there are conflicts. you will use
|
|
||||||
: private import semmle.code.java.dataflow.FlowSources
|
|
||||||
Follow this to FlowSources, and find the mentioned RemoteFlowSource
|
|
||||||
: abstract class RemoteFlowSource extends SourceNode
|
|
||||||
|
|
||||||
Add the custom source. The modified [[../ql/java/ql/lib/Customizations.qll]] is
|
Then modify =Customizations.qll= by adding the custom source. The modified
|
||||||
|
[[../ql/java/ql/lib/Customizations.qll]] is
|
||||||
#+BEGIN_SRC java
|
#+BEGIN_SRC java
|
||||||
import java
|
import java
|
||||||
private import semmle.code.java.dataflow.FlowSources
|
private import semmle.code.java.dataflow.FlowSources
|
||||||
@@ -106,15 +114,15 @@
|
|||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Note that the predicate
|
This allows
|
||||||
|
|
||||||
#+BEGIN_SRC java
|
#+BEGIN_SRC java
|
||||||
module QueryInjectionFlowConfig implements DataFlow::ConfigSig {
|
predicate isSource(DataFlow::Node src) {
|
||||||
predicate isSource(DataFlow::Node src) { src instanceof ActiveThreatModelSource }
|
src instanceof ActiveThreatModelSource
|
||||||
...;
|
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
now also returns the readLine() result -- although we extended
|
|
||||||
RemoteFlowSource, not ActiveThreatModelSource
|
to include =readLine()= even though we extended =RemoteFlowSource=.
|
||||||
|
|
||||||
** TODO supplement codeql: Add to models-as-data
|
** TODO supplement codeql: Add to models-as-data
|
||||||
- schema in codeql: [[../ql/java/ql/lib/semmle/code/java/dataflow/internal/ExternalFlowExtensions.qll]]
|
- schema in codeql: [[../ql/java/ql/lib/semmle/code/java/dataflow/internal/ExternalFlowExtensions.qll]]
|
||||||
@@ -130,7 +138,7 @@
|
|||||||
18: - ["java.io", "Console", False, "readLine", "(String,Object[])", "", "Argument[1].ArrayElement", "Argument[this]", "taint", "df-generated"]
|
18: - ["java.io", "Console", False, "readLine", "(String,Object[])", "", "Argument[1].ArrayElement", "Argument[this]", "taint", "df-generated"]
|
||||||
19: - ["java.io", "Console", False, "readLine", "(String,Object[])", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
|
19: - ["java.io", "Console", False, "readLine", "(String,Object[])", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
note: this file is in the generated/ tree.
|
note: this file is in the generated/ tree. There are others.
|
||||||
|
|
||||||
The current readline modeling is in the =summaryModel= section; we need it
|
The current readline modeling is in the =summaryModel= section; we need it
|
||||||
in a =sourceModel=
|
in a =sourceModel=
|
||||||
@@ -219,3 +227,6 @@
|
|||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Now we can run [[../ql/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql]] again.
|
Now we can run [[../ql/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql]] again.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user