Log4Shellに脆弱な環境をSpring Bootでつくる

勉強がてら、話題のLog4Shellに脆弱な環境を作ってみます。
**Log4j2のバージョン2.14.0を使っていると簡単に脆弱な環境を作れました。すぐにバージョンアップしないと危険です！**

脆弱性に対するSpring公式サイトの解説

https://spring.io/blog/2021/12/10/log4j2-vulnerability-and-spring-boot


# 題材

公式の[Getting Started Guides](https://spring.io/guides)の中にある[Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)をベースにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/43c562fd-3989-fc82-ed2d-5ae8f08426f1.png)


* GitHubからソースコードの取得

https://github.com/spring-guides/gs-rest-service/archive/main.zip
`complete`フォルダー内に完成したソースが含まれます。

```
│  build.gradle
│  gradlew
│  gradlew.bat
│  manifest.yml
│  mvnw
│  mvnw.cmd
│  pom.xml
│  settings.gradle
│
├─.mvn
│  └─wrapper
│          maven-wrapper.jar
│          maven-wrapper.properties
│
├─gradle
│  └─wrapper
│          gradle-wrapper.jar
│          gradle-wrapper.properties
│
└─src
    ├─main
    │  └─java
    │      └─com
    │          └─example
    │              └─restservice
    │                      Greeting.java
    │                      GreetingController.java
    │                      RestServiceApplication.java
    │
    └─test
        └─java
            └─com
                └─example
                    └─restservice
                            GreetingControllerTests.java
```

# ログ出力にLog4J2を使うように修正

Log4j2を使うように変更します。バージョンは脆弱性のある`2.14.0`です。

https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.logging.log4j


```diff:pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.2</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>rest-service-complete</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>rest-service-complete</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
+		<log4j2.version>2.14.0</log4j2.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter</artifactId>
+			<exclusions>
+				<exclusion>
+					<groupId>org.springframework.boot</groupId>
+					<artifactId>spring-boot-starter-logging</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
```

HTTPリクエストのHTTPヘッダーをログ出力するように変更

```diff:GreetingController.java
package com.example.restservice;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

 
+ import java.util.Map;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ import org.springframework.web.bind.annotation.RequestHeader;


@RestController
public class GreetingController {


+	static protected Logger logger = LoggerFactory.getLogger(GreetingController.class);

	private static final String template = "Hello, %s!";
	private final AtomicLong counter = new AtomicLong();

	@GetMapping("/greeting")
-	public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
+	public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name,
+			@RequestHeader Map<String, String> headers) {
+
+		headers.forEach((key, value) -> {
+			logger.info(String.format("Header '%s' = %s", key, value));
+		});

		return new Greeting(counter.incrementAndGet(), String.format(template, name));
	}
}
```

なんとこれだけで、脆弱です。

起動します。

```console
./mvnw spring-boot:run
```

# 確認

トレンドマイクロさんが、チェックサイトを用意しているのを見つけましたので、これを使って確認してみます。

https://log4j-tester.trendmicro.com/

こんな感じで、サイトから直接リクエストを投げてチェックできます。
今回はlocalhostで起動しているので、右側のcURLスクリプトを生成して、実行します。

![log4j-tester.trendmicro.com_(iPad) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/3b38493d-5099-8981-7e4a-00d89f4d1423.png)

結果はこんな感じで表示されます。

![log4j-tester.trendmicro.com_(iPad).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/2ea57d58-131c-dccd-dc65-22db12a7b9ea.png)

Log4J2の`2.14.0`を使っていると脆弱であることがわかります。
`pom.xml`のバージョンを`2.15.0`にあげて再実行すると、脆弱性は検出されませんでした。

怖いですね。すぐにバージョンアップしましょう。