LAC WATCH

セキュリティとITの最新情報

RSS

株式会社ラック

メールマガジン

サイバーセキュリティや
ラックに関する情報をお届けします。

テクニカルレポート | 

マルウェア「gokcpdoor」を用いた日本組織を狙う攻撃キャンペーン

ラックの脅威分析チームは、2022年4月頃から、KCPプロトコル※1をC2通信として利用する新たなマルウェア「gokcpdoor」を使用した攻撃活動を日本国内の製造業や学術機関などで確認しています。この攻撃活動は、中国を拠点とする攻撃者グループによるものと見られ、日本国内の組織や海外拠点へ同様の攻撃が行われている可能性がうかがえます。

※1 GitHub - skywind3000/kcp: :zap: KCP - A Fast and Reliable ARQ Protocol

そこで今回は、KCPプロトコルをC2通信として利用するgokcpdoorを利用した一連の攻撃キャンペーンをもとに、背後にある攻撃者像や同様の攻撃に対する検知や防御手法を紹介します。本内容は、2023年10月4日から6日に開催されたセキュリティカンファレンスVirus Bulletin Conference 2023(VB2023)にて、「Let's go door with KCP」というタイトルで詳細を発表しました※2

※2 Virus Bulletin :: Let's go door with KCP

KCPプロトコルと代表的なライブラリ

KCPプロトコルの概要と代表的なライブラリであるkcp-go※3について解説します。

※3 kcp package - github.com/xtaci/kcp-go - Go Packages

KCPプロトコル

KCPは、2011年にskywind3000氏によって設計・開発された自動再送要求(ARQ)を行うトランスポート層の通信プロトコルです。

KCP自体は下位のデータの転送方式を定義していませんが、KCPを使用する多くの実装では下位のプロトコルとしてUDPを採用しており、UDP上でTCPのような高信頼を確保しながら低遅延の通信を実現しています。このような特徴から、プロキシソフトウェアやオンラインゲーム、ストリーミングサービスなどのリアルタイム性が求められるソフトウェアやサービスで使用されています。

図1は、KCPプロトコルにおける単方向のデータ送信を表したものです。KCPメッセージには、4つのコマンドがあり、このうちIKCP_CMD_PUSHとIKCP_CMD_ACKは、データの送信と確認応答を示すためのコマンドで頻繁に使用されます。残りのIKCP_WASKとIKCP_CMD_WINSは、ウィンドウプローブとウィンドウ更新通知のためのコマンドで、ネットワークや受信者の負荷状況に応じて送信者がデータの転送を停止した際に、通信を再開するにあたり必要なものです。

図1 KCPプロトコルの通信イメージ
図1 KCPプロトコルの通信イメージ

図2は、単方向からKCPメッセージを送信した際にキャプチャしたパケットデータです。UDPのペイロードとしてKCPメッセージが送受信されており、赤色の箇所がデータの送信、青色の箇所がデータの受信を示しています。この図では、文字列"Message sent by Host-A"を送信しています。また、各データの先頭から5バイト目がコマンドを表しており、赤色の箇所の0x51(81)はIKCP_CMD_PUSH、青色の箇所の0x52(82)はIKCP_CMD_ACKです。

図2 UDPで転送されるKCPメッセージの例(単方向)
図2 UDPで転送されるKCPメッセージの例(単方向)

このように、KCPプロトコルに則った通信では平文でデータがやり取りされます。なお、KCPメッセージのデータ構造の詳細については、Appendixの「KCPおよびkcp-goの伝送データ構造」をご参照ください。

kcp-goライブラリ

KCPプロトコルに基づいた通信を提供するGo言語のライブラリの1つとして、kcp-goがあります(図3)。kcp-goは、前方誤り訂正やデータの暗号化などを備えており、これを用いると再送のコストを削減しつつUDP上で暗号化したKCPメッセージを送受信できるようになります。KCPに関するライブラリの中では最も人気が高く、gokcpdoorもC2通信を行うにあたってkcp-goを採用しています。

