Dockerフォレンジック - 実行中のコンテナに加えられた変更を特定する

# はじめに
本稿では、[Pentester Academy](https://www.pentesteracademy.com/)が提供する「[Attack Defense](https://attackdefense.pentesteracademy.com/)」の無料ハンズオン（Free Labs）のうち、「[System Backdoor](https://attackdefense.pentesteracademy.com/challengedetailsnoauth?cid=1454)」に注目します。
演習に関する手順のみならず、その背景にあるDocker技術について補足を行っています。

# 用語解説
Dockerのフォレンジックを理解する上で、そのエコシステムを抑えておくことが重要です。インシデント発生時には、これらエコシステムを構成するコンポーネントを調査することで、一連のイベントを明らかにすることができます。

|用語|概要|
|:---|:---|
|Docker イメージ（Image）|コード、バイナリ、ランタイム、依存関係、設定ファイルなどアプリケーションの実行に必要なもの一式をまとめたものです。|
|Docker コンテナ（Container）|Dockerイメージを元に作成される仮想環境のこと。コンテナで動作しているプロセスは、ホストと他のコンテナから隔離（isolate）し続けるために、複数のカプセル化する機能をプロセスに対して追加します。|
|レイヤー|コンテナを作成すると変更可能なレイヤーが新しく作成され、その上でプロセスが動作します。コンテナに対して新たに加えられたり修正されたりしたデータは、すべて書き込みレイヤーに保存されます。 コンテナが削除されると、その書き込みレイヤーも同じく削除されます。|
|チェックポイント|実行中のコンテナ状態（メモリ情報など）をチェックポイントで固定できます。dumpにより、ディスクへ書き出すことも可能です。|
|リストア|書き出した情報を読み込み、コンテナを実行することが可能です。|
|ネットワーク|Dockerでは、1コンテナでは1プロセスを動かす設計です。複数のプロセスを協調して動作させる場合、ソケットではなく、ネットワークで通信を行うことが推奨されています。|

:::note info
「Docker イメージ」、「Docker コンテナ」は単に「イメージ」、「コンテナ」と呼ぶことが多いです。
:::

# ケーススタディ

## 共通する基本列挙

さまざまなDockerフォレンジックケースおいて共通する、基本的な列挙事項を確認します。

### Step 1: 実行中のコンテナ一覧を確認

まず、実行中のコンテナ一覧を確認します。

**Command:** [docker ps](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/ps/)

**オプション**

|名前／省略形|説明|
|:---|:---|
|--all , -a|コンテナすべてを表示します。（デフォルトは実行中コンテナのみ。）|

```shell
root@localhost:~# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
e5813268132b        lamp-wordpress      "./run.sh"          6 minutes ago       Up 6 minutes        80/tcp              wordpress
root@localhost:~#
```

## 上書きされたアーティファクトの復元

Dockerイメージから上書きされたアーティファクトの復元。実行中のDockerコンテナに加えられた変更を分析します。

### Step 1: 変更履歴の概要を確認する

**Command:** [docker history](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/history/)

**オプション**

|名前／省略形|説明|
|:---|:---|
|--no-trunc|詳細出力を行います。|

```shell
student@localhost:~$ docker history --no-trunc ubuntuderived
IMAGE                                                                     CREATED             CREATED BY                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 SIZE                COMMENT
sha256:1b0b3bfeee1b5e1ab7842c7721725681df978c9e886ad3f279dbdb04a141d84c   2 years ago         /bin/sh -c chmod +x /bin/bash                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              1.11MB              
<missing>                                                                 2 years ago         /bin/sh -c echo "Overwritten" > /root/flag                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 12B                 
<missing>                                                                 2 years ago         /bin/sh -c #(nop) WORKDIR /root                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            0B                  
<missing>                                                                 2 years ago         /bin/sh -c md5sum /bin/bash > /root/flag                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   44B                 
<missing>                                                                 2 years ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       0B                  
<missing>                                                                 2 years ago         /bin/sh -c mkdir -p /run/systemd && echo 'docker' > /run/systemd/container                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 7B                  
<missing>                                                                 2 years ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /usr/sbin/policy-rc.d  && echo 'exit 101' >> /usr/sbin/policy-rc.d  && chmod +x /usr/sbin/policy-rc.d   && dpkg-divert --local --rename --add /sbin/initctl  && cp -a /usr/sbin/policy-rc.d /sbin/initctl  && sed -i 's/^exit.*/exit 0/' /sbin/initctl   && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup   && echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean  && echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean  && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean   && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages   && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes   && echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests   745B                
<missing>                                                                 2 years ago         /bin/sh -c [ -z "$(apt-get indextargets)" ]                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                987kB               
<missing>                                                                 2 years ago         /bin/sh -c #(nop) ADD file:a48a5dc1b9dbfc632f6cf86fe27b770b63f07a115c98c4465dc184e303a4efa1 in /                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           63.2MB              
student@localhost:~$
...
```

### Step 2: Dockerイメージをエクスポートする

**Command:** [docker save](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/save/)

```shell
student@localhost:~$ docker save ubuntuderived > image.tar
student@localhost:~$ ls -l
total 66148
-rw-rw-r-- 1 student student 67731968 Jan 28 22:19 image.tar
```

### Step 3: レイヤーの順序についてmanifest.jsonファイルを確認する

**Command:** cat manifest.json | python -m json.tool

`image.tar`を展開する

```shell
student@localhost:~$ tar -xf image.tar
student@localhost:~$ ls -l 
total 66188
drwxr-xr-x 2 student student     4096 Dec  5  2019 08de39d1ac185319b20c3ad53883b5c21200fab056074ac5d1d442faff04918c
-rw-r--r-- 1 student student     4017 Dec  5  2019 1b0b3bfeee1b5e1ab7842c7721725681df978c9e886ad3f279dbdb04a141d84c.json
drwxr-xr-x 2 student student     4096 Dec  5  2019 27a911bb510bf1e9458437f0f44216fd38fd08c462ed7aa026d91aab8c054e54
drwxr-xr-x 2 student student     4096 Dec  5  2019 b560a3d372ba4276e6b07e827f1ec5a8d019936d168528eb4546e66283093678
drwxr-xr-x 2 student student     4096 Dec  5  2019 b7a6351ad136b46a550495d4048d63458557138c16303bf718bb7b41580264c6
drwxr-xr-x 2 student student     4096 Dec  5  2019 cc59b0ca1cf21d77c81a98138703008daa167b1ab1a115849d498dba64e738dd
drwxr-xr-x 2 student student     4096 Dec  5  2019 d80735acaa72040a0a98ca3ae6891f9abb4e2f5d627b4099c4fefdc3ce1e696e
drwxr-xr-x 2 student student     4096 Dec  5  2019 e2b070f4dd10244735bfe0eb7a976791c90ab2f687177acd2b8b6eab481f6b0a
-rw-rw-r-- 1 student student 67731968 Jan 28 22:19 image.tar
-rw-r--r-- 1 student student      671 Jan  1  1970 manifest.json
-rw-r--r-- 1 student student       96 Jan  1  1970 repositories
```

`manifest.json`ファイルを確認する

```shell
student@localhost:~$ cat manifest.json | python -m json.tool
[
    {
        "Config": "1b0b3bfeee1b5e1ab7842c7721725681df978c9e886ad3f279dbdb04a141d84c.json",
        "Layers": [
            "cc59b0ca1cf21d77c81a98138703008daa167b1ab1a115849d498dba64e738dd/layer.tar",
            "27a911bb510bf1e9458437f0f44216fd38fd08c462ed7aa026d91aab8c054e54/layer.tar",
            "d80735acaa72040a0a98ca3ae6891f9abb4e2f5d627b4099c4fefdc3ce1e696e/layer.tar",
            "e2b070f4dd10244735bfe0eb7a976791c90ab2f687177acd2b8b6eab481f6b0a/layer.tar",
            "08de39d1ac185319b20c3ad53883b5c21200fab056074ac5d1d442faff04918c/layer.tar",
            "b560a3d372ba4276e6b07e827f1ec5a8d019936d168528eb4546e66283093678/layer.tar",
            "b7a6351ad136b46a550495d4048d63458557138c16303bf718bb7b41580264c6/layer.tar"
        ],
        "RepoTags": [
            "ubuntuderived:latest"
        ]
    }
]
```

### Step 4: 上書きされる前のレイヤーについて確認する

## 実行中のコンテナに加えられた変更を特定する

「[System Backdoor](https://attackdefense.pentesteracademy.com/challengedetailsnoauth?cid=1454)」のシナリオでは実行中の WordPress Docker コンテナに侵害の疑いが示されています。このような場合、どのようなステップで調査を行っていくべきなのか、確認します。

### Step 1: コンテナのファイルシステム上にあるファイルやディレクトリの変更箇所を確認

コンテナのファイルシステム内にて、コンテナが生成された以降に、変更されているファイルやディレクトリの一覧を確認します。

**Command:** [docker diff](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/diff/)

変更内容は次の三種類が示されます。

|シンボル|内容説明|
|:---|:---|
|`A`|ファイルまたはディレクトリの追加|
|`D`|ファイルまたはディレクトリの削除|
|`C`|ファイルまたはディレクトリの変更|

```shell
root@localhost:~# docker diff wordpress
C /run
A /run/supervisor.sock
C /run/apache2
C /run/apache2/apache2.pid
C /run/mysqld
C /run/mysqld/mysqld.pid
A /run/mysqld/mysqld.sock
C /run/supervisord.pid
C /var
...
A /var/log/supervisor/mysqld-stdout---supervisor-9K_Z6Y.log
D /var/log/supervisor/apache2-stdout---supervisor-70UbBd.log
D /var/log/supervisor/mysqld-stderr---supervisor-qMyeIi.log
D /var/log/supervisor/mysqld-stdout---supervisor-vIhK7D.log
D /var/log/supervisor/apache2-stderr---supervisor-MMCU08.log
C /etc
C /etc/shadow
C /etc/php5
C /etc/php5/apache2
C /etc/php5/apache2/php.ini
C /tmp
A /tmp/do
root@localhost:~# 
```

### Step 2: 疑わしきファイルをローカルファイルシステムにコピー

`docker diff`コマンドの結果から、疑わしきファイルをローカルへダウンロードし、調査を行います。
ここでは、`C /etc/shadow`の結果に注目し、調査を行います。

**Command:** [docker cp](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/cp/)

```shell
root@localhost:~# docker cp wordpress:/etc/shadow .
```

変更箇所を明らかにするために、新しいコンテナを実行し、そこからファイルを抽出。オリジナルと比較することで確認することもできます。

```shell
root@localhost:~# docker run -d lamp-wordpress
8c6feb6a45be96a6252b3c4f8d336ea8be0b2a552621ec20dfde8fdab83b8444
root@localhost:~# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
8c6feb6a45be        lamp-wordpress      "./run.sh"          21 seconds ago      Up 11 seconds       80/tcp              boring_wilson
e5813268132b        lamp-wordpress      "./run.sh"          14 minutes ago      Up 13 minutes       80/tcp              wordpress
root@localhost:~# docker cp 8c6feb6a45be:/etc/shadow original_shadow
root@localhost:~# diff original_shadow shadow
21a22
> service:$./9/Kdyr/9BJ{BLOCKED}xV0:18231::::::
root@localhost:~#
```

### Step 3: コンテナ内でシェルを起動し探索

コンテナへアクセスし、調査を行うことも可能です。

**Command:** [docker exec](https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/exec/)

**オプション**

|名前／省略形|説明|
|:---|:---|
|--interactive , -i|アタッチされていなくても STDIN は開放し続けます。|
|--tty , -t|擬似 TTY を割り当てます。|

```shell
root@localhost:~# docker exec -it wordpress bash
root@e5813268132b:/#
```

# 参考情報
- Docker ドキュメント日本語化プロジェクト, http://docs.docker.jp/
- HackTricks, Docker Forensics, https://book.hacktricks.xyz/forensics/basic-forensic-methodology/docker-forensics

# Pentester Academy - Free Labs
Pentester Academyが提供する「[Attack Defense](https://attackdefense.pentesteracademy.com/)」では、「**コンテナセキュリティ（CONTAINER SECURITY）**」に関する次のラボが無料で提供されています。

- Docker Registry - [Insecure Docker Registry II](https://attackdefense.pentesteracademy.com/challengedetailsnoauth?cid=1025)
- Docker Registry - [Corrupting Source Image](https://attackdefense.pentesteracademy.com/challengedetailsnoauth?cid=1573)
- Docker Forensics - [Flag File Forensic Recovery I](https://attackdefense.pentesteracademy.com/challengedetailsnoauth?cid=1036)
- Docker Forensics - [System Backdoor](https://attackdefense.pentesteracademy.com/challengedetailsnoauth?cid=1454)