脆弱性を攻撃してみよう (1) OSコマンドインジェクション (OGNL式インジェクション)

## はじめに
**脆弱性を理解するには、実際に脆弱性を攻撃してみるのが一番です。**

といっても、脆弱性のありそうなサイトを見つけて攻撃してみよう！と言っているわけではありません。自分だけが使っている仮想マシンの上で、脆弱性のあるアプリケーションを動かし、攻撃してみることをお勧めします。

脆弱性は、以前紹介した[バグだらけのWebアプリケーション](http://qiita.com/tamura__246/items/7275c7406706fb0057e8)にたくさん実装してあります。Webアプリケーションは[ここ](https://github.com/k-tamura/easybuggy/releases)からダウンロードして、次のコマンドで起動します。

```bash
java -jar easybuggy.jar
```

※実行するにはJavaが必要です。詳細については、[こちらのページ](https://t246osslab.wordpress.com/2017/03/14/easybuggy-%e3%81%ae%e3%83%88%e3%83%aa%e3%82%bb%e3%83%84/)を参照して下さい。

このWebアプリケーションは、現時点で以下の脆弱性を実装しています。

 - XSS (クロスサイトスクリプティング)
 - SQLインジェクション
 - LDAPインジェクション
 - コードインジェクション
 - OSコマンドインジェクション
 - メールヘッダーインジェクション
 - Nullバイトインジェクション
 - サイズ制限の無いファイルアップロード
 - 拡張子制限の無いファイルアップロード
 - オープンリダイレクト可能なログイン画面
 - ブルートフォース攻撃可能なログイン画面
 - セッション固定攻撃可能なログイン画面
 - 親切過ぎる認証エラーメッセージ
 - 危険なファイルインクルード
 - パストラバーサル
 - 意図しないファイル公開
 - CSRF (クロスサイトリクエストフォージェリ)
 - クリックジャッキング
 - XEE (XMLエンティティ拡張)
 - XXE (XML外部エンティティ)

今回はこの中から**「OSコマンドインジェクション」**(より正確に言うと、「OGNL式インジェクション」)を攻撃して、サーバーに致命的なダメージを与えたいたいと思います:smiley:

## OSコマンドインジェクションとは

OSコマンドインジェクションとは、Webアプリケーションなどを経由してサーバーのOSコマンドを実行する攻撃を指します。

![oscmdinjct.png](https://qiita-image-store.s3.amazonaws.com/0/43869/fd1ba184-364b-ef25-28b4-67c4d666ea0d.png)

例えば、Webアプリケーションが特定のリクエストパラメータを未検証のままOSのコマンドの引数に渡し、実行していたとします。一般のユーザーは通常の使い方しかしないので問題ないかもしれませんが、悪意のあるユーザーは「`;`」(セミコロン)などの区切り文字とともに「`rm -fr /`」のような文字列を付加したパラメータを送信して、サーバーのファイルを全て削除してしまうかもしれません。

## 攻撃してみよう

では、さっそくOSコマンドインジェクションの脆弱性を攻撃してみましょう。

Webアプリケーションを[ここ](https://github.com/k-tamura/easybuggy/releases)からダウンロードして、`java -jar easybuggy.jar`で起動します。なお、今回はSELinuxを無効にしたCentOS 6に、コマンドの実行権限がある`root`ユーザーでログインしています。

:::note info
この記事では、バージョン1.3.2を使用しています。今後のリリースで動作は変わる可能性があります。
:::

起動したら、[http://localhost:8080](http://localhost:8080)にアクセスして下さい。以下のような画面の真ん中に「脆弱性」と書かれたセクションがあります。

![main.png](https://qiita-image-store.s3.amazonaws.com/0/43869/c3eae6bc-7580-9917-72fb-990c3965452a.png)

この中の上から5番目に「OSコマンドインジェクション」のリンクがあるので、クリックします。

クリックすると、次のような画面が表示されます。

![ognl1.png](https://qiita-image-store.s3.amazonaws.com/0/43869/be36eedd-78e1-c3cd-cc1e-217af169b022.png)

数式を入力すると、その答えを表示するという単純な機能です。数式には`java.lang.Math`を使用することができます。

まずは`1 + 2`や`Math.sqrt(5)`などの簡単な数式を入力してみて下さい。正しい答えが返ってくるはずです。次に`abc`などの数式として不正な値を入力して下さい。エラーメッセージが表示されます。

![err1.png](https://qiita-image-store.s3.amazonaws.com/0/43869/14230371-8cc7-2b86-4543-31b22fbcca67.png)

この機能は一見正常に動作するように見えます。

しかし、画面下部の:information_source:に記載されているように`@Runtime@getRuntime().exec('rm -fr /your-important-dir/')`を入力し、計算ボタンをクリックすると、サーバー上のディレクトリ(`/your-important-dir/`)が削除されてしまいます。

:::note warn
/your-important-dir/は、サーバー上の削除してもいいディレクトリへの絶対パスにするか、削除する前にバックアップを取得して下さい。また、Windowsの場合は、rm -frコマンドの代わりにrmdir /s /qコマンドを使って下さい。
:::

では、実際にやってみます。対象のディレクトリは`/etc`にします。`ll`(`ls -la`)コマンドで現在の`/`配下のディレクトリ構成を確認すると、以下のようになっています。

```bash
$ ll /
合計 102
dr-xr-xr-x.   2 root root  4096  4月 23 03:46 2017 bin
dr-xr-xr-x.   5 root root  5120  4月 26 21:53 2017 boot
drwxr-xr-x.  20 root root  3820  6月  1 22:57 2017 dev
drwxr-xr-x. 119 root root 12288  6月  1 22:57 2017 etc
drwxr-xr-x.   4 root root  4096  4月  2 00:41 2016 home
dr-xr-xr-x.  11 root root  4096  4月 19 21:20 2017 lib
dr-xr-xr-x.  10 root root 12288  4月 23 03:46 2017 lib64
drwx------.   2 root root 16384  8月  8 01:21 2015 lost+found
drwxr-xr-x.   2 root root  4096  3月 18 20:24 2017 media
drwxr-xr-x.   4 root root  4096 11月 15 18:00 2015 mnt
drwxr-xr-x.   8 root root  4096  4月  1 21:49 2017 opt
dr-xr-xr-x. 277 root root     0  6月  1 22:56 2017 proc
dr-xr-x---.  78 root root  4096  6月  2 07:39 2017 root
dr-xr-xr-x.   2 root root 12288  4月 20 03:27 2017 sbin
drwxr-xr-x.   7 root root     0  6月  1 22:56 2017 selinux
drwxr-xr-x.   2 root root  4096  9月 23 20:50 2011 srv
drwxr-xr-x   13 root root     0  6月  1 22:56 2017 sys
drwxrwxrwx.   3 root root  4096  6月  2 07:41 2017 tmp
drwxr-xr-x.  14 root root  4096  9月 23 08:32 2016 usr
drwxr-xr-x.  23 root root  4096 10月  5 17:12 2016 var
```

実行する前にバックアップを取っておきましょう。

```bash
$ cp -pr /etc etc_bk
```

`@Runtime@getRuntime().exec('rm -fr /etc')`を入力し、計算ボタンをクリックします。

![rmetc1.png](https://qiita-image-store.s3.amazonaws.com/0/43869/19cac30c-896f-a3e7-56f2-07c74de1a5bd.png)

そして、もう一度`ll`コマンドを実行します。

```bash
$ ll /
合計 90
dr-xr-xr-x.   2 0 0  4096  4月 22 18:46 2017 bin
dr-xr-xr-x.   5 0 0  5120  4月 26 12:53 2017 boot
drwxr-xr-x.  20 0 0  3820  6月  1 13:57 2017 dev
drwxr-xr-x.   4 0 0  4096  4月  1 15:41 2016 home
dr-xr-xr-x.  11 0 0  4096  4月 19 12:20 2017 lib
dr-xr-xr-x.  10 0 0 12288  4月 22 18:46 2017 lib64
drwx------.   2 0 0 16384  8月  7 16:21 2015 lost+found
drwxr-xr-x.   2 0 0  4096  3月 18 11:24 2017 media
drwxr-xr-x.   4 0 0  4096 11月 15 09:00 2015 mnt
drwxr-xr-x.   8 0 0  4096  4月  1 12:49 2017 opt
dr-xr-xr-x. 296 0 0     0  6月  1 13:56 2017 proc
dr-xr-x---.  78 0 0  4096  6月  9 14:09 2017 root
dr-xr-xr-x.   2 0 0 12288  4月 19 18:27 2017 sbin
drwxr-xr-x.   7 0 0     0  6月  1 13:56 2017 selinux
drwxr-xr-x.   2 0 0  4096  9月 23 11:50 2011 srv
drwxr-xr-x   13 0 0     0  6月  1 13:56 2017 sys
drwxrwxrwx.   8 0 0  4096  6月  8 14:31 2017 tmp
drwxr-xr-x.  14 0 0  4096  9月 22 23:32 2016 usr
drwxr-xr-x.  23 0 0  4096 10月  5 08:12 2016 var
```

`/etc`というディレクトリは無くなりました。これがOSコマンドインジェクションです。ここでは`/etc`を削除しましたが、**もちろん他のディレクトリも削除できますし、`rm`コマンド以外のコマンドも使えます。OSのコマンドを操れるので、いろいろな攻撃が考えられます。**

## 攻撃者はどのように脆弱性を見つけるか

「とはいえ、問題を起こす文字列(`@Runtime@...`)を攻撃者は知ることができないのでは??」と思った方もいるかと思います。このアプリケーションでは、あえて脆弱性の攻撃方法を画面上に記載していますが、通常のアプリケーションには当然そのようなものはありません。攻撃者はどのように脆弱性を見つけるのでしょうか？

**ヒントはエラーメッセージにあります。**エラーメッセージは攻撃者にアプリケーションの実装を推測させる材料にもなりえます。

いろいろな種類の不正な入力値でエラーメッセージを表示させてみましょう。例えば、この画面で`Math.sqrt(5x)`と入力して計算ボタンをクリックしてみると、次のようなエラーが表示されます。

![sqrt5x.png](https://qiita-image-store.s3.amazonaws.com/0/43869/3b93ad02-396f-41d4-19ac-48e73dbcd39b.png)

「不正な数式です」の後に英語のメッセージが続いています。アプリケーションの開発経験がある人であれば、「不正な数式です」の後に、何らかのライブラリが返したエラーメッセージをそのまま連結しているのではないか、と推測するのではないでしょうか。

次は、`Math`を完全修飾クラス名にして、`java.lang.Math.sqrt(5)`と入力し、計算ボタンをクリックしてみます。

![javalangMathsqrt5.png](https://qiita-image-store.s3.amazonaws.com/0/43869/3de9195c-8fb6-2f0f-1fc3-e6a9b4e13ee1.png)

入力していないはずの「`@`」(アットマーク)が入力されたことを示すようなエラーメッセージが出力されました。「`@`」には何か意味がありそうです。

さらに、`Math.`を付けずに`sqrt(5)`と入力して計算ボタンをクリックしてみましょう。次のようなエラーが表示されます。

![sqrt5.png](https://qiita-image-store.s3.amazonaws.com/0/43869/1d329b43-36ed-764d-40e7-0f0c5d13fc2c.png)

今度は、入力していない「`ognl.OgnlContext`」というキーワードが現れました。これを見て、知識のある人であれば、この機能を実現しているのが「**OGNL**」という技術であると推測できます。OGNLはJavaに似た文法の式言語のライブラリです。

[OGNLの仕様](https://commons.apache.org/proper/commons-ognl/language-guide.html)を見てみると、以下のような記述があります。

> **Calling Static Methods**
You can call a static method using the syntax @class@method(args). 

静的なメソッド呼び出しは`@class@method(args)`で実現できるようです。

「ということは...アプリケーションの内部では、次のように入力値の中にある`Math.`を`@Math@`に置換して、OGNL式として実行しているだけかもしれない」という推測ができます。

`Math.sqrt(5)` → `@Math@sqrt(5)`に置換 → OGNL式として実行

この推測が正しいか確認するために、`@System@currentTimeMillis()`を入力してみましょう。

`@System@currentTimeMillis()` → `@System@currentTimeMillis()`のまま(置換されず) → OGNL式として実行

正しければ、1970年1月1日0時からの経過時刻をミリ秒で取得できるはずです。

![sct.png](https://qiita-image-store.s3.amazonaws.com/0/43869/39b1df64-1112-6cdb-fed3-147b0c7f03d9.png)

結果が示す通り、推測が正しい可能性が高いと判断できます。

ここまできたら、「`@System@exit(0)`」と入力してWebアプリケーションのプロセスをシャットダウンさせるか、それともその前に...:sunglasses:といろいろなことが想像できます。

## どのような実装になっているか

実際にどのような実装になっているのでしょうか。[ソースコード](https://github.com/k-tamura/easybuggy/blob/master/src/main/java/org/t246osslab/easybuggy/vulnerabilities/OGNLExpressionInjectionServlet.java)を見てみましょう。重要な部分は以下です。

```java
try {
    Object expr = Ognl.parseExpression(expression.replaceAll("Math\\.", "@Math@"));
    value = Ognl.getValue(expr, ctx);
} catch (OgnlException e) {
    isValid = false;
    if (e.getReason() != null) {
        errMessage = e.getReason().getMessage();
    }

```

推測の通り、`Math.`を`@Math@`に置換して、OGNL式として実行しているだけです。

ちなみに、今回実行したのはOSコマンドインジェクションですが、Javaのコードも実行できるため、「**コードインジェクション**」と言うこともできます。さらに、より詳細に分類すると「**OGNL式インジェクション**」とも言えます。

## OGNL式インジェクションについて

OGNL式インジェクションの名前を広めたのは、Webアプリケーションのフレームワークとして有名な「**Struts 2**」です。今年の3月にも、OGNL式インジェクションの脆弱性がStruts 2に見つかり、複数のウェブサイトにおいて情報漏洩等の被害が発生しました。日本のサーバーにも、海外から大量の不正リクエストが送信されてきたという噂です。私もこの脆弱性は実際に試してみましたが(もちろんローカルのStrutsアプリで)、**非常に簡単で危険性の高い攻撃ができる**ものでした。

Struts 2の脆弱性として報告されるもののうち、かなりの割合を占めるのがこの脆弱性です。Struts 2のいろいろな箇所でOGNL式が利用されており、各箇所でOGNL式インジェクションが起きないように正規表現を使って、式の妥当性チェックを行っています。しかし、脆弱性を対策した正規表現が公開されても、それをかいくぐるような新しい文字列での攻撃方法が見つかり、なかなか根本解決に至っていないのが現状です。

## OSコマンド/コードインジェクションの対策

では、どのような対策をすればいいでしょうか？対策として思いつくのは、以下のようなことです。

 - そもそもそのような危険性を含む機能はつくらない(設計の段階で却下)
 - 別の実装方法を検討する
 - 実装を特定されるようなエラーメッセージをユーザーに返さない
 - 入力値の妥当性チェックを実施する
 - Webアプリケーションを適切なユーザー権限で実行する(Tomcatユーザー権限など)
 - OSの機能で保護する(Unix chroot jail、AppArmor、SELinuxなど)
 - JVMの機能で保護する(SecurityManager)

この中のいくつかを実際にやってみましょう。

### 適切なユーザー権限で実行する

`root`ユーザー以外でWebアプリケーションを実行していたら、どうなるでしょうか？`tomcat`ユーザーに変更して、確認してみましょう。

```bash
$ su tomcat
```

Webアプリケーションを起動したら、`@Runtime@getRuntime().exec('rm -fr /etc')`と入力して、計算ボタンをクリックします。エラーは表示されませんでした。どうなったのでしょうか？

```bash
$ ll /
合計 102
dr-xr-xr-x.   2 root root  4096  4月 23 03:46 2017 bin
dr-xr-xr-x.   5 root root  5120  4月 26 21:53 2017 boot
drwxr-xr-x.  20 root root  3820  6月  1 22:57 2017 dev
drwxr-xr-x. 119 root root 12288  6月  1 22:57 2017 etc
drwxr-xr-x.   4 root root  4096  4月  2 00:41 2016 home
dr-xr-xr-x.  11 root root  4096  4月 19 21:20 2017 lib
dr-xr-xr-x.  10 root root 12288  4月 23 03:46 2017 lib64
drwx------.   2 root root 16384  8月  8 01:21 2015 lost+found
drwxr-xr-x.   2 root root  4096  3月 18 20:24 2017 media
drwxr-xr-x.   4 root root  4096 11月 15 18:00 2015 mnt
drwxr-xr-x.   8 root root  4096  4月  1 21:49 2017 opt
dr-xr-xr-x. 296 root root     0  6月  1 22:56 2017 proc
dr-xr-x---.  78 root root  4096  6月  9 23:09 2017 root
dr-xr-xr-x.   2 root root 12288  4月 20 03:27 2017 sbin
drwxr-xr-x.   7 root root     0  6月  1 22:56 2017 selinux
drwxr-xr-x.   2 root root  4096  9月 23 20:50 2011 srv
drwxr-xr-x   13 root root     0  6月  1 22:56 2017 sys
drwxrwxrwx.   8 root root  4096  6月  9 23:11 2017 tmp
drwxr-xr-x.  14 root root  4096  9月 23 08:32 2016 usr
drwxr-xr-x.  23 root root  4096 10月  5 17:12 2016 var
```

この通り、`/etc`は削除されていません。とはいっても、Webアプリケーションを動かすユーザーが実行できるコマンド(`rm -fr /home/tomcat/anydir`など)は、この攻撃でも実行できてしまいます。しかし、それだけでもかなり有効な対策であると言えます。

### OSの機能で保護する(SELinux)

SELinuxを有効にしていたら、OSコマンドインジェクションを抑止してくれるのでしょうか？もう一度`root`ユーザーに変更して、SELinuxを有効にします。

```bash
$ vi /etc/selinux/config
# SELINUX=disabled
SELINUX=enforcing
```

変更したら、CentOSを再起動します。Webアプリケーションを起動したら、`@Runtime@getRuntime().exec('rm -fr /etc')`と入力して、計算ボタンをクリックします。

```bash
$ ll /
合計 90
dr-xr-xr-x.   2 0 0  4096  4月 22 18:46 2017 bin
dr-xr-xr-x.   5 0 0  5120  4月 26 12:53 2017 boot
drwxr-xr-x.  20 0 0  3820  6月  1 13:57 2017 dev
drwxr-xr-x.   4 0 0  4096  4月  1 15:41 2016 home
dr-xr-xr-x.  11 0 0  4096  4月 19 12:20 2017 lib
dr-xr-xr-x.  10 0 0 12288  4月 22 18:46 2017 lib64
drwx------.   2 0 0 16384  8月  7 16:21 2015 lost+found
drwxr-xr-x.   2 0 0  4096  3月 18 11:24 2017 media
drwxr-xr-x.   4 0 0  4096 11月 15 09:00 2015 mnt
drwxr-xr-x.   8 0 0  4096  4月  1 12:49 2017 opt
dr-xr-xr-x. 296 0 0     0  6月  1 13:56 2017 proc
dr-xr-x---.  78 0 0  4096  6月  9 14:09 2017 root
dr-xr-xr-x.   2 0 0 12288  4月 19 18:27 2017 sbin
drwxr-xr-x.   7 0 0     0  6月  1 13:56 2017 selinux
drwxr-xr-x.   2 0 0  4096  9月 23 11:50 2011 srv
drwxr-xr-x   13 0 0     0  6月  1 13:56 2017 sys
drwxrwxrwx.   8 0 0  4096  6月  8 14:31 2017 tmp
drwxr-xr-x.  14 0 0  4096  9月 22 23:32 2016 usr
drwxr-xr-x.  23 0 0  4096 10月  5 08:12 2016 var
```

消えてしまいました...デフォルトでSELinuxが保護するディレクトリ(例えば、`/selinux`)以外は、保護してくれないようです。少なくともデフォルト設定のSELinuxを有効にしたところで、OSコマンドインジェクションに効果は無いと言えそうです。

### JVMの機能で保護する(SecurityManager)

Javaには悪意のあるユーザーからのJVMの操作を保護する「**SecurityManager**」という機能があります。これを有効にしていたら、どうなるのでしょうか？

SecurityManagerを有効にするには、easybuggy.jar起動時のオプションに以下を付加します。

```
-Djava.security.manager -Djava.security.policy=catalina.policy
```
<table width="100%"><tr><td>※`mvn`コマンドでEasyBuggyを起動する場合は、pom.xmlの以下の行のコメントを解除して下さい。

```xml
<!-- <argument>-Djava.security.manager</argument>
<argument>-Djava.security.policy=catalina.policy</argument> -->
```
</td></tr><table>

`catalina.policy`は[ここ](https://raw.githubusercontent.com/k-tamura/easybuggy/master/catalina.policy)からダウンロードして下さい。このファイルは、デフォルトではOSコマンドインジェクションを防ぐようになっていませんが、以下のように修正を行うことでそれを抑止できます。

**・ Linux (CentOS 6.3)の場合**

```
grant {
    // 全てのファイルへの全ての操作を許可せず、必要なものだけ許可する
    // permission java.io.FilePermission "<<ALL FILES>>", "write, read, execute, delete";
    permission java.io.FilePermission "-", "write, read, execute, delete";
    permission java.io.FilePermission "/usr/java/-", "write, read, execute";
    permission java.io.FilePermission "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.79.x86_64/-", "write, read, execute";
  ・・・

```

**Windowsの場合**

```
grant {
    // 全てのファイルへの全ての操作を許可せず、必要なものだけ許可する
    // permission java.io.FilePermission "<<ALL FILES>>", "write, read, execute, delete";
    permission java.io.FilePermission "-", "write, read, execute, delete";
    permission java.io.FilePermission "C:/Program Files/Java/-", "write, read, execute";
    permission java.io.FilePermission "C:/Windows/Sun/Java/-", "write, read, execute";
  ・・・

```

(※設定は、環境により異なります)

変更が完了したら、SecurityManagerを有効にするオプションを付加してWebアプリケーションを起動します。そして、`@Runtime@getRuntime().exec('rm -fr /etc')`と入力して、計算ボタンをクリックします。

![smrmetc.png](https://qiita-image-store.s3.amazonaws.com/0/43869/a3406adb-60a6-a1ac-8d97-20cbf47f62aa.png)

SecurityManagerにより、OSコマンドインジェクションは失敗しました。

```bash
$ ll /
合計 102
dr-xr-xr-x.   2 root root  4096  4月 23 03:46 2017 bin
dr-xr-xr-x.   5 root root  5120  4月 26 21:53 2017 boot
drwxr-xr-x.  20 root root  3820  6月  1 22:57 2017 dev
drwxr-xr-x. 119 root root 12288  6月  1 22:57 2017 etc
drwxr-xr-x.   4 root root  4096  4月  2 00:41 2016 home
dr-xr-xr-x.  11 root root  4096  4月 19 21:20 2017 lib
dr-xr-xr-x.  10 root root 12288  4月 23 03:46 2017 lib64
drwx------.   2 root root 16384  8月  8 01:21 2015 lost+found
drwxr-xr-x.   2 root root  4096  3月 18 20:24 2017 media
drwxr-xr-x.   4 root root  4096 11月 15 18:00 2015 mnt
drwxr-xr-x.   8 root root  4096  4月  1 21:49 2017 opt
dr-xr-xr-x. 296 root root     0  6月  1 22:56 2017 proc
dr-xr-x---.  78 root root  4096  6月  9 23:09 2017 root
dr-xr-xr-x.   2 root root 12288  4月 20 03:27 2017 sbin
drwxr-xr-x.   7 root root     0  6月  1 22:56 2017 selinux
drwxr-xr-x.   2 root root  4096  9月 23 20:50 2011 srv
drwxr-xr-x   13 root root     0  6月  1 22:56 2017 sys
drwxrwxrwx.   8 root root  4096  6月  9 23:11 2017 tmp
drwxr-xr-x.  14 root root  4096  9月 23 08:32 2016 usr
drwxr-xr-x.  23 root root  4096 10月  5 17:12 2016 var
```

さらに`catalina.policy`の次の行をコメントアウトすると、`System.exit(n)`も拒否できます。

```bash
permission java.lang.RuntimePermission "exitVM";
```

コメントアウトして、EasyBuggyを再起動したら、`@System@exit(0)`と入力して、計算ボタンをクリックします。

![exitvm.png](https://qiita-image-store.s3.amazonaws.com/0/43869/7f490b69-c623-d2db-9a1a-c016ae3a4584.png)

このようにJVMのシャットダウンも防ぐことができます。SecurityManagerは、設定が直感的に分かりやすいわけではないので、しっかり理解して使用しなければなりませんが、OSコマンドインジェクションやコードインジェクションには効果的な対策と言えます。


## 参考

 - [JVN iPedia 脆弱性対策情報データベース OSコマンドインジェクション](http://jvndb.jvn.jp/ja/cwe/CWE-78.html)
 - [OWASP Command Injection](https://www.owasp.org/index.php/Command_Injection)
 - [WAF Tech Blog Struts2が危険である理由](https://www.scutum.jp/information/waf_tech_blog/2017/03/waf-blog-046.html)