kcp-goの暗号化処理は、AESやBlowfish、Salsa20などをサポートしており、CFBモードで行われます。また、暗号化時にランダムな値(Nonce)をデータの先頭に付与するため、同じ平文であっても暗号化後のデータが毎回異なります。このため、kcp-goによって暗号化されたUDP通信をキャプチャしたとしても、KCPメッセージを判別することは困難です。

図3 kcp-goパッケージのドキュメント
図3 kcp-goパッケージのドキュメント

KCPプロトコルを利用するマルウェア

図4は、KCPプロトコルを実装するマルウェアをコンパイルタイムスタンプの情報を基にタイムラインで時系列にまとめたものです。2020年4月頃からマルウェア「Crosswalk」※4にKCPプロトコルが実装されて以降、当該プロトコルを利用するマルウェアを目にする機会が増加しています。

※4 Higaisa or Winnti? APT41 backdoors, old and new

一方、マルウェアを利用する攻撃者に焦点を当ててみると、多くのマルウェアがAPT41に関連していることもわかります。実は、これら多くのマルウェアは、KCPプロトコルを実際の攻撃活動に使用しているという報告はほとんどありません。このような状況の中、2022年3月、実際の攻撃活動で確認したgokcpdoorは、kcp-goライブラリを利用してKCPプロトコルでC2通信を行うマルウェアでした。

図4 KCPプロトコルが実装されるマルウェアのタイムライン
図4 KCPプロトコルが実装されるマルウェアのタイムライン

図5は、gokcpdoorにおけるKCPプロトコルの実装を確認するために、kcp-goライブラリのソースコード(kcp-go/kcp.go)と、gokcpdoorのprogram/kcp.(*KCP).Input関数のデコンパイルした擬似コードを比較したものです。gokcpdoorは、kcp-goのソースコードを利用していることが確認できます。

図5 kcp.goのソースコードとgokcpdoorのKCPプロトコル実装の比較(左:kcp.go/右:gokcpdoor)
図5 kcp.goのソースコードとgokcpdoorのKCPプロトコル実装の比較(左:kcp.go/右:gokcpdoor)

gokcpdoorの解析

gokcpdoorは、Go言語でコーディングされたバックドア型のマルウェアであり、Linux(ELF)版とWindows(PE)版を確認しています。C2通信は、前述した通り、KCPプロトコルを利用することが大きな特徴です。以降では、gokcpdoorの詳細な解析結果について解説します。

Windows版とLinux版の比較

はじめに、Linux版とWindows版のビルドバージョンを確認すると、いずれのバージョンもgo1.17.5でビルドされています(図6)。また、図7にある通り、コンパイル環境には「gokcpdoor1.0-20220301」という文字列が含まれていることがわかります。このことから当該マルウェアをgokcpdoorと命名しています。

図6 ビルドされたGo言語のバージョン
図6 ビルドされたGo言語のバージョン
図7 コンパイル環境に含まれる文字列(gokcpdoor1.0-20220301)
図7 コンパイル環境に含まれる文字列(gokcpdoor1.0-20220301)

次に、マルウェアの機能性を見てみると、こちらもLinux版とWindows版でどちらもほぼ同じ機能を有しています。ただし、Windows版には「main_WinExec」という名前の特徴的な関数が含まれています(図8)。

この関数は、文字通り、WinExec APIを呼び出すことで指定されたコマンドを実行するためのものであり、図9に示す通り、該当の関数でWinExecのアドレスを解決し、呼び出していることが確認できます。

図8 Linux版とWindows版の機能性の比較(左:Linux版/右:Windows版)
図8 Linux版とWindows版の機能性の比較(左:Linux版/右:Windows版)
図9 WinExecのアドレスを取得後、Syscall関数で実行
図9 WinExecのアドレスを取得後、Syscall関数で実行

バックドア機能

gokcpdoorは、Go言語のnet.ResolveUDPAddr関数※5およびnet.ListenUDP関数※6を使用して、ハードコードされたポート番号で待ち受けます(図10)。

