mirror of
https://github.com/hohn/codeql-javascript-multiflow.git
synced 2025-12-15 19:53:03 +01:00
Minimal Javascript/SQLite3 sample
This commit is contained in:
11
LICENSE
Normal file
11
LICENSE
Normal file
@@ -0,0 +1,11 @@
|
||||
Copyright (c) 2023 Github, Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
265
README.org
Normal file
265
README.org
Normal file
@@ -0,0 +1,265 @@
|
||||
* SQL injection example
|
||||
The primary purpose of this material is to serve as an introduction to CodeQL
|
||||
for Python.
|
||||
The section [[*Reading Order][Reading Order]] describes the basic CodeQL queries to go through.
|
||||
|
||||
The Python code is intentionally trivial and mirrors the structure of production
|
||||
code. Further, the steps needed for [[*CodeQL setup][CodeQL setup]] in production CI/CD pipelines
|
||||
have identical structure to the one shown here.
|
||||
|
||||
Thus, it is expedient to illustrate intermediate and advanced topics here as
|
||||
well. The section [[*Additional Topics][Additional Topics]] does this by illustrating descriptions from
|
||||
the CodeQL documentation using the Python code in this repository.
|
||||
Thus, the [[*Additional Topics][Additional Topics]] serve as additional examples to parts of the
|
||||
documentation.
|
||||
These additional topics should be read in the order of appearance.
|
||||
|
||||
For system administration and devops, the section [[*CodeQL setup][CodeQL setup]] provides a
|
||||
rudimentary guide.
|
||||
|
||||
** Node setup and Running Sequence
|
||||
#+BEGIN_SRC sh
|
||||
npm i sqlite3
|
||||
|
||||
node add-user.js
|
||||
|
||||
./admin -c
|
||||
./admin -s
|
||||
|
||||
echo frank | node add-user.js
|
||||
|
||||
./admin -s
|
||||
|
||||
echo 'Johnny"); DROP TABLE users; --' | node add-user.js
|
||||
|
||||
./admin -s
|
||||
|
||||
#+END_SRC
|
||||
|
||||
** CodeQL setup
|
||||
It's best to have a full development setup for CodeQL on your laptop/desktop.
|
||||
This requires you to
|
||||
1. download VS Code
|
||||
|
||||
2. install the CodeQL extension. Instructions on how to do that found here:
|
||||
https://codeql.github.com/docs/codeql-for-visual-studio-code/setting-up-codeql-in-visual-studio-code/
|
||||
|
||||
3. install a CodeQL binary (containing CodeQL CLI) for whichever platform
|
||||
you are on and unpack that
|
||||
|
||||
The binary for 2.13.5 is found here:
|
||||
https://github.com/github/codeql-cli-binaries/releases/tag/v2.13.5
|
||||
|
||||
See script below.
|
||||
|
||||
4. (recommended for browsing) Install the codeql standard library matching the
|
||||
binary version. This is not needed to write or run queries anymore, but the
|
||||
library has many examples and searching it is much easier after extracting
|
||||
this archive:
|
||||
https://github.com/github/codeql/releases/tag/codeql-cli%2Fv2.13.5
|
||||
|
||||
See script below.
|
||||
|
||||
5. clone this repository.
|
||||
#+BEGIN_SRC sh :session shared :results output
|
||||
mkdir ~/local && cd ~/local && \
|
||||
git clone https://github.com/hohn/codeql-dataflow-sql-injection-python.git
|
||||
#+END_SRC
|
||||
|
||||
6. open the workspace directory in VS Code. This should just be
|
||||
#+BEGIN_SRC sh :session shared :results output
|
||||
cd ~/local/codeql-dataflow-sql-injection-python
|
||||
code python-sqli.code-workspace
|
||||
#+END_SRC
|
||||
|
||||
7. add the downloaded CodeQL CLI to the VS Code's search path. Find the CodeQL
|
||||
extension settings, then paste the full path to the CodeQL CLI into the
|
||||
: Code QL > Cli: Executable Path
|
||||
field.
|
||||
|
||||
8. install the pack dependencies for the CLI. In a shell, use
|
||||
#+BEGIN_SRC sh
|
||||
cd ~/local/codeql-dataflow-sql-injection-python
|
||||
codeql pack install
|
||||
#+END_SRC
|
||||
|
||||
9. install the pack dependencies VS Code. Do this via
|
||||
: command palette
|
||||
and then select all listed by
|
||||
: CodeQL: Install Pack Dependencies
|
||||
|
||||
It will generate a =codeql-pack.lock.yml= file.
|
||||
|
||||
10. use the following to build a CodeQL database.
|
||||
#+BEGIN_SRC sh
|
||||
#* Build the db with source commit id.
|
||||
codeql --version
|
||||
: CodeQL command-line toolchain release 2.13.5.
|
||||
|
||||
cd ~/local/codeql-dataflow-sql-injection-python
|
||||
|
||||
DB=./python-sqli-db-$(git rev-parse --short HEAD)
|
||||
|
||||
echo $DB
|
||||
test -d "$DB" && rm -fR "$DB"
|
||||
mkdir -p "$DB"
|
||||
|
||||
codeql database create --language=python -s . -j 8 -v $DB
|
||||
#+END_SRC
|
||||
|
||||
11. add the database to the editor. To do this there is a widget on the left
|
||||
side of editor that looks like QL and after selecting that, there is a
|
||||
databases panel. There are options to select from archive or folder. Select
|
||||
the "from folder" option and add the "database" folders you created above.
|
||||
|
||||
12. open the query =trivial.ql= and run it via
|
||||
: right click > run query on selected database
|
||||
|
||||
There are several ways to install the CodeQL binaries and libraries. Here is a
|
||||
shell script to do it one way
|
||||
|
||||
#+BEGIN_SRC sh :session shared :results output
|
||||
# grab -- retrieve and extract codeql cli and library
|
||||
# Usage: grab version platform prefix
|
||||
grab() {
|
||||
version=$1; shift
|
||||
platform=$1; shift
|
||||
prefix=$1; shift
|
||||
mkdir -p $prefix/codeql-$version &&
|
||||
cd $prefix/codeql-$version || return
|
||||
|
||||
# Get cli
|
||||
wget "https://github.com/github/codeql-cli-binaries/releases/download/$version/codeql-$platform.zip"
|
||||
# Get lib
|
||||
wget "https://github.com/github/codeql/archive/refs/tags/codeql-cli/$version.zip"
|
||||
# Fix attributes
|
||||
if [ `uname` = Darwin ] ; then
|
||||
xattr -c *.zip
|
||||
fi
|
||||
# Extract
|
||||
unzip -q codeql-$platform.zip
|
||||
unzip -q $version.zip
|
||||
# Rename library directory for VS Code
|
||||
mv codeql-codeql-cli-$version/ ql
|
||||
# remove archives?
|
||||
# rm codeql-$platform.zip
|
||||
# rm $version.zip
|
||||
}
|
||||
|
||||
# Try:
|
||||
grab v2.13.5 osx64 $HOME/local/xefm
|
||||
|
||||
grab v2.13.5 linux64 $HOME/local/xefm
|
||||
|
||||
ls $HOME/local/xefm/codeql-v2.13.5/
|
||||
: codeql/ codeql-osx64.zip ql/ v2.13.5.zip
|
||||
#+END_SRC
|
||||
|
||||
** Sample Application Setup and Run
|
||||
Execute the following in a bourne-style shell, one block at a time to see
|
||||
results. This requires a working Python installation and a POSIX shell.
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
# Prepare db
|
||||
./admin -r
|
||||
./admin -c
|
||||
./admin -s
|
||||
|
||||
# Add regular user
|
||||
./add-user.py 2>> log
|
||||
First User
|
||||
|
||||
# Check
|
||||
./admin -s
|
||||
|
||||
# Add Johnny Droptable
|
||||
./add-user.py 2>> log
|
||||
Johnny'); DROP TABLE users; --
|
||||
|
||||
# See the problem:
|
||||
./admin -s
|
||||
|
||||
# Check the log
|
||||
tail log
|
||||
#+END_SRC
|
||||
|
||||
** Reading Order
|
||||
The queries introduce CodeQL concepts and should be read bottom-up in this
|
||||
order:
|
||||
1. =source.ql=: introduces Value, ControlFlowNode and DataFlow::Node.
|
||||
2. =sink.ql=: introduces AstNode.
|
||||
3. =TaintFlowTemplate.ql=: introduce the taint flow template.
|
||||
4. =TaintFlow.ql=: taint flow with endpoints only, using a class. This is the
|
||||
old way, but it still works and is a good introduction to /using/ classes --
|
||||
not /writing/ them.
|
||||
5. =TaintFlowPath.ql=: taint flow with full path. Again, the old way.
|
||||
6. =TaintFlowWithModule.ql=: taint flow with endpoints only, using modules.
|
||||
The way forward.
|
||||
7. =TaintFlowPathQueryWithModule.ql=: taint flow with full path, using modules.
|
||||
|
||||
** Note on the Python code
|
||||
The Python call
|
||||
: conn.execute(query)
|
||||
to sqlite3 only allows one statement and produces an exception:
|
||||
: sqlite3.Warning: You can only execute one statement at a time.
|
||||
This makes it safer than the raw
|
||||
: sqlite3_exec()
|
||||
or Python's
|
||||
: conn.executescript
|
||||
|
||||
For this tutorial, we use the multi-statement =executescript()= call.
|
||||
|
||||
* Additional Topics
|
||||
This repository and its source code are used to illustrate some additional
|
||||
topics from the CodeQL Python documentation.
|
||||
|
||||
** Dataflow in Python
|
||||
https://codeql.github.com/docs/codeql-language-guides/analyzing-data-flow-in-python/
|
||||
|
||||
Using and extending the CodeQL standard library:
|
||||
- StdLibPlain.ql
|
||||
Illustrates using the CodeQL standard library's
|
||||
: RemoteFlowSource
|
||||
- StdLibExt.ql
|
||||
Illustrates extension of the CodeQL standard library via
|
||||
: class SqlAccess extends FileSystemAccess::Range ...
|
||||
and
|
||||
: class TerminalInput extends RemoteFlowSource::Range ...
|
||||
|
||||
Various data flow / taint flow examples from the documentation, modified as
|
||||
needed:
|
||||
- using-local-data-flow.ql
|
||||
- using-local-sources.ql
|
||||
- using-local-taint-tracking.ql
|
||||
|
||||
** API graphs
|
||||
https://codeql.github.com/docs/codeql-language-guides/using-api-graphs-in-python/
|
||||
|
||||
API graphs are a uniform interface for referring to functions, classes, and methods defined in external libraries.
|
||||
|
||||
- =ApiGraphs.ql=: various sample queries
|
||||
|
||||
** Type Tracking
|
||||
Documentation for JavaScript, also applicable here:
|
||||
https://codeql.github.com/docs/codeql-language-guides/using-type-tracking-for-api-modeling/#using-type-tracking-for-api-modeling
|
||||
|
||||
The files
|
||||
- sqlite-info.py
|
||||
- TypeTracking.ql
|
||||
use type tracking. From the docs: You can track data through an API by
|
||||
creating a model using the CodeQL type-tracking library. The type-tracking
|
||||
library makes it possible to track values through properties and function
|
||||
calls.
|
||||
|
||||
The file
|
||||
- =TypeTrackingWithData.ql=
|
||||
goes further. From the docs: The type-tracking library makes it possible to
|
||||
track values through properties and function calls. Here, we also track some
|
||||
associated data. See
|
||||
https://codeql.github.com/docs/codeql-language-guides/using-type-tracking-for-api-modeling/#tracking-associated-data
|
||||
|
||||
** Flow State
|
||||
The query =TaintFlowPathQueryWithSanitizer.ql= illustrates using a flow-state
|
||||
representing whether user input has been sanitized.
|
||||
|
||||
It introduces [[https://codeql.github.com/docs/ql-language-reference/types/#algebraic-datatypes][ADT]]s via the =newtype= declaration of =TInputSanitizationState=.
|
||||
43
add-user.js
Normal file
43
add-user.js
Normal file
@@ -0,0 +1,43 @@
|
||||
function get_user_info() {
|
||||
var fs = require("fs");
|
||||
var stdinBuffer = fs.readFileSync(process.stdin.fd);
|
||||
var line = stdinBuffer.toString();
|
||||
console.log(line);
|
||||
line = line.replace(/(\r\n|\n|\r)/gm, "");
|
||||
return line
|
||||
}
|
||||
|
||||
function get_new_id() {
|
||||
return Math.floor(Math.random() * 12345);
|
||||
}
|
||||
|
||||
function write_info(id, info) {
|
||||
const sqlite3 = require('sqlite3').verbose();
|
||||
const db = new sqlite3.Database(
|
||||
'users.sqlite',
|
||||
sqlite3.OPEN_READWRITE | sqlite3.OPEN_FULLMUTEX,
|
||||
err => {
|
||||
if (err){
|
||||
console.log(err);
|
||||
throw err;
|
||||
} else {
|
||||
console.log('DB opened');
|
||||
}
|
||||
});
|
||||
|
||||
db.serialize();
|
||||
const query = `INSERT INTO users VALUES (${id}, "${info}")`;
|
||||
console.log(query);
|
||||
db.exec(query);
|
||||
|
||||
db.close();
|
||||
}
|
||||
|
||||
let add_user = () => {
|
||||
console.log("Running add-user");
|
||||
info = get_user_info()
|
||||
id = get_new_id()
|
||||
write_info(id, info)
|
||||
}
|
||||
|
||||
add_user()
|
||||
60
admin
Executable file
60
admin
Executable 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
|
||||
22
codeql-pack.lock.yml
Normal file
22
codeql-pack.lock.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
lockVersion: 1.0.0
|
||||
dependencies:
|
||||
codeql/javascript-all:
|
||||
version: 0.8.3
|
||||
codeql/javascript-queries:
|
||||
version: 0.8.3
|
||||
codeql/mad:
|
||||
version: 0.2.3
|
||||
codeql/regex:
|
||||
version: 0.2.3
|
||||
codeql/suite-helpers:
|
||||
version: 0.7.3
|
||||
codeql/tutorial:
|
||||
version: 0.2.3
|
||||
codeql/typos:
|
||||
version: 0.2.3
|
||||
codeql/util:
|
||||
version: 0.2.3
|
||||
codeql/yaml:
|
||||
version: 0.2.3
|
||||
compiled: false
|
||||
10
js-sqli.code-workspace
Normal file
10
js-sqli.code-workspace
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
}
|
||||
1104
package-lock.json
generated
Normal file
1104
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
5
package.json
Normal file
5
package.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"sqlite3": "^5.1.6"
|
||||
}
|
||||
}
|
||||
8
qlpack.yml
Normal file
8
qlpack.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
library: false
|
||||
name: hohn/codeql-javascript-multiflow
|
||||
version: 0.0.1
|
||||
# Install the queries for browsing. They are not needed for this example.
|
||||
dependencies:
|
||||
codeql/javascript-all: "*"
|
||||
codeql/javascript-queries: "*"
|
||||
Reference in New Issue
Block a user