
Все этапы исследования polkit CVE-2021-4034 с помощью codeql
** Обзор В этом репозитории исследуется ошибка polkit pkexec с помощью CodeQL. Здесь есть
Выполнено:
Ещё предстоит сделать:
** Ошибка Ошибка Polkit pkexec [[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)]] начинается с ошибки выхода за границы массива относительно argv и развивается дальше. Выход за границы — это то, что мы можем исследовать с помощью библиотеки анализа диапазонов codeql.
Функция main() в pkexec в polkit/src/programs/pkexec.c имеет структуру #+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
Основные идеи:
Версии для проверки:
Все версии Polkit с 2009 года уязвимы; первая версия — май 2009 года (коммит c8c3d83, «Add a pkexec(1) command»).
мы можем получить /a/ базу данных [[https://lgtm.com/projects/g/freedesktop/polkit/ci/#ql][с lgtm]], текущая <2022-02-11 Пт> — =...srcVersion_a6bedfd...= но эта версия уже содержит патч polkit: #+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 И мы видим, что проблема исправлена: #+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);
Поэтому нам нужен [[https://gitlab.freedesktop.org/polkit/polkit.git][исходный код]] и сборка собственных баз данных: одна до патча, одна после.
В следующем разделе описываются шаги сборки с использованием Docker-контейнера.
** Сборка polkit и CodeQL DB Нам нужна среда сборки polkit, прежде чем мы сможем получить базу данных codeql.
Варианты операционных систем для сборки:
macOS стоит попробовать, но это становится сложным уже в начале. Использование =brew= для получения зависимостей работает до определённого момента, но зависимость =mozjs-78= — это конкретная версия spidermonkey, и собрать /её/ непрактично. #+BEGIN_SRC sh # autoconf... немного сложно на mac brew install autoconf automake libtool gtk-doc export PATH="/usr/local/opt/libtool/libexec/gnubin:$PATH" ./autogen.sh
# Использовать meson?
brew install meson ninja intltool glib gobject-introspection
#+END_SRC
Linux — это родная среда для polkit, но какая именно? Зависимость mozjs-78 — это конкретная версия spidermonkey; кроме того, polkit используется не всеми дистрибутивами:
Ubuntu 22.04 можно запустить несколькими способами: на оборудовании, в виртуальной машине (vmware, virtualbox, multipass и т. д.) или в docker-контейнере на другом хосте. Для этой задачи мы можем использовать Docker-контейнер и включить в него также инструменты командной строки codeql.
Определение контейнера находится в ./Dockerfiles, вот последовательность сборки: #+BEGIN_SRC shell # Базовый образ для настройки контейнера qlbuild docker pull ubuntu:jammy docker images docker run --cpus 4 -m 8GB -ti ubuntu:jammy
# Образ, который будет настроен
docker build -t qlbuild .
#+END_SRC Примечание: при использовании docker desktop на Windows и Mac ограничения памяти и ЦП необходимо увеличить там. После этого последовательность запуска контейнера проста: #+BEGIN_SRC sh # Запуск как демона, чтобы он оставался активным даже при отключении. docker run -d -p 127.0.0.1:2020:22 --cpus 8 -m 16GB qlbuild
# И подключение
ssh -p 2020 test@localhost
#+END_SRC
Сборка на Ubuntu 22.04
#+BEGIN_SRC sh
# ---------------------------------
# Настройка/установка системы, от 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 a2bf5c9c также требует некоторых дополнительных пакетов
apt install duktape duktape-dev
# более старая версия meson в /usr/local/bin
pip3 install meson==0.60.3
# Или получить исходники и использовать их:
# wget https://github.com/mesonbuild/meson/archive/refs/tags/0.60.3.tar.gz
# tar zxf 0.60.3.tar.gz
# и т. д.
# ---------------------------------
# Настройка codeql -- всё ещё от root
# grab -- загрузка и извлечение codeql cli и библиотеки
# Использование: 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
wget "https://github.com/github/codeql-cli-binaries/releases/download/$version/codeql-$platform.zip"
# Получить библиотеку
wget "https://github.com/github/codeql/archive/refs/tags/codeql-cli/$version.zip"
# Исправить атрибуты
if [ `uname` = Darwin ] ; then
xattr -c *.zip
fi
# Извлечь
unzip -q codeql-$platform.zip
unzip -q $version.zip
# Переименовать каталог библиотеки для VS Code
mv codeql-codeql-cli-$version/ ql
# Удалить архивы
rm codeql-$platform.zip
rm $version.zip
}
grab v2.7.6 linux64 /opt
grab v2.6.3 linux64 /opt
# ---------------------------------
# От пользователя test:
# Получить исходники polkit
cd /tmp && git clone https://gitlab.freedesktop.org/polkit/polkit.git
# Собрать версию 0.119
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 для версии 0.119
cd /tmp/polkit
git checkout 0.119
git clean -fxd
# Выполнить шаг настройки как обычно, без codeql
cd /tmp/polkit && rm -fR builddir
meson setup builddir
# Выполнить шаг сборки под codeql
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'
# Дождаться
# TRAP import complete (10.2s).
# Successfully created database at /tmp/polkit/polkit-0.119.db.
# И быстрая проверка, что pkexec был обнаружен:
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 для версии a2bf5c9c, пропатченной версии (и всё ещё с
# mozjs-78)
cd /tmp/polkit
git checkout a2bf5c9c
git clean -fxd
# Выполнить шаг настройки как обычно, без codeql
cd /tmp/polkit && rm -fR builddir
/usr/local/bin/meson setup builddir
# С meson 0.61 настройка завершается ошибкой
# actions/meson.build:3:5: ERROR: Function does not take positional arguments.
# быстрый поиск приводит к
# https://lore.kernel.org/all/20220111222135.693a88f2@windsurf/T/
# а оттуда к
# [1/1] package/gobject-introspection: bump to version 1.70.0
# Выполнить шаг сборки под codeql
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'
# Дождаться
# TRAP import complete (7.2s).
# Successfully created database at /tmp/polkit/polkit-a2bf5c9c.db.
# И быстрая проверка, что pkexec был обнаружен:
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
Скопировать базу данных в постоянное место на хосте #+BEGIN_SRC sh # Скопировать из контейнера 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 .
# Сохранить оригиналы
zip -rq polkit-0.119.zip polkit-0.119.db
zip -rq polkit-a2bf5c9c.zip polkit-a2bf5c9c.db
#+END_SRC
Далее — настройка для разработки запросов.
** Настройка разработки запросов Запросы можно исследовать с помощью codeql cli самостоятельно или с помощью codeql cli + плагина VS Code. В обоих случаях установите cli (см. функцию =grab()= выше) и извлеките базы данных из [[./db]] или соберите их, как описано в [[*Build polkit and codeql db][Сборка polkit и codeql db]].
Далее мы предполагаем следующую структуру каталогов для баз данных: #+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
** Запрос Запрос разрабатывается поэтапно в [[./argv-out-of-bounds-*.ql]].
Первые шаги в [[./argv-out-of-bounds-0.ql]] используют AST и ссылки на переменные, чтобы сузить результаты до известных частей проблемы, как показано ниже.
#+BEGIN_SRC text объявление | 435 main (int argc, char *argv[]) | 436 { | ... инициализация др. переменной; | 534 for (n = 1; сравнение с argc | n < (guint) argc; обновление др. переменной | n++) | 535 { | ... | 568 } | ... чтение по индексу | 610 path = g_strdup (argv[n]); | ... | 629 if (path[0] != '/') | 630 { | ... | 632 s = g_find_program_in_path (path); | ... запись по индексу | 639 argv[n] = path = s; | 640 } #+END_SRC
Исследование значений начинается в [[./argv-out-of-bounds-1.ql]] с попыткой использования библиотеки =SimpleRangeAnalysis= через #+begin_src javascript lowerBound(cmp.getLeftOperand().getFullyConverted()), "left lower bound", lowerBound(cmp.getRightOperand().getFullyConverted()), "right lower bound" #+end_src Границы корректны для типов, но слишком общие — они включают возможные результаты итераций. Нас интересуют только начальные границы, которые статически определимы, то есть те, что существуют до начала любых итераций.
Иными словами, это не общая задача анализа потоков данных; мы хотим проверить только распространение начальных значений по определённым путям выполнения. Цикл =for= усложняет это, как и операции внутри него.
Нам действительно нужно увидеть пути выполнения, которые полностью обходят цикл. Это делается в последних частях [[./argv-out-of-bounds-1.ql]] с использованием =SsaDefinition=.
Запрос [[./argv-out-of-bounds-2.ql]] очищает исследование из [[./argv-out-of-bounds-1.ql]] и корректно определяет все места использования =n= с известным значением индекса =n > 0=.
Этот запрос выдаёт результаты на уязвимой версии кода, =polkit-0.119.db=. Далее его нужно проверить и улучшить, чтобы он не выдавал ничего на пропатченной версии, =polkit-a2bf5c9c.db=.