Online исправление уязвимостей с помощью SysCare

Устранение уязвимостей в ПО происходит путём обновления версии установленного ПО с последующим перезапуском процессов. В версии openScaler 22.03 SP1 была добавлена технология SysCare, которая поможет произвести установку патча для процесса пользователя без его перезапуска.

В официальной документации на сайте https://docs.openeuler.org/en/docs/22.03_LTS_SP1/docs/SysCare/SysCare_introduction.html приведены следующие возможности утилиты:

  1. Простое создание патчей, как для ядра, так и для уровня пользователя.

  2. Интерфейс для управления патчами, включая их установку, активацию, деактивация и удаление.

Используются следующие возможности:

  1. Унифицированные патчи: SysCare скрывает разницу в деталях создания патча, предоставляя унифицированный инструмент для улучшения эффективности эксплуатации и обслуживания.

  2. Применение патчей на лету для приложения уровня пользователя: SysCare поддерживает наложение патчей на многопоточные и много-процессные приложения в пространстве пользователя, что позволяет достичь эффекта без перезапуска процесса или потока.

  3. Ленивый механизм: SysCare отлавливает все системные вызовы через ptrace и ждёт их завершения, что позволяет повысить эффективность успешного применения.

Для проверки возможности SysCare будет произведено создание и применение патча для redis, процесса, который хранит данные в памяти и который не желательно перезапускать.

В качестве примера возьмём CVE-2022-24834 https://github.com/redis/redis/security/advisories/GHSA-p8x2-9v9q-c838, которое было исправлено в версии 6.2.13 и попробуем создать патч для версии 6.2.7, которая имеется в составе openScaler 22.03 SP2.

Первым делом установим openScaler и redis на ВМ или сервер.

Процесс установки ОС опустим, ввиду его тривиальности.

Для установки redis версии 6.2.7 необходимо установить пакет redis6:

dnf install redis6

Запустим сервис и проверим, что он работает:

systemctl start redis
journalctl -f

Теперь настало время SysCare. В настоящее время, ещё нет готового rpm пакета с SysCare, писать свой мы не будем. Устанавливать будем путём сборки из исходных текстов. Установим необходимые инструменты для сборки:

dnf install -y elfutils-libelf-devel openssl-devel dwarves flex python3-devel rpm-build bison cmake make gcc g++ rust cargo git kernel-devel

После установки необходимых пакетов, возьмём исходный код SysCare из git репозитория:

git clone https://gitee.com/openeuler/syscare.git

Так как мы собираем SysCare из исходников, то у нас в системе не будет rpm пакета syscare, значит нам необходимо удалить его требование для установки на этапе создании патчей. Для этого необходимо удалить строку 28 в файле builder/src/package/rpm_spec_generator.rs:

Requires: %{syscare_pkg_name}
Пример команд для удаления:

cd
syscare
vi builder/src/package/rpm_spec_generator.rs
28gg
dd
:wq

Курсор на строке 28

и удалили.

UPDATE: Из-за большого числа изменений с момента написания статьи, необходимо использовать коммит 9e342488350478db4973be282d541629167ac796, а так же может потребоваться rust более высокой версии, чем есть в системе (надо удалить системный и поставить новый).

Создадим каталог сборки и выполним её:

cd syscare
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
make

Пока идёт компиляция можно откинуться на спинку стула и отдохнуть.

После успешной сборки необходимо превратить бинарный дистрибутив в slackware установить собранные утилиты командой:

make install

В процессе установки так же устанавливается модуль ядра upatch.ko, но не по правильному пути, для возможности его загрузки, он должен располагаться в каталоге /lib/modules/5.10.0-153.12.0.92.os2203sp2.x86_64/, поместить его туда можно простым копированием:

cp /usr/libexec/syscare/upatch.ko /lib/modules/5.10.0-153.12.0.92.os2203sp2.x86_64/

Для обновления дерева моделей даём команду

depmod
modinfo upatch

Как видно ядро успешно увидело модуль, теперь его можно загрузить:

modprobe upatch
lsmod | grep upatch
dmesg| grep upatch

Модуль успешно загрузился.

Теперь необходимо подготовить патч и собрать его.

Патч пожно взять из коммита в репозитории redis. Для этого открываем репозиторий redis на github и переключаемся на ветку версии 6.2:

Открываем список коммитов и ищем коммит с исправлением:

Искомый коммит имеет в своём комментарии CVE-2022-24834 и имеет хеш 405d14fd44c6a159680484f048b6811e6af21143, открываем его:

Чтобы получить этот коммит в виде patch файла, необходимо в адресной строке добавить .patch, тогда путь будет выглядеть так:

https://github.com/redis/redis/commit/405d14fd44c6a159680484f048b6811e6af21143.patch

Его можно сохранить как через браузер, так и выкачать через curl или wget:

cd ~
mkdir redis-patch
cd redis-patch
curl https://github.com/redis/redis/commit/405d14fd44c6a159680484f048b6811e6af21143.patch -o CVE-2022-24834.patch

Дальше необходимы пакеты с исходниками и отладочной информацией: redis6-6.2.7-2.os2203sp2.src.rpm и redis6-debuginfo-6.2.7-2.os2203sp2.x86_64.rpm. Получить их можно через репозитории source и debug. По умолчанию эти репозитории отключены, но их можно включить. Получим список всех доступных репозиториев:

dnf repolist –all


Включим необходимые репозитории:

dnf config-manager --set-enabled source
dnf config-manager --set-enabled debuginfo
dnf repolist --all

Скачаем требуемые пакеты:

dnf download --source redis6
dnf download redis6-debuginfo

Все подготовительные шаги выполнены и можно приступить к сборке патча.

Для сборки необходимо выполнить команду:

syscare build -n redis_CVE-2022-24834 –source redis6-6.2.7-2.os2203sp2.src.rpm –debuginfo redis6-debuginfo-6.2.7-2.os2203sp2.x86_64.rpm CVE-2022-24834.patch

И-и-и, провал…

Как же так? Или что-то забыли. Время читать логи:

less /root/redis-patch/syscare-build.9767/build.log

Как видно, не хватает пакетов необходимых для сборки redis. Попробуем получить и установить требуемые пакеты:

rpmbuild -ra redis6-6.2.7-2.os2203sp2.src.rpm

Видно, что нужны пакеты libatomic и systemd-devel, установим их командой:

dnf install systemd-devel libatomic

Пробуем ещё раз:

syscare build -n redis_CVE-2022-24834 –source redis6-6.2.7-2.os2203sp2.src.rpm –debuginfo redis6-debuginfo-6.2.7-2.os2203sp2.x86_64.rpm CVE-2022-24834.patch

Успех. Проверяем что получилось:

syscare list

Хм, что-то не то…

ll

На выходе получился rpm файл, попробуем поставить:

dnf localinstall patch-redis6-6.2.7-2.os2203sp2-redis_CVE-2022-24834-1-1.x86_64.rpm

И проверим патчи:

syscare list

Теперь осталось применить патч:

syscare apply redis6-6.2.7-2.os2203sp2/redis_CVE-2022-24834
syscare list

Посмотрим, что в системном журнале:

journalctl

Видно что патч применился.

Теперь настал пора проверить: а работает ли он? Для этого воспользуемся exploit: https://github.com/convisolabs/CVE-2022-24834.

Проверку работоспособности првоедём сразу после перезагрузки системы, так сказать с чистого листа. Производим перезагрузку, но syscare не активируем.

Скачаем expoit и установим зависимости:

git clone https://github.com/convisolabs/CVE-2022-24834
pip3 install pwn
dnf install nc

Выполним exploit:

cd CVE-2022-24834
python3 redis_cve-2022-24834.py

Как видно выполнение exploit завершилось ошибкой, а как там redis?

systemctl status redis

Упал, посмотрим в логах, от чего ему поплохело:

tail -n 20 /var/log/redis/redis.log

Видно что произошло повреждение памяти, посмотрим детальнее, чем это вызвано:

less /var/log/redis/redis.log

Ага, это сработал exploit. Значит данный exploit вызывает падение redis и может привести к DoS. Посмотрим как он поведёт себя при применённом патче. Загрузим модуль ядра и проверим состояние syscare:

modprobe upatch
syscare list

Перезапускаем процесс redis и применяем патч:

systemctl restart redis
syscare apply redis6-6.2.7-2.os2203sp2/redis_CVE-2022-24834
syscare list

Приготовления выполнены, теперь в бой:

python3 redis_cve-2022-24834.py

Exploit опять сработал… Что-то не так… Посмотрим системный журнал:

journalctl -f

Ага, дело в selinux. Есть два пути: отключить selinux и правильный. Пойдём по правильному пути. Установим пакет setroubleshoot:

dnf install setroubleshoot

Найдём в audit.log событие, на базе которого создадим модуль selinux:

grep denied /var/log/audit/audit.log

Возьмём последнее событие:

grep 1692345229.419:115 /var/log/audit/audit.log | audit2allow -a -M syscare-redis

Загрузим созданный модуль:

semodule -i syscare-redis.pp

Перезагрузим redis:

systemctl restart redis

И попробуем ещё раз:

python3 redis_cve-2022-24834.py

Two hours later…

Прошло довольно много времени, а exploit и не думает срабатывать:

Таким образом, созданный патч для syscare и вправду работает. Необходимо только не забыть про SElinux.

В заключение можно сказать, что данный инструментарий является одним из ключевых новых веяний в инструментарии управления информационной безопасности и защиты корпоративной ИТ инфраструктуры. И заслуживает пристального внимания и анализа со стороны инженеров подразделений обеспечения ИБ и служб технической поддержки и сопровождения корпоративных сервисов.