※5 net package - net - Go Packages "ResolveUDPAddr"

※6 net package - net - Go Packages "ListenUDP"

図10 Go言語のnetパッケージを利用したポート開放
図10 Go言語のnetパッケージを利用したポート開放

開放するポート番号などの情報は、XOR演算およびBase64でエンコードされています。図11に示すLinux版のgokcpdoorサンプルの場合は、図上部のオフセット0x7aefd0(off_7AEFD0)に暗号化されたバイナリがあります。このデータをハードコードされたXORキーでXOR演算後、Base64でデコードを行うと、図下部のように開放アドレスとポートを表す"0.0.0.0:10054"(赤色の枠)と識別子を表す"nId2jUd3Ld1Fxe"(橙色の枠)を確認できます。

なお、識別子は、バックドアのコマンド操作開始時に使う固定文字列であり、これをバックドアに対して最初に送信することで、gokcpdoorがコマンドを受け付ける状態になります。

図11 暗号化されたポート番号および識別子のコード
図11 暗号化されたポート番号および識別子のコード

gokcpdoorがサポートするバックドアコマンドは20種類あり、図12のように実装されています。これらのコマンドには、任意コマンドの実行やダウンロード実行、任意ファイルのアップロード、ポートフォワードなどがあり、バックドアが動作する被害ホストを完全に制御できます。コマンド一覧およびその内容の詳細については、Appendixの「C2コマンド」をご参照ください。

図12 gokcpdoorのC2コマンドの実装コード
図12 gokcpdoorのC2コマンドの実装コード("back"および"exec")

通信データと暗号化処理

図13は、バックドアとC2サーバの間でやり取りされるC2コマンドおよび実行結果が、内部でUDPパケットにカプセル化されるまでの処理過程を示したものです。

C2コマンドなどのデータは、まずBase64エンコードされ、改行コードを末尾に付けた形式で、前述のkcp-goライブラリの送信処理に渡されます。その後、kcp-goライブラリによってKCPメッセージが生成され、そのKCPメッセージを組み込んだkcp-goフォーマットのデータが生成されます。そして暗号化後にUDPパケットのデータとして格納されます。

図13 C2コマンドおよび実行結果データの処理過程(一部)
図13 C2コマンドおよび実行結果データの処理過程(一部)

データの暗号化処理として、gokcpdoorはAES-256を使用します。図14は、gokcpdoorにおいてKCPプロトコルを利用したC2通信の暗号化処理を定義した部分のコードです。このコードでは、PBKDF2-HMAC-SHA1でハードコードされたパスワードとソルトなどから32バイトの鍵を導出し、その導出鍵をAES暗号化のためにNewAESBlockCrypt関数へ渡しています。gokcpdoorの通信データを復号する場合、この導出鍵(もしくは導出時のパラメータ)が必要となります。

図14 gokcpdoorにおける暗号化設定
図14 gokcpdoorにおける暗号化設定

類似マルウェア「gokcprat」

gokcpdoorを使用した攻撃活動を調査する過程で、利用しているライブラリやコード、含まれている文字列などが類似する「gokcprat」というマルウェアも確認しています(図15)。

gokcpratは、表1に示す通り、ビルドバージョンやVirus Totalの投稿時期から、gokcpdoorよりも前に開発された可能性が高く、また、コマンドの数がgokcpdoorより少ない特徴があります。また、機能面で見れば、gokcpdoorがポートを開放して外部からの接続を待ち受けるのに対し、gokcpratは外部へコールバック通信を発生させる点が大きく異なります。

図15 コンパイル環境に含まれる文字列(gokcprat1.0)
図15 コンパイル環境に含まれる文字列(gokcprat1.0)
比較要素 gokcpdoor gokcprat
ビルドバージョン go1.17.5 go1.16.6
サポートOS Linux, Windows Linux
通信手段 Listen Reverse
暗号化方法 PBKDF2 and AES-256 PBKDF2 and AES-256
コマンド数 20種類 15種類
通信プロトコル KCP KCP
Virus TotalにおけるFirst Submissions 2022年7月12日 2021年11月18日
表1 gokcpdoorとgokcpratの比較

