
Machen Sie erste Schritte in CodeQL für Python, indem Sie eine Abfrage schreiben, um CVE-2024-32022 zu finden
Voraussetzungen • Ressourcen • Workshop
Sie haben die Wahl zwischen zwei Optionen, um die Workshop-Übungen durchzuführen:
Verwenden Sie eine lokale CodeQL-Installation, um an den Workshop-Übungen zu arbeiten.
git installiert auf Ihrem lokalen Rechner.curl -L -O "https://github.com/sylwia-budzynska/codeql-workshop/releases/download/v1/test-app-db.zip" curl -L -O "https://github.com/sylwia-budzynska/codeql-workshop/releases/download/v1/kohya_ss-db.zip"
3. In VS Code: Datei -> **Arbeitsbereich aus Datei öffnen...** `vscode-codeql-starter.code-workspace`
4. Fahren Sie fort mit [Auswählen einer CodeQL-Datenbank](#select-codeql-database)
5. Dann [Testen Sie Ihre Installation](#test-your-installation)
### Option B: GitHub Codespace
Verwenden Sie einen remote GitHub Codespace, um an den Workshop-Übungen zu arbeiten.
#### Voraussetzungen
* GitHub-Konto ([kostenlos anmelden](https://github.com/))
* Browser (Sie können den gesamten Workshop in einem Browser durchführen – dies ist der schnellste Setup) oder [Visual Studio Code](https://code.visualstudio.com/download) (VS Code) mit der [GitHub Codespaces](https://marketplace.visualstudio.com/items?itemName=GitHub.codespaces)-Erweiterung, die auf Ihrem lokalen Rechner installiert ist.
Hinweis: Die ersten 120 Stunden pro Kern der Codespace-Nutzung sind pro Monat kostenlos. Wir verwenden für diesen Workshop einen Codespace mit 4 Kernen, da 4 Kerne das derzeitige Maximum für kostenlose Konten sind. (Wenn Sie ein Pro-Konto haben, empfehlen wir, auf eine 8-Kern-Maschine umzusteigen.)
#### Anleitung
1. Melden Sie sich bei Ihrem [GitHub](https://github.com/login)-Konto an
2. Gehen Sie zum Repository https://github.com/sylwia-budzynska/codeql-workshop
3. Klicken Sie auf Code -> Codespaces
4. Klicken Sie auf das Pluszeichen (+), um einen neuen Codespace zu erstellen.
<img src="https://assets.kitploit.com/production/public/readmes/33098/c86e537f9e7891fb6bdb5da727cae5b6ad0b2c9ac94f67854d48296f2dad89cb.png" width="439" alt="Screenshot: Codespace erstellen, klicken Sie auf Plus">
VS Code wird in Ihrem Browser gestartet und ein remote Codespace wird erstellt. Dies kann einige Minuten dauern.
Wenn Sie aufgefordert werden, den Arbeitsbereich `vscode-codeql-starter.code-workspace` zu öffnen, klicken Sie auf "Arbeitsbereich öffnen".
5. Wenn Sie VS Code lokal verwenden möchten, drücken Sie die Drei-Linien-Taste oben links und wählen Sie "Open VS Code Desktop". Die Option kann einige Minuten dauern, bis sie erscheint.
<img src="https://assets.kitploit.com/production/public/readmes/33098/f2c8c2fe6da80142344b17c208da31a23c3fa68a3917a124f0e2f7871b6a20f7.png" width="300" alt="Screenshot: Drücken Sie die Drei-Linien-Taste und VS Code Desktop öffnen">
6. Fahren Sie fort mit [Auswählen einer CodeQL-Datenbank](#select-codeql-database)
7. Dann [Testen Sie Ihre Installation](#test-your-installation)
Sie können Ihre Codespaces unter [github.com/codespaces](https://github.com/codespaces) einsehen. Der Codespace schaltet sich nach einigen Stunden der Nichtbenutzung von selbst aus. Um sicherzustellen, dass Sie keine zusätzlichen Stunden der 120 kostenlosen Stunden verbrauchen, denken Sie daran, nach dem Workshop zu [github.com/codespaces](https://github.com/codespaces) > drei Punkte > "Codespace stoppen" zu gehen.
#### Fehlerbehebung bei der Installation
Falls Fehler wie diese auftreten:
* `Failed to run query: Could not resolve library path for [..]`
* `Could not resolve module [..]`
* `Could not resolve type [..]`
Haben Sie sehr wahrscheinlich vergessen, die Git-Submodule (nämlich das ql-Repository) zu klonen. Führen Sie zur Behebung `git submodule init && git submodule update --recursive` aus.
### CodeQL-Datenbank auswählen
1. Stellen Sie sicher, dass der Arbeitsbereich `vscode-codeql-starter.code-workspace` in VS Code geöffnet ist.
2. Klicken Sie in der linken Tab-Leiste auf das "QL"-Symbol, um zur CodeQL-Ansicht zu gelangen.
3. Klicken Sie auf "Datenbank aus Archiv auswählen" und wählen Sie die Datei `test-app-db.zip` im Stammverzeichnis des Repositorys.
Hinweis: Möglicherweise tritt an dieser Stelle ein Fehler in VSCode mit einer Pop-up-Meldung auf, die Sie auffordert, die CodeQL CLI zu installieren. Wenn Sie dieser Installation zustimmen, sollte das Problem behoben werden. Nachdem die CLI-Installation abgeschlossen ist, sollten Sie die obige Datenbankauswahl abschließen können.
<img src="https://assets.kitploit.com/production/public/readmes/33098/65cc5790b8b49113623bc9a9b34a1be61575b05bea2428c46f83115e2271148b.png" alt="Screenshot: VSCode Fehlermeldung bzgl. CodeQL">
<img src="https://assets.kitploit.com/production/public/readmes/33098/c3bf9c304d9c1f6199f591c9bcbf6e446ee4f5388ab209e30887326698129f84.png" alt="Screenshot: VSCode installiert CodeQL CLI">
### Testen Sie Ihre Installation
#### Voraussetzungen
Stellen Sie sicher, dass die zuvor ausgewählte CodeQL-Datenbank in der CodeQL-Ansicht ausgewählt ist. (Klicken Sie auf "Auswählen", falls nicht)
Wenn die Datenbank ausgewählt ist, sollte dies wie folgt aussehen (beachten Sie das Häkchen):
<img src="https://assets.kitploit.com/production/public/readmes/33098/fee6e47c0d9b0754c7ac9e29e2f0b3a721093aa5ce882615b3839a99f4862506.png" alt="Screenshot: CodeQL-Datenbank ausgewählt">
#### Anleitung
1. Gehen Sie in VS Code zum Arbeitsbereichsordner: `codeql-custom-queries-python`
2. Erstellen Sie eine neue Datei `test.ql`
3. Fügen Sie den folgenden Inhalt hinzu: `select "Hello World!"`
4. Speichern Sie die Datei, klicken Sie mit der rechten Maustaste in den Dateibereich und wählen Sie "CodeQL: Abfrage auf ausgewählter Datenbank ausführen"
5. Es sollte ein neuer Tab mit dem Ergebnis "Hello World!" geöffnet werden.
## :books: Ressourcen
- [QL-Tutorials](https://codeql.github.com/docs/writing-codeql-queries/ql-tutorials/)
- [CodeQL für Python – Sprachleitfaden](https://codeql.github.com/docs/codeql-language-guides/codeql-for-python/)
- [CodeQL-Dokumentation](https://codeql.github.com/docs/)
- [QL-Sprachreferenz](https://codeql.github.com/docs/ql-language-reference/)
- [CodeQL-Bibliothek für Python](https://codeql.github.com/codeql-standard-libraries/python/)
- [Grundlegende Abfrage für Python-Code](https://codeql.github.com/docs/codeql-language-guides/basic-query-for-python-code/)
- [QL-Klassen](https://codeql.github.com/docs/ql-language-reference/types/#classes)
- [CodeQL von Null zu Held Teil 1: Die Grundlagen der statischen Analyse für die Schwachstellenforschung](https://github.blog/2023-03-31-codeql-zero-to-hero-part-1-the-fundamentals-of-static-analysis-for-vulnerability-research/)
- [CodeQL von Null zu Held Teil 2: Erste Schritte mit CodeQL](https://github.blog/2023-06-15-codeql-zero-to-hero-part-2-getting-started-with-codeql/)
- [CodeQL von Null zu Held Teil 3: Sicherheitsforschung](https://github.blog/2024-04-29-codeql-zero-to-hero-part-3-security-research-with-codeql/)
- [CodeQL von Null zu Held Teil 4: Gradio-Fallstudie](https://github.blog/security/vulnerability-research/codeql-zero-to-hero-part-4-gradio-framework-case-study/)
- [CodeQL von Null zu Held Teil 5: Debugging von Abfragen](https://github.blog/security/vulnerability-research/codeql-zero-to-hero-part-5-debugging-queries/)
## Workshop
Willkommen zum Workshop "Schwachstellen mit CodeQL finden"!
Diese Sitzung führt in die Grundlagen der Sicherheitsforschung und statischen Analyse ein, die bei der Suche nach Schwachstellen in Software verwendet werden. Wir werden am Beispiel einer einfachen Schwachstelle demonstrieren, wie CodeQL sie erkennen könnte, und Beispiele geben, wie das Publikum CodeQL selbst zur Schwachstellensuche einsetzen kann.
Bevor wir beginnen, ist es wichtig, dass alle Voraussetzungen erfüllt sind, damit Sie am Workshop teilnehmen können.
Der Workshop ist in mehrere Abschnitte unterteilt, und jeder Abschnitt besteht aus Übungen, die zur endgültigen Abfrage hinführen.
Für jeden Abschnitt stellen wir *Richtlinien* bereit, die Ihnen helfen, die Übung zu absolvieren, indem wir auf QL-Klassen und Member-Prädikate verweisen, die Sie verwenden können.
### Überblick
In diesem Workshop werden wir nach einer bekannten *Befehlsinjektions-Schwachstelle* in [kohya_ss](https://securitylab.github.com/advisories/GHSL-2024-019_GHSL-2024-024_kohya_ss/) suchen. Solche Schwachstellen können auftreten, wenn von einem Benutzer kontrollierte Informationen in Anwendungscode gelangen, der unsicher einen Befehl konstruiert und ausführt. Der unsicher aus Benutzereingaben konstruierte Befehl kann so umgeschrieben werden, dass unbeabsichtigte Aktionen wie die Ausführung beliebiger Befehle oder die Offenlegung sensibler Informationen möglich sind.
Die in diesem Workshop behandelten Befehlsinjektionen sind [CVE-2024-32022, CVE-2024-32026, CVE-2024-32025, CVE-2024-32027](https://securitylab.github.com/advisories/GHSL-2024-019_GHSL-2024-024_kohya_ss/).
## Theorie
### Quellen und Senken
Denken Sie an eine der bekanntesten Schwachstellen – Befehlsinjektion. Sie tritt auf, wenn Benutzereingaben in Funktionen verwendet werden, die es erlauben, Befehle in einer Shell direkt auf dem Server auszuführen. Ein Angreifer kann dadurch Betriebssystembefehle auf dem Server ausführen, auf dem eine Anwendung läuft, und typischerweise die Anwendung und ihre Daten vollständig kompromittieren.
Die Hauptursache für Injektionsschwachstellen sind nicht vertrauenswürdige, vom Benutzer kontrollierte Eingaben, die in sensiblen oder gefährlichen Funktionen des Programms verwendet werden. Um dies in der statischen Analyse darzustellen, verwenden wir Begriffe wie Datenfluss, Quellen und Senken.
Benutzereingaben stammen im Allgemeinen von Einstiegspunkten in eine Anwendung – dem Ursprung der Daten. Dazu gehören Parameter in HTTP-Methoden wie GET und POST oder Befehlszeilenargumente eines Programms. Diese werden als "**Quellen**" bezeichnet.
Um bei unserer Befehlsinjektion zu bleiben: Ein Beispiel für eine gefährliche Funktion, die nicht mit unsauberen, nicht vertrauenswürdigen Daten aufgerufen werden sollte, ist `os.system`. Diese gefährlichen Funktionen werden "**Senken**" genannt. Beachten Sie, dass nur weil eine Funktion potenziell gefährlich ist, dies nicht bedeutet, dass es sich sofort um eine ausnutzbare Schwachstelle handelt, die entfernt werden muss. Viele Senken haben Möglichkeiten, sie sicher zu verwenden. Weitere Beispiele für Senken, die nicht mit Benutzereingaben verwendet werden sollten, sind `MySQLCursor.execute()` aus der MySQLdb-Bibliothek in Python (was SQL-Injection verursacht) oder Pythons eingebaute `eval()`-Funktion, die beliebige Ausdrücke auswertet (was Code-Injection verursacht).
Damit eine Schwachstelle vorhanden ist, muss die unsichere, vom Benutzer kontrollierte Eingabe ohne ordnungsgemäße Bereinigung oder Eingabevalidierung in einer gefährlichen Funktion verwendet werden. Mit anderen Worten: Es muss einen Codepfad zwischen der Quelle und der Senke geben; in diesem Fall sagen wir, dass Daten von einer Quelle zu einer Senke fließen – es gibt einen "**Datenfluss**" von der Quelle zur Senke.
<img src="https://assets.kitploit.com/production/public/readmes/33098/ff60a1649737805a71bd27710209dba66203a77159cc72ae435c165353e56491.png">
### CodeQL-Spickzettel
Die grundlegende Abfragestruktur```codeql
import python
from <type> <name> //variables used in the query
where <conditions for variables>
select <output> //results, referring to the variables
Finde Verweise auf os.system() Aufrufe```codeql
import python
import semmle.python.ApiGraphs
from API::CallNode call where call = API::moduleImport("os") .getMember("system") .getACall() select call, "Call to os.system"
Finde Verweise auf `os.system()`-Aufrufe, diesmal mit einem Prädikat```codeql
predicate isOsSystemSink(API::CallNode call) {
call = API::moduleImport("os")
.getMember("system").getACall()
}
from API::CallNode call
where isOsSystemSink(call)
select call, "Call to os.system"
Finde Verweise auf os.system()-Aufrufe, diesmal mit einer Klasse.```codeql
class OsSystemSink extends API::CallNode {
OsSystemSink() {
this = API::moduleImport("os")
.getMember("system").getACall()
}
}
from API::CallNode call where call instanceof OsSystemSink select call, "Call to os.system"
Finde Verweise auf `os.system()`-Aufrufe, diesmal mit einer Klasse.
Geben Sie an, dass der Typ, mit dem wir beginnen, `OsSystemSink` ist.```codeql
class OsSystemSink extends API::CallNode {
OsSystemSink() {
this = API::moduleImport("os")
.getMember("system").getACall()
}
}
from OsSystemSink s
select s, "Call to os.system"
In diesem Workshop werden wir Befehlseinschleusungen finden, bei denen Benutzereingaben in einem os.system-Aufruf landen.
Im ersten Teil des Workshops schreiben wir CodeQL-Abfragen, um Quellen und Senken zu finden, also os.system-Aufrufe, in einer absichtlich verwundbaren Codebasis. Im zweiten Teil des Workshops werden wir diese Abfragen nutzen, um eine Befehlseinschleusung von einer Quelle zu einer Senke in einer Open-Source-Software, kohya_ss v22.6.1, zu finden.
Mit der CodeQL-Abfrage, die wir schreiben, werden wir in der Lage sein, Befehlseinschleusungen wie die untenstehende zu finden.
Die Benutzereingabe stammt von einer interaktiven Gradio-Komponente (Web-Framework für maschinelle Lernanwendungen) gr.Textbox bei #1. gr.Button.click bei #2 bindet den Button-Klick an die Funktion execute_cmd und übergibt die Werte aus folder. Das bedeutet, wenn der gr.Button geklickt wird, wird folder an execute_cmd übergeben, wo folder in einen Befehl verkettet und in einem os.system-Aufruf bei #3 ausgeführt wird.```python
import gradio as gr
import os
def execute_cmd(folder): cmd = f"python caption.py --dir={folder}" os.system(cmd) #3
with gr.Blocks() as demo: gr.Markdown("Create caption files for images in a directory") with gr.Row(): folder = gr.Textbox(placeholder="Directory to caption") #1 logs = gr.Checkbox(label="Add verbose logs")
btn = gr.Button("Run")
btn.click(fn=execute_cmd, inputs=[folder]) #2
if name == "main": demo.launch(debug=True)
Sie werden auch ein weiteres Beispiel für eine Befehlseinschleusung im Workshop bemerken, in einer App, die mit dem `Flask`-Framework erstellt wurde. In diesem Fall stammt die Benutzereingabe aus einem GET-Parameter einer Flask-Anfrage (einem beliebten Web-Framework in Python), die in der Variablen `files` gespeichert ist (siehe #1). `files` wird dann an den `os.system`-Aufruf übergeben und mit `ls` verkettet, was zu einer Befehlseinschleusung führt (siehe #2).```python
import os
from flask import Flask, request
app = Flask(__name__)
@app.route("/command1")
def command_injection1():
files = request.args.get('files', '') #1
os.system("ls " + files) #2
Wir beginnen damit, schrittweise eine Abfrage zur Erkennung von os.system-Aufrufen und anschließend eine Abfrage für Quellen aufzubauen.
Wir können alle Aufrufe von Funktionen aus externen Bibliotheken (die nicht in der Codebasis definiert sind) mit Hilfe des CodeQL-Moduls ApiGraphs finden.
Verwenden Sie folgende Vorlage:```codeql import python import semmle.python.ApiGraphs
from //TODO: fill me in. Start typing API:: and press Ctrl+Space to see a list of available types. Name your variable call
select //TODO: fill me in
Right click in the file area and choose "CodeQL: Run Query on Selected Database" to run the query.
<details>
<summary>Richtlinien</summary>
- Verwenden Sie in der `from`-Klausel `API::` und drücken Sie `Ctrl + Space`, um die verfügbaren Typen im API-Graphs-Modul anzuzeigen.
- Ein Aufruf wird durch den Typ `API::CallNode` dargestellt. Erstellen Sie eine Variable mit diesem Typ und dem Namen `call`.
- Um die Ergebnisse nur auf Aufrufe im Stammverzeichnis der Anwendung (genannt `test-app`) zu beschränken, fügen Sie eine `where`-Klausel mit der Bedingung `where call.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*")` hinzu.
</details>
<details>
<summary>Lösung</summary>```codeql
import python
import semmle.python.ApiGraphs
from API::CallNode call
where call.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*")
select call, "A call"
os.system findenfrom-Klausel eine call-Variable vom Typ API::CallNode.where-Klausel den Gleichheitsoperator =, um zu bestätigen, dass call den os.system-Aufrufen entspricht. Verwenden Sie den logischen Operator and, um mehrere Bedingungen zu spezifizieren.os-Bibliothek entsprechen, verwenden Sie die Methode API::moduleImport() mit os als Argument. Um auf die system-Funktion der os-Bibliothek zuzugreifen, verwenden Sie das Prädikat getMember() auf . Rufen Sie schließlich alle -Aufrufe mit dem Prädikat ab.os.systemWir möchten die ersten Argumente von os.system-Aufrufen finden, um später zu sehen, ob Benutzereingaben in die ersten Argumente (also in den auszuführenden Befehl) fließen.
from API::CallNode call
where call = API::moduleImport("os").getMember("system").getACall() and
call.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*")
select call // TODO: fill me in. Type a dot . right after call and press Ctrl+Space to see available predicates.
</details>
<details>
<summary>Lösung</summary>```codeql
import python
import semmle.python.ApiGraphs
from API::CallNode call
where call = API::moduleImport("os").getMember("system").getACall() and
call.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*")
select call.getArg(0), "First argument of an `os.system` call"
os.system findet, in eine CodeQL-Klasseclasses in CodeQL können verwendet werden, um wiederverwendbare Logikteile zu kapseln. Klassen repräsentieren einzelne Wertemengen und können auch Operationen (sogenannte Member-Prädikate) enthalten, die für diese Wertemenge spezifisch sind. Sie haben bereits zahlreiche Beispiele von CodeQL-Klassen (API::CallNode) und Member-Prädikaten (getLocation() usw.) gesehen.
API::CallNode – ihm einen Namen und ein charakteristisches Prädikat mit demselben Namen geben. Wir werden unsere Klasse OsSystemSink nennen.Füllen Sie die Vorlage aus:
class OsSystemSink extends API::CallNode { OsSystemSink() { //TODO: fill me in } }
from API::CallNode call where // TODO: fill me in and call.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*") select call.getArg(0), "Call to os.system"
- Verwenden Sie das magische `this`-Schlüsselwort, das sich auf die Instanzen der Aufrufknoten (`API::CallNode`s) bezieht, die wir in der Klasse beschreiben. Verwenden Sie `this`, um die Aufrufe von `os.system` auf die gleiche Weise zu finden, wie Sie es zuvor mit `API::moduleImport` getan haben.
- Ändern Sie die `where`-Klausel, um Ihre `call`-Variable zu einem `instanceof` Ihrer neuen `OsSystemSink`-Klasse zu machen.```codeql
import python
import semmle.python.ApiGraphs
class OsSystemSink extends API::CallNode {
OsSystemSink() {
this = API::moduleImport("os").getMember("system").getACall()
}
}
from API::CallNode call
where call instanceof OsSystemSink
and call.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*")
select call.getArg(0), "First argument of an `os.system` call"
Nun wechseln wir zum Auffinden von Quellen.
Die meisten Quellen sind bereits modelliert und in CodeQL vorhanden und haben den Typ RemoteFlowSource. Wir können diesen Typ verwenden, um alle Quellen in einer Codebasis zu finden.
semmle.python.dataflow.new.RemoteFlowSources, um den RemoteFlowSource-Typ zu verwenden.from-Klausel Strg + Leertaste, um alle verfügbaren Typen anzuzeigen.Füllen Sie die Vorlage aus:```codeql import python import semmle.python.dataflow.new.RemoteFlowSources
from //TODO: fill me in where //TODO: fill me in select //TODO: fill me in
</details>
<details>
<summary>Lösung</summary>```codeql
import python
import semmle.python.dataflow.new.RemoteFlowSources
from RemoteFlowSource rfs
where rfs.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*")
select rfs
Kohya_ss ist eine GUI für Kohyas Stable-Diffusion-Skripte für Training, Generierung und Hilfsprogramme für Stable Diffusion.
Im zweiten Teil des Workshops wechseln wir die Codebasis, die wir abfragen, zu kohya_ss und finden die Datenflüsse von Quellen zu Senken in kohya_ss, die zu Befehlsinjektionen führen: CVE-2024-32022, CVE-2024-32026, CVE-2024-32025, CVE-2024-32027
Bevor Sie mit der nächsten Übung beginnen:
Databases, klicken Sie auf "Choose Database from Archive" und wählen Sie die Datei kohya_ss-db.zip im Stammverzeichnis des Repositorys aus. Es sollte ein Häkchen erscheinen. Dadurch wird die CodeQL-Datenbank ausgewählt, mit der Sie arbeiten.os.system-Aufrufen findenisSource-Prädikat verfeinern Sie die Variable source auf den Typ RemoteFlowSource.isSink-Prädikat verfeinern Sie die Variable sink auf das erste Argument eines os.system-Aufrufs. Tun Sie dies mit dem exists-Mechanismus und Ihrer OsSystemSink-Klasse.
exists ist ein Mechanismus zur Einführung temporärer Variablen mit eingeschränktem Gültigkeitsbereich. Sie können ihn sich als ein eigenes from-where-select vorstellen. Verwenden Sie in diesem Fall exists, um die Variable call vom Typ OsSystemSink einzuführen, und verfeinern Sie dann sink auf das erste Argument von .```codeql
/**CodeQL-Abfragen für Python befinden sich im Ordner ql/python/ql/src/Security. Es gibt bereits Abfragen für die gängigsten Schwachstellen: SQL-Injection, Command-Injection, Code-Injection usw. Führen Sie die SQL-Injection-Abfrage (CWE-089) auf der Testdatenbank aus (Sie müssen sie in der CodeQL-Erweiterung > Datenbanken auswählen. Beachten Sie das Häkchen).
💡 Dies ist für Sicherheitsforscher sehr interessant – mit den Standardabfragen können wir einen allgemeinen Eindruck davon gewinnen, welche potenziellen Schwachstellen in einem bestimmten Projekt existieren könnten.
Die Stärke von CodeQL liegt darin, die CodeQL-Abfragen und -Modelle wiederverwenden zu können, um sie auf beliebige Codebasen in derselben Sprache anzuwenden. Wir können CodeQL-Abfragen mit der Multi-Repository-Variantenanalyse (MRVA) gleichzeitig auf bis zu 1000 Repositorys ausführen. Die Projekte müssen auf GitHub gehostet sein.
💡 Dies ist für Sicherheitsforscher sehr interessant – wenn Sie eine potenziell gefährliche Senke oder Quelle gefunden haben, können Sie sie zu CodeQL hinzufügen (oder als Abfrage ausführen) und Ihre Forschung gleichzeitig an tausend Repositorys durchführen.
Heute haben Sie gelernt, wie Sie eine Codebasis mit CodeQL erkunden und CodeQL in Ihrem eigenen Sicherheitsforschungs-Workflow einsetzen können.
Sehen Sie sich diese Ressourcen an, wenn Sie mehr über folgende Themen erfahren möchten:
Wenn Sie mit CodeQL eine Schwachstelle finden, können Sie sie gerne der CodeQL Ruhmeshalle hinzufügen.
API::moduleImport()os.systemgetACall()Füllen Sie die Vorlage aus:```codeql import python import semmle.python.ApiGraphs
from API::CallNode call
where call //TODO: fill me in
and
call.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*")
select call, "Call to os.system"
</details>
<details>
<summary>Lösung</summary>```codeql
import python
import semmle.python.ApiGraphs
from API::CallNode call
where call = API::moduleImport("os").getMember("system").getACall() and
call.getLocation().getFile().getRelativePath().regexpMatch("test-app/.*")
select call, "Call to `os.system`"
callimport python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TaintTracking import semmle.python.ApiGraphs import MyFlow::PathGraph import semmle.python.dataflow.new.RemoteFlowSources
//TODO: add previous class definition here
private module MyConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { // TODO: fill me in }
predicate isSink(DataFlow::Node sink) {
// TODO: fill me in. Use the exists mechanism
exists( |
sink = ...
)
}
}
module MyFlow = TaintTracking::Global;
from MyFlow::PathNode source, MyFlow::PathNode sink where MyFlow::flowPath(source, sink) select sink.getNode(), source, sink, "Command injection"
</details>
<details>
<summary>Lösung</summary>```codeql
/**
* @name Command injection in os.system sink
* @kind path-problem
* @id codeql-ws/dataflow-query
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.ApiGraphs
import semmle.python.dataflow.new.RemoteFlowSources
import MyFlow::PathGraph
class OsSystemSink extends API::CallNode {
OsSystemSink() {
this = API::moduleImport("os").getMember("system").getACall()
}
}
private module MyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource
}
predicate isSink(DataFlow::Node sink) {
exists(OsSystemSink call |
sink = call.getArg(0)
)
}
}
module MyFlow = TaintTracking::Global<MyConfig>;
from MyFlow::PathNode source, MyFlow::PathNode sink
where MyFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "Command injection"