
Alle Phasen der Untersuchung von polkit CVE-2021-4034 mithilfe von CodeQL
** Überblick Dieses Repository untersucht den polkit pkexec-Bug mit CodeQL. Es enthält
Erledigt sind:
Noch zu erledigen:
** Der Bug Der Polkit pkexec-Bug [[https://blog.qualys.com/vulnerabilities-threat-research/2022/01/25/pwnkit-local-privilege-escalation-vulnerability-discovered-in-polkits-pkexec-cve-2021-4034][(CVE-2021-4034)]] beginnt mit einem Array-Grenzen-Fehler in Bezug auf argv und baut darauf auf. Der Teil des Problems, der außerhalb der Grenzen liegt, ist etwas, das wir mit der codeql-Bereichsanalyse-Bibliothek untersuchen können.
Die main()-Funktion von pkexec in polkit/src/programs/pkexec.c hat die Struktur #+begin_src text 435 main (int argc, char *argv[]) 436 { ... 534 for (n = 1; n < (guint) argc; n++) 535 { ... 568 } ... 610 path = g_strdup (argv[n]); ... #+end_src
Hauptideen:
Zu prüfende Versionen:
Alle Polkit-Versionen ab 2009 sind verwundbar; erste Version im Mai 2009 (Commit c8c3d83, „Add a pkexec(1) command“).
Wir können /eine/ Datenbank [[https://lgtm.com/projects/g/freedesktop/polkit/ci/#ql][von lgtm]] bekommen, die aktuelle <2022-02-11 Fri> ist =...srcVersion_a6bedfd...= aber diese ist bereits nach dem polkit-Patch: #+BEGIN_SRC text commit a6bedfd09b7bba753de7a107dc471da0db801858 (origin/master, origin/HEAD, master) Author: Xi Ruoyao [email protected] Date: Thu Jan 27 10:16:32 2022 +0000
jsauthority: port to mozjs-91
commit a2bf5c9c83b6ae46cbd5c779d3055bff81ded683 Author: Jan Rybar [email protected] Date: Tue Jan 25 17:21:46 2022 +0000
pkexec: local privilege escalation (CVE-2021-4034)
#+END_SRC Und wir können sehen, dass das Problem behoben ist: #+BEGIN_SRC text commit a2bf5c9c83b6ae46cbd5c779d3055bff81ded683 Author: Jan Rybar [email protected] Date: Tue Jan 25 17:21:46 2022 +0000
pkexec: local privilege escalation (CVE-2021-4034)
diff --git a/src/programs/pkcheck.c b/src/programs/pkcheck.c index f1bb4e1..768525c 100644 --- a/src/programs/pkcheck.c +++ b/src/programs/pkcheck.c @@ -363,6 +363,11 @@ main (int argc, char *argv[]) local_agent_handle = NULL; ret = 126;
exit(126);
Also brauchen wir den [[https://gitlab.freedesktop.org/polkit/polkit.git][Quellcode]] und bauen unsere eigenen Datenbanken, eine vor dem Patch, eine danach.
Der nächste Abschnitt geht die Build-Schritte durch, unter Verwendung eines Docker-Containers.
** polkit und CodeQL-DB bauen Wir brauchen das Build-Setup für polkit, bevor wir eine codeql-Datenbank erhalten können.
Betriebssystemoptionen für den Build:
macOS ist einen Versuch wert, wird aber früh knifflig. Die Verwendung von =brew= für Abhängigkeiten funktioniert bis zu einem gewissen Punkt, aber die =mozjs-78=-Abhängigkeit ist eine spezifische Version von spidermonkey und /diese/ zu bauen ist nicht praktikabel. #+BEGIN_SRC sh # autoconf... ein wenig knifflig auf einem Mac brew install autoconf automake libtool gtk-doc export PATH="/usr/local/opt/libtool/libexec/gnubin:$PATH" ./autogen.sh
# Meson verwenden?
brew install meson ninja intltool glib gobject-introspection
#+END_SRC
Linux ist die native Umgebung für polkit, aber welche? Die mozjs-78 Abhängigkeit ist eine spezifische Version von spidermonkey; außerdem wird polkit nicht von allen Distributionen verwendet:
Ubuntu 22.04 kann auf verschiedene Arten ausgeführt werden, auf Hardware, einer VM (vmware, virtualbox, multipass, etc.), oder einem Docker Container auf einem anderen Host. Für dieses Problem können wir einen Docker-Container verwenden und auch die codeql-Kommandozeilenwerkzeuge einbeziehen.
Die Definition des Containers befindet sich in ./Dockerfiles, hier ist die Build- Sequenz: #+BEGIN_SRC shell # Basis-Image für die Einrichtung des qlbuild-Containers docker pull ubuntu:jammy docker images docker run --cpus 4 -m 8GB -ti ubuntu:jammy
# Anzupassendes Image
docker build -t qlbuild .
#+END_SRC Hinweis: Bei Verwendung von Docker Desktop unter Windows und Mac müssen Speicher- und CPU-Grenzen dort erhöht werden. Einmal gesetzt, ist die Container-Ausführungssequenz einfach #+BEGIN_SRC sh # Als Daemon ausführen, damit er auch beim Trennen erhalten bleibt. docker run -d -p 127.0.0.1:2020:22 --cpus 8 -m 16GB qlbuild
# Und verbinden
ssh -p 2020 test@localhost
#+END_SRC
Build auf Ubuntu 22.04
#+BEGIN_SRC sh
# ---------------------------------
# System-Setup/Installation, als root:
echo "deb-src http://archive.ubuntu.com/ubuntu/ jammy main restricted" >> /etc/apt/sources.list
apt-get update
apt-get install -y zile build-essential git cmake
meson ninja-build
libmozjs-78-0 libmozjs-78-dev
libdbus-1-3 libdbus-1-dev
apt-get build-dep -y policykit-1
apt install unzip
# polkit-Version a2bf5c9c benötigt auch einige Extras
apt install duktape duktape-dev
# älteres meson in /usr/local/bin
pip3 install meson==0.60.3
# Oder den Quellcode holen und diesen verwenden:
# wget https://github.com/mesonbuild/meson/archive/refs/tags/0.60.3.tar.gz
# tar zxf 0.60.3.tar.gz
# etc.
# ---------------------------------
# codeql-Setup -- immer noch root
# holen -- codeql cli und Bibliothek abrufen und extrahieren
# Verwendung: grab version url prefix
grab() {
version=$1; shift
platform=$1; shift
prefix=$1; shift
mkdir -p $prefix/codeql-$version &&
cd $prefix/codeql-$version || return
# cli holen
wget "https://github.com/github/codeql-cli-binaries/releases/download/$version/codeql-$platform.zip"
# Bibliothek holen
wget "https://github.com/github/codeql/archive/refs/tags/codeql-cli/$version.zip"
# Attribute korrigieren
if [ `uname` = Darwin ] ; then
xattr -c *.zip
fi
# Extrahieren
unzip -q codeql-$platform.zip
unzip -q $version.zip
# Bibliotheksverzeichnis für VS Code umbenennen
mv codeql-codeql-cli-$version/ ql
# Archive entfernen
rm codeql-$platform.zip
rm $version.zip
}
grab v2.7.6 linux64 /opt
grab v2.6.3 linux64 /opt
# ---------------------------------
# Als Benutzer test:
# polkit-Quellcode holen
cd /tmp && git clone https://gitlab.freedesktop.org/polkit/polkit.git
# Version 0.119 bauen
cd /tmp/polkit
git checkout 0.119
git clean -fxd
meson setup builddir
meson compile -C builddir
find builddir -name pkexec -ls
: 139269 76 -rwxr-xr-x 1 test root 76696 Feb 12 03:06 builddir/src/programs/pkexec
# ---------------------------------
# codeql-Datenbank für Version 0.119 bauen
cd /tmp/polkit
git checkout 0.119
git clean -fxd
# Den Konfigurationsschritt wie gewohnt ausführen, ohne codeql
cd /tmp/polkit && rm -fR builddir
meson setup builddir
# Den Build-Schritt unter codeql ausführen
export CODEQL=/opt/codeql-v2.7.6/codeql/codeql
$CODEQL --version
$CODEQL database create --language=cpp -s . -j 8 -v \
polkit-0.119.db \
--command='meson compile -C builddir'
# Warten auf
# TRAP import complete (10.2s).
# Successfully created database at /tmp/polkit/polkit-0.119.db.
# Und eine schnelle Prüfung, um sicherzustellen, dass pkexec gesehen wurde:
unzip -v polkit-0.119.db/src.zip |grep pkexec
: 29713 Defl:N 8477 72% 2022-02-14 20:12 bb39f235 tmp/polkit/src/programs/pkexec.c
# ---------------------------------
# codeql-Datenbank für Version a2bf5c9c bauen, die gepatchte Version (und weiterhin mit
# mozjs-78)
cd /tmp/polkit
git checkout a2bf5c9c
git clean -fxd
# Den Konfigurationsschritt wie gewohnt ausführen, ohne codeql
cd /tmp/polkit && rm -fR builddir
/usr/local/bin/meson setup builddir
# Mit meson 0.61 läuft die Konfiguration in den Fehler
# actions/meson.build:3:5: ERROR: Function does not take positional arguments.
# Eine schnelle Suche führt zu
# https://lore.kernel.org/all/20220111222135.693a88f2@windsurf/T/
# und von dort zu
# [1/1] package/gobject-introspection: bump to version 1.70.0
# Den Build-Schritt unter codeql ausführen
export CODEQL=/opt/codeql-v2.7.6/codeql/codeql
$CODEQL --version
$CODEQL database create --language=cpp -s . -j 8 -v \
polkit-a2bf5c9c.db \
--command='/usr/local/bin/meson compile -C builddir'
# Warten auf
# TRAP import complete (7.2s).
# Successfully created database at /tmp/polkit/polkit-a2bf5c9c.db.
# Und eine schnelle Prüfung, um sicherzustellen, dass pkexec gesehen wurde:
unzip -v polkit-a2bf5c9c.db/src.zip |grep pkexec
: 30136 Defl:N 8647 71% 2022-02-14 21:27 6af18604 tmp/polkit/src/programs/pkexec.c
#+END_SRC
Die db an einen dauerhaften Ort auf dem Host kopieren #+BEGIN_SRC sh # Aus dem Container kopieren mkdir -p ~/local/polkit && cd ~/local/polkit scp -rq -P 2020 test@localhost:/tmp/polkit/polkit-0.119.db . scp -rq -P 2020 test@localhost:/tmp/polkit/polkit-a2bf5c9c.db .
# Originale behalten
zip -rq polkit-0.119.zip polkit-0.119.db
zip -rq polkit-a2bf5c9c.zip polkit-a2bf5c9c.db
#+END_SRC
Als Nächstes: Einrichtung für die Abfrageentwicklung.
** Einrichtung der Abfrageentwicklung Abfragen können über die codeql cli allein erkundet werden, oder unter Verwendung der codeql cli + dem VS Code-Plugin. Für beide Fälle die cli installieren (siehe die =grab()=-Funktion oben), und die Datenbanken aus [[./db]] extrahieren oder sie bauen wie in [[*Build polkit and codeql db][Build polkit and codeql db]] beschrieben.
Im Folgenden nehmen wir diese Verzeichnisstruktur für die Datenbanken an: #+BEGIN_SRC text . ├── polkit-0.119.db │ ├── codeql-database.yml │ ├── db-cpp │ ├── log │ └── src.zip ├── polkit-0.119.zip ├── polkit-a2bf5c9c.db │ ├── codeql-database.yml │ ├── db-cpp │ ├── log │ └── src.zip └── polkit-a2bf5c9c.zip #+END_SRC
** Die Abfrage Die Abfrage wird inkrementell in [[./argv-out-of-bounds-*.ql]] entwickelt.
Die ersten Schritte in [[./argv-out-of-bounds-0.ql]] verwenden den AST und Variablen- referenzen, um Ergebnisse auf die bekannten Teile des Problems einzugrenzen, wie im Folgenden.
#+BEGIN_SRC text declaration | 435 main (int argc, char *argv[]) | 436 { | ... init other var; | 534 for (n = 1; compare to argc | n < (guint) argc; update other var | n++) | 535 { | ... | 568 } | ... indexed read | 610 path = g_strdup (argv[n]); | ... | 629 if (path[0] != '/') | 630 { | ... | 632 s = g_find_program_in_path (path); | ... indexed write | 639 argv[n] = path = s; | 640 } #+END_SRC
Die Erkundung von Werten beginnt in [[./argv-out-of-bounds-1.ql]] mit einem Versuch, die =SimpleRangeAnalysis=-Bibliothek zu verwenden, über #+begin_src javascript lowerBound(cmp.getLeftOperand().getFullyConverted()), "left lower bound", lowerBound(cmp.getRightOperand().getFullyConverted()), "right lower bound" #+end_src Die Grenzen sind korrekte Grenzen für die Typen, aber zu allgemein -- sie schließen die möglichen Ergebnisse der Iteration ein. Wir sind nur an anfänglichen Grenzen interessiert, die statisch bestimmt sind, jenen vor jeder Iteration.
Anders ausgedrückt, dies ist kein allgemeines Datenflussproblem; wir wollen nur die anfängliche Wertausbreitung entlang bestimmter Ausführungspfade prüfen. Die =for=-Schleife verkompliziert dies, ebenso wie die Operationen innerhalb von ihr.
Wir wollen wirklich Ausführungspfade sehen, die die Schleife ganz umgehen. Das wird in den späteren Teilen von [[./argv-out-of-bounds-1.ql]] getan, unter Verwendung einer =SsaDefinition=.
Die Abfrage [[./argv-out-of-bounds-2.ql]] bereinigt die Erkundung aus [[./argv-out-of-bounds-1.ql]] und identifiziert korrekt alle Stellen, die =n= mit einem bekannten Indexwert =n > 0= verwenden.
Diese Abfrage meldet Ergebnisse auf der verwundbaren Version des Codes, =polkit-0.119.db=. Als Nächstes muss sie geprüft und erweitert werden, sodass sie nichts auf der gepatchten Version meldet, =polkit-a2bf5c9c.db=.