攻撃者グループの考察

図16は、2021年から2022年にかけて確認したgokcpdoorに関連する攻撃手口の一例です。この攻撃者グループは、窃取した認証情報やクライアント証明書などを使用して、SSL-VPN経由で被害者のネットワークに侵入し、端末やサーバにマルウェアやツールセットを設置します。この事例では、gokcpdoorをはじめ、別のマルウェア「ABK downloader」※7やデュアルユースツール(PsExec、MimikatzやWinRAR)などが設置されていました。

※7 An Overhead View of the Royal Road | @nao_sec

図16 gokcpdoorの攻撃手口(一例)
図16 gokcpdoorの攻撃手口(一例)

攻撃者グループが使用するマルウェア

ABK downloaderは、ダウンローダ型マルウェアで、攻撃者グループTickが使用するマルウェアの1つです。今回の事例で見つかったABK downloaderは、次の動作を行うことを確認しています。

図17は、ABK downloaderの動作概要です。ABK downloaderは、TickやTonto Teamで利用されるマルウェア「OAED Loader」※8にXORで暗号化されて内包されています。このOAED Loaderは、DLLサイドローディングによって実行され、Process Hollowingを利用してABK downloaderをsvchost.exeなどの正規のプロセスにインジェクションし、動作させます。また、文字列「v|xI?1bW」をマーカーとして、以降のバイナリデータをXOR演算し、AKB downloaderを復号します(図18)。

※8 標的型攻撃の実態と対策アプローチ 日本を狙うサイバーエスピオナージの動向2020年度|Macnica Networks、TeamT5

図17 ABK downloaderの動作概要
図17 ABK downloaderの動作概要
図18 ABK downloaderの復号コード
図18 ABK downloaderの復号コード

ABK downloaderには、主に次の4つの機能があります。

  1. Symantec社、TrendMicro社、Qihoo 360社およびMcAfee社のセキュリティ対策製品を検出(図19)
  2. MACアドレス、システム情報、およびセキュリティソフトの情報を収集し、空白文字なしのUser-Agentを利用してC2サーバにこれらのデータを送信(図20)
  3. GetLocalTime APIを使用して、"8:00-18:00"の就業時間と考えられる時間帯にのみ動作
  4. 正規のWebサイトを侵害し、C2サーバやマルウェア置き場として利用
図19 検出するセキュリティ対策製品
図19 検出するセキュリティ対策製品
図20 空白文字が含まれないUser-Agent
図20 空白文字が含まれないUser-Agent

攻撃者グループとマルウェアの関係性

図21は、攻撃者グループとマルウェアの関係性を表したものです。前述したように、KCPプロトコルを使用するマルウェアの多くはAPT41と関連しており、gokcpdoorもその1つであると疑われます。しかしながら、確認した攻撃事例では、Tickが使用するマルウェア(ABK downloaderおよびOAED Loder)と共にgokcpdoorが確認できており、当該マルウェアは、Tickとの関連があると考えられます。

攻撃者グループの帰属の概要については、Appendixの「Diamond Model」を参照してください。

図21 攻撃者グループとマルウェアの関係性
図21 攻撃者グループとマルウェアの関係性

対策

KCPプロトコルやgokcpdoorに関する攻撃キャンペーンへの対策について紹介します。

なお、gokcpdoorやgokcpratのC2通信はAESで暗号化されているため、KCPトラフィックとして検出を行うためには、通信を復号する必要があります。

KCPトラフィックの検出

KCPトラフィックには、KCP特有のメッセージヘッダフィールドが存在しますが、KCPプロトコルを識別するための特徴が少なく、ネットワークトラフィックからKCPだけを検出することは困難です。ネットワークセキュリティ製品などを利用している場合は、「Unknown UDP Traffic」などのアラート種別で検出することがあり、そのような特徴的なアラートを確認する方法が最も現実的です。

