
Le but de ce projet est de démontrer la vulnérabilité exploitée log4j cve-2021-44228 dans une configuration spring-boot, et de montrer comment la corriger.
Le but de ce projet est de démontrer la vulnérabilité d'exploitation log4j cve-2021-44228 dans une configuration spring-boot, et de montrer comment la corriger.
Ce projet contient trois sous-modules. L'un d'eux contient du code vulnérable, les deux autres sont corrigés.
Exécutez ./mvnw clean test à la racine du projet pour exécuter les tests dans les deux modules.
Dans log4shell-example-unpatched, vous verrez beaucoup d'exceptions (le test réussira quand même, car c'est attendu), car il ne reçoit pas la réponse correcte du serveur auquel il tente de se connecter.
Votre application est vulnérable si vous avez remplacé le logger par défaut pour utiliser l'implémentation log4j2 et que vous n'avez pas remplacé la version de log4j2 utilisée. Le pom ressemblera à ceci :```xml org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-logging
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Vous pouvez constater que vos invocations de log sont désormais vulnérables en exécutant le test dans `log4shell-example-unpatched`. Ce test réussit lorsque les invocations de log sont vulnérables.
### Utiliser le test d'intégration Spring pour vérifier si votre propre application est vulnérable
#### 1. Ajouter le `Log4ShellTest` à votre projet
Ajoutez le `Log4ShellTest` depuis `log4shell-example-patched-version` à votre projet :```java
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
@SpringBootTest
@Import(Log4ShellTest.Log4ShellConfig.class)
public class Log4ShellTest {
@Autowired
private List<Log4ShellService> servicesToTest;
@Test
public void testVulnerabilityPatched() throws Exception {
CountDownLatch waitLatch = new CountDownLatch(1);
AtomicInteger connectionAttemptCounter = new AtomicInteger();
Thread listener = new Thread(() -> {
try {
ServerSocket socket = new ServerSocket(22345);
while(true) {
waitLatch.countDown();
Socket connection = socket.accept();
connectionAttemptCounter.getAndIncrement();
connection.close();
}
}
catch(IOException ex) {
throw new IllegalStateException(ex);
}
});
listener.start();
waitLatch.await();
servicesToTest.forEach(service -> service.testLog("${jndi:ldap://127.0.0.1:22345}"));
Assertions.assertEquals(0, connectionAttemptCounter.get());
// If you're not using lombok, change the 6 to 2
Assertions.assertEquals(6, servicesToTest.size());
listener.interrupt();
}
@Configuration
@ComponentScan
public static class Log4ShellConfig {
}
public interface Log4ShellService {
void testLog(String arg);
}
@Component
public static class Service1 implements Log4ShellService {
private static final Logger logger = LogManager.getLogger("Test");
@Override
public void testLog(String arg) {
logger.info("Test: " + arg);
}
}
@Component
public static class Service2 implements Log4ShellService {
private static final Logger logger = LogManager.getLogger("Test");
@Override
public void testLog(String arg) {
logger.info("Test: {}", arg);
}
}
// Remove this class if you're not using lombok
@Component
@Slf4j
public static class Service3 implements Log4ShellService {
@Override
public void testLog(String arg) {
log.info("Test: {}", arg);
}
}
// Remove this class if you're not using lombok
@Component
@Slf4j
public static class Service4 implements Log4ShellService {
@Override
public void testLog(String arg) {
log.info("Test: " + arg);
}
}
// Remove this class if you're not using lombok
@Component
@Log4j2
public static class Service5 implements Log4ShellService {
@Override
public void testLog(String arg) {
log.info("Test: {}", arg);
}
}
// Remove this class if you're not using lombok
@Component
@Log4j2
public static class Service6 implements Log4ShellService {
@Override
public void testLog(String arg) {
log.info("Test: " + arg);
}
}
}