Dockerコンテナのpostgresqlがマルウェアに感染した件について

# 背景

Dockerコンテナを立てたらマルウェアに感染したのでサイバーセキュリティの啓蒙を兼ねてメモ書きしてみました。

# 注意事項

マルウェアに感染した被害の対処方法を記述しています。マルウェア自体の機能や解析の解説ではなく一般利用者ユーザーの視点から感染経路と対応方法についての記述になります。

# マルウェア感染状況

## 症状

Dockerコンテナを稼働させたホストのロードアベレージ(CPU負荷)が常時4を超える状況になっていました。つまり400%でホストがフル回転してた訳ですな。
例えるならエヴァンゲリオン初号機が暴走してマヤちゃんがコンソール画面に向かって叫んでいるところです（違）
こうなるとクラウドサービスのAWSとかだと英文で警告アラートが飛んで来ますし毎日課金されで膨大な利用料金請求が来ることになります。恐ろしい！！

## 状況の調査

CPUの利用状況やメモリの使用量などを調査するツール類がありますので、まずはCPU負荷を極端に使用しているサービスとプロセスを調査します。


### docker stats

各Dockerコンテナのリソース利用状況は「docker stats」コマンドで確認できます。

```
$ docker stats
```

実際にマルウェアに感染した状況は以下の通り。

![docker-stats202208-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35898/210ffde8-bad5-2dce-34d4-9dc3993d5b7e.png)

postgresのDockerコンテナのCPU負荷が400%超えています！
該当するDockerコンテナを停止すれば解消されますが原因の調査の為に次の確認作業をします。

### ps aux

ホスト側で稼働プロセスのCPU負荷状況を確認する為に「ps aux」コマンドを使用します。

```
$ ps aux
```

表示されたプロセス一覧の中からCPU負荷を極端に使用しているプロセスを探したところありました。

- 「/tmp/kinsing」
- 「/tmp/kdevtmpfsi」

この2つのプロセスがCPU負荷300%を超えていました。

# kinsing(kdevtmpfsi)マルウェア

このDockerマルウェアは感染したDockerホストで仮想通貨をマイニングしてCPU負荷を掛ける仮想通貨マイニングマルウェアです。ここではマルウェア自体の機能と解析の解説は記述しません。
詳しくは以下のリンク先を参考にしてください。

