Java: EasyBuggy - 30分でわかる！XMLエンティティ拡張(XEE)の脆弱性

# 概要

[EasyBuggy](https://github.com/k-tamura/easybuggy/blob/master/README.jp.md)または[EasyBuggy Boot](https://github.com/k-tamura/easybuggy4sb/blob/master/README.jp.md)を利用して、XMLエンティティ拡張(XEE)の脆弱性をシミュレートし、その修正を試みます。

環境構築はこちらの記事から。

https://qiita.com/flyaway/items/4922af5dbaafa1942e88

## 注意事項

本記事では脆弱性をついた攻撃手法について解説しています。

しかし、実際に第三者が運用しているWebサービスなどに対して、勝手に脆弱性の検査をおこなうのは違法行為となる可能性が非常に高いです。無害な検査用文字列を送信しているだけのつもりであっても、意図しない破壊を招いたり、監視システムによって攻撃と勘違いされる可能性があります。

絶対にやめましょう。

参考事例: [脆弱性検査について](https://www.whitehackerz.jp/blog/%E8%84%86%E5%BC%B1%E6%80%A7%E6%A4%9C%E6%9F%BB%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/)

# 脆弱性を確認する

EasyBuggyを起動し、`脆弱性 > XEE (XMLエンティティ拡張)`を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/5b46b4b7-50f3-f915-d4b0-d4940c0f1992.png)

XMLファイルをアップロードし、ユーザーを一括登録する機能のようです。
しかし、アップロードされたXMLファイルを処理する実装に脆弱性があります。

今回は、サーバーのCPUリソースに高負荷を与える攻撃をしてみます。
Wikipediaでは`Billion laughs attack`とも紹介されています。

https://en.wikipedia.org/wiki/Billion_laughs_attack

## プロファイリングツールの準備

サーバのCPUリソースをプロファイリングするために、下記のいずれかのツールを起動します。

Windowsであれば、`Javaのインストールフォルダ\bin`内に、下記のようなファイルがあると思います。もし存在しなければ、ダウンロードします。

|プロファイリングツール名|ファイル名|特徴|ダウンロード先(例)|
|----|----|----|----|
|[VisualVM](https://qiita.com/koduki/items/eb1ed4bdf0c24e14b0d8#visualvm)|jvisualvm.exe または visualvm.exe|軽い、低機能|https://visualvm.github.io/download.html|
|[JDK Mission Control(JMC)](https://qiita.com/koduki/items/eb1ed4bdf0c24e14b0d8#jdk-mission-controljmc)|jmc.exe|やや重い、高機能|https://adoptopenjdk.net/jmc|

### VisualVMの場合

1. Applicationsタブにて、アプリケーションを選択します
    - EasyBuggyの場合は `Tomcat` を選択
    - EasyBuggy Bootの場合は `org.t246osslab.easybuggy4sb.Easybuggy4sbApplication` を選択
1. Monitorタブを選択し、CPU欄を表示します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/b40bf27f-cc35-e367-81e5-261606dfac06.png)

### JDK Mission Control(JMC)の場合

1. JVMブラウザタブにて、アプリケーションを選択します
    - EasyBuggyの場合は `org.apache.catalina.startup.Bootstrap start` を選択
    - EasyBuggy Bootの場合は `org.t246osslab.easybuggy4sb.Easybuggy4sbApplication` を選択
1. `MBeanサーバー` を選択します
1. 選択したサーバーのダッシュボードやプロセッサ欄を表示します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/6e80770a-da31-23d9-c8a5-281590d99088.png)

## ファイルのアップロード

EasyBuggyのページ内に記載されているXMLはtypoがあるのと、ちょっと長いです。
このため、[Wikipediaページに記載されていたXMLファイル](https://en.wikipedia.org/wiki/Billion_laughs_attack#Code_example)を作成し、アップロードしてみます。

```xml:XEEの脆弱性を攻撃するXMLファイル
<?xml version="1.0"?>
<!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ELEMENT lolz (#PCDATA)>
 <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
```

アップロード操作をおこなうと、サーバの処理に時間がかかり、なかなかレスポンスが返りません。
プロファイリングツールを確認すると、アップロード前は落ち着いていたCPU使用率が上昇し続けていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/50118f0c-c0be-b630-d405-5cb845615c79.png)

このような状態が続くと、サーバーを利用しているほかの利用者の処理が遅くなる可能性があります。
今回は、Eclipseからサーバーを終了させましょう。

# 脆弱性を修正する

[EasyBuggy](https://github.com/k-tamura/easybuggy/blob/master/README.jp.md)でも[EasyBuggy Boot](https://github.com/k-tamura/easybuggy4sb/blob/master/README.jp.md)でも同じ実装内容になっています。

EasyBuggyの場合は、XEEandXXEServletクラスに問題となる実装があります。
EasyBuggyの場合は、XEEandXXEControllerクラスに問題となる実装があります。

## 脆弱性の原因

利用しているXMLパーサーのデフォルト設定で、XEEが有効になっているためです。
このため、XEEを悪用して攻撃ができてしまいます。

## 具体的な修正方法

機能の目的から考えて、XEEを含むXMLファイルを処理する必要はありません。
このため、XEEを明示的に無効にすることで修正をおこないます。

JavaではいくつかのXMLを処理するパーサーがありますが、それぞれによって修正方法が少しずつ異なります。基本的に下記のページを参考にして修正すると良いでしょう。

https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxp-documentbuilderfactory-saxparserfactory-and-dom4j

ページ内に `For a syntax highlighted example code snippet using SAXParserFactory, look here.` とあります。EasyBuggyでは`SAXParserFactory`を利用しているので、指示に従います。

https://gist.github.com/asudhakar02/45e2e6fd8bcdfb4bc3b2

どうやら、下記の1行を追加してやれば良いようですね。

```java:DOCTYPE宣言を許可しない
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
```

DOCTYPE宣言内にXMLエンティティ拡張を入れることで攻撃しているわけですから、DOCTYPE宣言自体を禁止してしまえばよいようです。

修正を反映し、再度、動作確認します。
正しく修正できていれば、すぐに応答が返ってきて、処理に失敗した旨のメッセージが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/4d4e8472-6964-13ff-dbdb-2a537cc65a45.png)
もしかしたら「もう少し詳しいエラーメッセージを用意するべきか？」とも感じるかもしれません。
しかし、相手は悪意をもって攻撃をしてきているわけです。
攻撃者に対して、わざわざ親切なエラーメッセージを表示してやる必要はないでしょう。