静的解析ツールCodeQL CLIを用いた脆弱性の検出をしてみた

作成: 2020年12月08日

更新: 2021年03月29日

概要

この記事はセキュリティ Advent Calendar 2020 - Qiitaの9日目です.

静的解析ツールCodeQLのCLI版を用いてセキュリティ脆弱性の発見をテストしてみました.

CodeQLとは?

CodeQL - GitHub Security Lab

CodeQLは静的解析ツール一種でソースコードをデータベースのように扱い,脆弱性を引き起こすパターンや冗長なコードのパターンをクエリとしてデータベース化されたソースコードに対して実行することで脆弱性を発見できます.

シンプルな例として以下のクエリはPythonコードの中でpassしか含まれていない冗長なif文を検出します.

import python
from If ifstmt, Stmt pass
where pass = ifstmt.getStmt(0) and
pass instanceof Pass
select ifstmt, "This 'if' statement is redundant."

passしか含まれていない冗⻑なif⽂の例

if is_checked == True:
    print("Check")
else:
    pass

同様の⽅法で脆弱性を引き起こすコードのパターンを検出できる.
この記事ではLGTMというサービスが包括的なセキュリティチェックに使⽤しているクエリをCLIを用いて実際に実行してみる.

またセキュリティチェックの対象としてDjango製のeasybuggy4djangoを用いる.easybuggy4djangoはSQLインジェクションやデッドロックなど有名な脆弱性が山ほど含まれてます.easybuggy4djangoはPython3.7以降では動かないみたいなので注意.

CodeQL CLIの実行

参考: CodeQL CLI — CodeQL

Windows 10のWSL上で実行しました.

  1. CodeQL CLIのセットアップ

    wget https://github.com/github/codeql-clibinaries/releases/latest/download/codeql.zip
    unzip codeql
    mkdir ~/codeql-home
    mv codeql ~/codeql-home/
  2. 解析に必要なCodeQLクエリのクローン

    git clone https://github.com/github/codeql.git
    mv codeql codeql-repo
    mv codeql-repo ~/codeql-home/
  3. easybuggy4djangoのクローン

    git clone https://github.com/k-tamura/easybuggy4django.git
    cd easybuggy4django
  4. easybuggy4djangoのデータベース構築

    ~/codeql-home/codeql/codeql databse create codeql-db --language=python
  5. 解析

    python-security-and-qualityを指定することでセキュリティに関するクエリセットを実行しています.

    mkdir codeql-result
    ~/codeql-home/codeql/codeql databse analyze "codeql-db" python-security-and-quality
    --format=sarif-latest --output=codeql-resutlt/security-and-quality.
    sarif

    codeql-resutlt/security-and-quality.sarif に解析結果が出⼒される.

解析結果

sarifファイルはVSCodeの拡張機能Sarif Viewer - Visual Studio Marketplace で見ることができます.

sarif.png

SQLインジェクションなどの脆弱性がしっかり検出できています.

SQLインジェクションを起こしているソースコードでは以下のようになっています.

def sql_injection(request):
    d = {
    'title': _('title.sqlijc.page'),
    'note': _('msg.note.sqlijc'),
    }
    if request.method == 'POST':
        name = request.POST.get("name")
        password = request.POST.get("password")
        d['users'] = User.objects.raw("SELECT * FROM easybuggy_user WHERE ispublic = 'true' AND name='" + name + "' AND password='" + password + "' ORDER BY id")
    return render(request, 'sqlijc.html', d)

変数を含む生SQLを検知しているのだと思います.

一方で検出できていない脆弱性もありました.

以下はDjangoのテンプレート記法で書かれていてXSSを起こします.

{% extends "base.html" %}
{% load i18n %}
{% block body %}
{% include "header.html" %}
<form action="" method="post" enctype="application/x-www-form-urlencoded">
    {% csrf_token %}
    <p>{% trans 'description.reverse.string' %}</p><br/>
    <label>{% trans 'label.string' %}</label><span>: </span>
    <input type="text" name="string" size="100" maxlength="100"/><br/>
    <br/> <input type="submit" value="{% trans 'label.submit' %}"/><br/><br/>
    {% autoescape off %}
    <p>{{ msg }}</p><br/>
    {% endautoescape %}
    <div class="alert alert-info" role="alert">
        <span class="glyphicon glyphicon-info-sign"></span>
        {% trans 'msg.note.xss' %}
    </div>
</form>
{% endblock %}

Djangoのもつエスケープ機能を{% autoescape off %}でキャンセルしているためXSSが起こってしまう.これはDjangoというフレームワーク由来で起きる脆弱性でこのようなものは検知できない(HTMLやJavaScriptとしてCodeQLを実行しても検知できない)

まとめ

CodeQL CLIを用いてセキュリティ解析を行ってみました.

CodeQLはまだ発展途上ではありますがGithubが公式にサポートしていることもあり今後のコミュニティの発展がとても楽しみです.