- [脅威：コンテナ環境を対象としたマルウェア「Kinsing」が増加中 #AquaSecurity #セキュリティ #コンテナ #マルウェア](https://www.creationline.com/lab/34036)
- [コンテナを標的にしたマルウェア、Aqua Security Softwareが攻撃手法を解説](https://atmarkit.itmedia.co.jp/ait/articles/2004/15/news056.html)

# 感染経路

誤って外部公開されたDocker APIが主な感染経路ですが他にも様々な脆弱性を利用して感染するので必ずしもDocker API経由とは限りません。
外部公開されたサービスポートの全てで感染経路は疑われます。

## 事象の分析

今回の感染状況から以下の事が推測出来ます。

- Docker APIは外部公開を有効化していない
- 勝手にDockerコンテナを作成されてはいない
- 複数あるDockerコンテナのうちpostgresのDockerコンテナだけに発生

どうやらDocker APIではなく既存のpostgresqlのDockerコンテナに原因がありそうです。
このpostgresqlコンテナは検疫された公式Dockerイメージなのでマルウェア混入は無いとは限りませんが調査の優先順位は低いです。
となると感染経路として外部公開されたサービスポートを疑うことが最優先です。

## サービスポートの外部開放

Dockerコンテナではサービスポートをオプションの「-p」でホスト側にポートフォワードして外部公開します。
同一ホスト内であればサービスポートを外部公開する事はありませんが、別のホストから参照する場合にはサービスポートを外部公開します。よくあるのがwebサービスのHTTP(80/TCP)やHTTPS(443/TCP)などがそうですね。
データベースのPostgreSQLやMySQLも別のホストから参照する為に外部公開する事があります。
今回のpostgresqlコンテナは「5432/TCP」サービスポートをホスト側にポートフォワードしています。

## ファイアウォール設定

一般的にサービスポートはファイアウォール設定で許可範囲を管理します。
その際にファイアウォールの設置箇所としては以下があります。

- ホストの外側
　クラウドのAWSではセキュリティグループ設定、オンプレ環境ではルーター機器やファイアウォール装置
- ホスト側
　Linuxのubuntuの場合はufwやiptables

一般公開するwebサービスは許可範囲を限定せずに「0.0.0.0/0」として外部開放しますがデータベースのサービスは参照元ホストをファイアウォールで限定すべきです。
今回はオンプレ環境のルーター機器でインターネット側のグローバルIPアドレスをホスト側にstatic NATしていましたのでホスト側でファイアウォール設定します。

## Dockerコンテナのファイアウォール設定の失敗

ホスト側のOSはUbuntu Serverなので一般的にufwを使ってファイアウォール設定します。
ところがDockerコンテナの場合はufwの設定に関わらずiptablesにて直接設定されます。
ufwでファイアウォール設定していたつもりがiptablesで外部公開されていたのが今回の感染経路の原因の1つでした。
そんな訳で外部から制限無く「5432/TCP」サービスポートに接続出来る状況でした。

正しくUbuntuでDockerコンテナのファイアウォール設定をする方法については以下の記事を作成していますので参考にして下さい。

- [Dockerのファイアウォール設定(ufwとiptables)](https://qiita.com/ohhara_shiojiri/items/e08076009cd3098a9deb)

## アカウント設定の失敗

外部公開されたサービスポートから脆弱性を突いてハッキング攻撃される事はよくあります。
今回の場合は検疫された公式Dockerイメージの最新版なので未知の脆弱性の可能性が無いとは限りませんが調査の優先順位は低いです。
それよりもサービスポートに接続してログインに成功さえすれば不正なプログラムを仕込む事は安易です。PostgreSQLのデータベースにもログイン認証が必要ですのでアカウント設定を見直します。
postgresのDockerコンテナはDocker Composeで作成していますが初期アカウント設定は以下になります。

```:compose.yaml
services:

  db:
    image: postgres:14.5
    container_name: postgres14
    ports: 
      - "5432:5432"
    environment:
      - POSTGRES_USER
      - POSTGRES_PASSWORD
```

「environment」の各変数「POSTGRES_USER」「POSTGRES_PASSWORD」でアカウント情報を渡しています。
実際のアカウント情報は別の「.env」ファイルに記述しています。
果たしてそこにあったアカウント情報はパスワードと共に「postgres」に設定していました。2つ目の原因はアカウント情報の不備でした。
これでは易々とデータベースにログインして不正なプログラムを仕掛ける事も可能でした。

# マルウェアの駆除方法

今回のマルウェアが仕掛けたプログラムを単に削除しても再度感染してしまうので順を追って駆除していきます。

## Dockerコンテナの停止と削除

postgresのDockerコンテナを停止して削除します。
これでホストのロードアベレージ(CPU負荷)は解消されます。

```
$ docker stop postgres14
$ docker rm postgres14
```

## マルウェアの削除

ホストのロードアベレージ(CPU負荷)は解消されますが不正プログラムはまだ残っていますので以下の様に探して削除します。

```
$ sudo find / -name kinsing
/var/lib/docker/overlay2/b076a.../diff/tmp/kinsing
/var/lib/docker/overlay2/b076a.../merged/tmp/kinsing
$ sudo rm /var/lib/docker/overlay2/b076a.../diff/tmp/kinsing
$ sudo rm /var/lib/docker/overlay2/b076a.../merged/tmp/kinsing

$ sudo find / -name kdevtmpfsi
/var/lib/docker/overlay2/b076a.../diff/tmp/kdevtmpfsi
/var/lib/docker/overlay2/b076a.../merged/tmp/kdevtmpfsi
$ sudo rm /var/lib/docker/overlay2/b076a.../diff/tmp/kdevtmpfsi
$ sudo rm /var/lib/docker/overlay2/b076a.../merged/tmp/kdevtmpfsi
```

# セキュリティ対策

再びマルウェアに感染しないようにセキュリティ対策をします。

## 正しくファイアウォールを設定する

サービスポートが意図と違って外部公開されていましたので正しくファイアウォール設定をします。
UbuntuでDockerコンテナのファイアウォール設定をする方法については以下の記事を作成していますので参考にして下さい。

- [Dockerのファイアウォール設定(ufwとiptables)](https://qiita.com/ohhara_shiojiri/items/e08076009cd3098a9deb)

ホストのサービスポートが外部公開されていないか無料で確認するサービスがSHODANなど複数ありますので利用しましょう。
別のホストからnmapコマンドを使用しても良いですね。

## 正しくアカウント設定する

簡単に類推できるようなパスワードではなく英数字記号を複数含む複雑で長い文字列のパスワードを設定します。

## 基本的なセキュリティ対策

使用しているOSやアプリケーションを常に最新版に更新して不要なサービスは停止するなど基本的なセキュリティ対策は当然行います。
しかし意図しない設定からハッキングされてサイバー攻撃を受ける事は個人や組織を問わず規模の大小に関わらず起こりえる事です。
今回の件は路傍の石かも知れませんが教訓として少しでも参考にして頂ければ幸いです。