また、UDPパケットをキャプチャ可能な環境の場合、UDPペイロードにKCPのコマンドが存在するかを確認することで、KCPの通信を判別できる可能性があります。

例えば、Splunkでは、Splunk Streamを用いてパケットをキャプチャした上で、図22に示すサーチクエリを利用すればログからKCPトラフィックを検出できます。このクエリは、UDPのキャプチャログから、送受信内容の5バイト目がKCPのコマンド(IKCP_CMD_PUSHとIKCP_CMD_ACK)であるものをサーチします。

なお、本クエリを使用する場合は、別途Splunk Steamのデプロイおよびキャプチャ設定が必要となります。設定方法については、Appendix「Splunk Steamの設定方法」を参照してください。

図22 SplunkおよびSplunk Steamを利用したKCPトラフィックの検索例
図22 SplunkおよびSplunk Steamを利用したKCPトラフィックの検索例

また、Wiresharkにおいて、KCPプロトコルを分析可能なKCP dissectorプラグインを使用することで、不審なUDPトラフィックをKCPトラフィックとして識別することもできます。図23は、CandyMi氏によって開発されたプラグイン※9を使用した例です。

※9 GitHub - cfadmin-cn/kcp_dissector: kcp dissector based on wireshark.

図23 WiresharkでKCP dissectorの利用例
図23 WiresharkでKCP dissectorの利用例

gokcpdoorの検知

gokcpdoorは、マルウェア内に含まれる特徴的な文字列や、バックドアとして動作した際の実行痕跡から、以下の4つの手法で検知できる可能性があります。

  1. Yaraルールによるスキャン(Appendix「Yaraルール」)
  2. AutorunsによるAutoStart Extensibility Points(ASEP)のチェック
  3. Sysmonのプロセス作成イベントおよびネットワーク接続イベントのログのチェック(図24)
  4. EDR製品のプロセスツリーからのシェルコマンド実行のチェック(図25)
図24 gokcpdoor実行後のSysmon for Linuxのログ例(Network Connect)
図24 gokcpdoor実行後のSysmon for Linuxのログ例(Network Connect)
図25 CrowdStrike Falconのプロセスツリーの検出例
図25 CrowdStrike Falconのプロセスツリーの検出例

まとめ

gokcpdoorは、C2通信にKCPプロトコルを使用するGo言語でコーディングされたバックドア型のマルウェアです。同じ開発者が作成したと思われるgokcpratの存在も確認しており、いずれも検体内にバージョン情報と考えられる文字列が含まれていることから、攻撃者は、今後も機能を改善した類似検体の開発を継続する可能性があります。

また、昨今、KCPプロトコルを利用するマルウェアを目にする機会が増えており、攻撃者は今後もKCPプロトコルをC2通信の一手段として利用するマルウェアを攻撃に使用することが予想されます。このため、十分に警戒し、EDR製品を利用したエンドポイントの監視やネットワーク機器を利用した通信制御および監視といった、セキュリティ対策を講じていくことが重要です。

ラックの脅威分析チームでは、今後もこの攻撃者グループおよび利用されたマルウェアについて、継続的に調査し、広く情報を提供していきますので、ご活用いただければ幸いです。

松本 拓馬、石川 芳浩

Appendix

KCPおよびkcp-goの伝送データ構造

図26 KCPメッセージの構造
図26 KCPメッセージの構造
フィールド サイズ 説明
conv 4bytes セッション番号
cmd 1byte コマンド
frg 1byte フラグメント数
wnd 2byte ウィンドウサイズ
ts 4bytes タイムスタンプ
sn 4bytes シリアル番号
una 4bytes 受信済みのKCPメッセージ数
len 4bytes データの長さ
data 可変長 データ
表2 KCPメッセージのパラメータ
図27 kcp-goのデータ構造
図27 kcp-goのデータ構造
Field Size Description
Nonce 16bytes ランダムな値
CRC32 4bytes CRC32チェックサム
FEC SEQ ID 4bytes FECシーケンスID
FEC Type 2bytes FECタイプ
Size 2bytes データの長さ
Data 可変長 KCPメッセージまたはFECのParity Shard
表3 kcp-goのデータのパラメータ

