Online исправление уязвимостей с помощью SysCare
Устранение уязвимостей в ПО происходит путём обновления версии установленного ПО с последующим перезапуском процессов. В версии openScaler 22.03 SP1 была добавлена технология SysCare, которая поможет произвести установку патча для процесса пользователя без его перезапуска.
В официальной документации на сайте https://docs.openeuler.org/en/docs/22.03_LTS_SP1/docs/SysCare/SysCare_introduction.html приведены следующие возможности утилиты:
-
Простое создание патчей, как для ядра, так и для уровня пользователя.
-
Интерфейс для управления патчами, включая их установку, активацию, деактивация и удаление.
Используются следующие возможности:
-
Унифицированные патчи: SysCare скрывает разницу в деталях создания патча, предоставляя унифицированный инструмент для улучшения эффективности эксплуатации и обслуживания.
-
Применение патчей на лету для приложения уровня пользователя: SysCare поддерживает наложение патчей на многопоточные и много-процессные приложения в пространстве пользователя, что позволяет достичь эффекта без перезапуска процесса или потока.
-
Ленивый механизм: 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.
В заключение можно сказать, что данный инструментарий является одним из ключевых новых веяний в инструментарии управления информационной безопасности и защиты корпоративной ИТ инфраструктуры. И заслуживает пристального внимания и анализа со стороны инженеров подразделений обеспечения ИБ и служб технической поддержки и сопровождения корпоративных сервисов.