C2コマンド

Command Description
exec 任意のコマンド実行
shell リバースシェル。コマンドプロンプトを起動し、インタラクティブに操作
wget 指定されたURLから感染端末へファイルのダウンロード
upload C2サーバから感染端末にファイルをアップロード
download 感染端末からC2サーバにファイルをダウンロード
dir / ls カレントディレクトリのファイル一覧を取得
mkdir ディレクトリを作成
rm 任意のパスのファイルおよびフォルダを削除
cd ディレクトリを移動
pwd カレントディレクトリのパスを取得
whoami / id "whoami"または"id"コマンドを実行し、コンピュータ名とユーザ名を取得
getos "wmic os get name"または"uname -a"コマンドを実行し、OS情報を取得
ps 実行中のプロセス一覧を取得
ifconfig / ipconfig ネットワーク設定情報を取得
netstat ネットワークの接続状況を取得
portfoward
  • list - ポートフォワードの設定状況を取得
  • add -ポートフォワード設定を追加(tcpまたはudpを選択可能)
  • delete -ポートフォワード設定を削除
socks5
  • list - socks5プロキシの設定状況を取得
  • add - socks5プロキシ設定を追加
  • delete - socks5プロキシ設定を削除
charset 文字コードを変更(UTF-8のみをサポート)
back コマンド操作を終了
exitprocess 自身のプロセスを終了
表4 gokcpdoorのコマンド一覧

Yaraルール

rule gokcpdoor {
meta:
description = "Detects gokcpdoor malware"
author = "LAC Co., Ltd."
strings:
$str1 = "gokcpdoor" ascii
$str2 = "exec_lin.go" ascii
$str3 = "exec_win.go" ascii
$str4 = "syscmds/ps_linux.go" ascii
$str5 = "syscmds/ps_windows.go" ascii
$str6 = "target.go" ascii
condition:
(4 of ($str*)) and filesize > 2MB
}
gokcpdoorのYaraルール

* 本番システムに導入する前に、適切なテストとチューニングを行うことを推奨します。

Splunk Steamの設定方法

図28 Splunk Streamの設定例
図28 Splunk Streamの設定例
図29 Splunkに記録されるログとKCP通信の対応関係(左:Splunk/右:Wireshark)
図29 Splunkに記録されるログとKCP通信の対応関係(左:Splunk/右:Wireshark)

Diamond Model

図30 gokcpdoorを利用する攻撃者グループの概要
図30 gokcpdoorを利用する攻撃者グループの概要

IOC(Indicator Of Compromised)

Indicator Indicator Type Type Context
86f02e9f344a8e8009e59ecae934a780 MD5 ABK Downloader
d85c9b3d49b1af482c384a4253c16e28ae65a0f5 SHA1
61eb25a6e6457087232de7ce7cd7b6cd9926e10674487c9e55b9a3fa54748b4c SHA256
Mozilla/4.0(compatible;MSIE8.0;WindowsNT6.0;Trident/4.0) User-Agent
a6f4a5ec66b7c5f275e793be02885543 MD5 gokcpdoor for Linux
bdb3db1013b16cb64b3f8156eae621054fa334bf SHA1
2dd8ab1493a97e0a4416e077d6ce1c35c7b2d8749592b319a7e2a8f4cd1cc008 SHA256
fa4a45c531a19744e91bbfb9da1b29c0 MD5 gokcprat for Linux
f43e693cf6d459506249d1801742a190c3a4b483 SHA1
993dbbce860539e1b7a1f91ebacc0ee7f1cd1a6cc37a9c7a2a2647fc64382f56 SHA256
103.97.179[.]182 C2

この記事は役に立ちましたか?

はい いいえ