トップナビゲーションをスキップ
BlackBerry ThreatVector ブログ

CostaRicto キャンペーン:サイバースパイのアウトソーシング

要約:RaaS(サービスとしてのランサムウェア)のまぎれもない成功に伴い、サイバー犯罪市場のポートフォリオは拡大し、フィッシングやスパイ活動の専用キャンペーンが不正サービスのリストに追加されています…

この 6 か月の間、BlackBerry リサーチ & インテリジェンスチーム は世界中のさまざまな被害者を標的にしたサイバースパイキャンペーンを監視してきました。BlackBerry が「CostaRicto」と名付けたこのキャンペーンは、特製のマルウェアツールと複雑な VPN プロキシおよび SSH トンネリング機能を備えた APT 傭兵グループ「hackers-for-hire」によって運営されているようです。

APT スタイルの攻撃を行う傭兵グループは、ますます広まりつつあります。彼らの戦術、手法、および手順(TTP)は、国家が支援する非常に高度なキャンペーンに似ていることがよくありますが、その被害者のプロファイルや地域は、単一の悪意のあるアクターの関心に結び付けるにはあまりにもかけ離れています。

APT 傭兵グループの顧客には、理屈の上では金銭的余裕のある誰もが含まれる可能性がありますが、より高度なアクターは、大企業にせよ、影響力のある個人にせよ、あるいは政府にせよ、最高のプロファイルを持つ支援者と仕事をすることを自然に選ぶでしょう。サイバー犯罪者は多くの危険にさらされており、依頼を選ぶ際には、暴露されるリスクを避けるために極めて慎重にならざるを得ません。

スパイキャンペーンまたはその一部を傭兵グループにアウトソーシングすることは、特に競争相手に関する情報を求めているものの、必要なツールやインフラストラクチャ、経験がないために自ら攻撃を仕掛けることができない企業や個人にとって、非常に魅力的なのかもしれません。一方で、サイバースパイに熟練した悪名高い攻撃者でさえも、攻撃に間接層を加えることで恩恵を受けることができます。傭兵をプロキシとして使用することにより、真の攻撃者は自身の身元の防御を強化し、アトリビューションの試みを阻止することができます。

主な調査結果

  • CostaRicto の標的は、ヨーロッパ、南北アメリカ、アジア、オーストラリア、およびアフリカの諸国に分散していますが、南アジア(特にインド、バングラデシュ、およびシンガポール)に最も集中しているようです。これは、脅威アクターがその地域を拠点にしながら、さまざまな依頼者からの幅広い依頼で働いている可能性があることを示唆しています。

  • コマンドアンドコントロール(C2)サーバーは、Tor および/またはプロキシレイヤーを介して管理されており、被害者の環境には SSH トンネルの複雑なネットワークも構築されています。これらの手法は、平均以上の能力を持つ運用セキュリティを破ります。

  • 足掛かりとして使用されたバックドアは見たことのない新種のマルウェアで、挑発的なプロジェクト名、しっかりした構成のコード、および詳細なバージョン管理システムを備えたカスタムビルトツールです。最も古いタイムスタンプは 2019 年 10 月で、バージョン番号によるとプロジェクトはデバッグテスト段階にあるようです。脅威アクターが内部開発したものなのか、それともベータテストの一環で専用として別のエンティティから取得したものなのかは、現時点では不明です。

  • ペイロードステージャーのタイムスタンプは 2017 年まで遡ります。これは、運用自体はしばらく続いていたものの、別のペイロードの配信に使用されたことを示唆していることも考えられます。とはいえ、ステージャーを再コンパイルせずに(つまり、バイナリ編集で C2 URL を変更することにより)、そのまま再利用することは不可能です。

  • バックドアプロジェクトは Sombra と呼ばれます。Sombra とはOverwatch game personaで、スパイおよび情報分析を専門とし、ステルス、侵入、およびハッキングスキルを特徴とする敵対者組織のエージェントです。

  • バックドアのバイナリにハードコーディングされたドメイン名の一部は、正規ドメインを偽装しているようです(例えば、悪意のあるドメイン sbibd[.]net は、インドステート銀行バングラデシュ支店の正規ドメイン sbibd.com の偽装)。しかし、これらのバックドアの影響を受けた被害者は無関係で、別の目的を果たした既存インフラストラクチャの再利用であることを示唆しています。

  • バックドアドメインが登録されていた IP アドレスの 1 つは、APT28 に起因する以前のフィッシングキャンペーンと重複しています(つまり、RiskIQ データによると、SombRAT のドメイン akams[.]in は、攻撃時点でフィッシングドメイン mail.kub-gas[.]com と同じ IP アドレスに登録されていました)。しかし、BlackBerry のリサーチャーは、CostaRicto と APT28 との直接的なつながりは非常に考えにくいと見ています。IP の重複は偶然か、あるいは以前のフィッシングキャンペーンが実際の脅威アクターの代行として傭兵にアウトソーシングされていたと考えたほうが自然です。

標的

国家が支援する APT アクターのほとんどとは異なり、CostaRicto 攻撃者は被害者の地域に関して言えば無差別のように見えます。その標的は、南アジア地域に若干集中しているものの、世界各国に分散しています。

  • インド
  • バングラデシュ
  • シンガポール
  • 中華人民共和国
  • 米国
  • バハマ
  • オーストラリア
  • モザンビーク
  • フランス
  • オランダ
  • オーストリア
  • ポルトガル
  • チェコ

被害者のプロファイルは、いくつかの業界にわたって多種多様で、大部分は金融機関です。

 

配布

攻撃者は、(おそらくフィッシングで取得またはダークウェブで購入した、盗まれた資格情報を使用して)被害者の環境へのアクセス権を取得した後、SSH ツールを使用してリモートトンネリングを設定します。SSH ツールは、トラフィックを悪意のあるドメインからローカルポート上でリスンしているプロキシにリダイレクトするよう設定されています。トンネルの認証には攻撃者の秘密鍵が使用されます。

バックドアを開けるには、スケジュールしたタスクを使用して HTTP または逆引き DNS ペイロードステージャーを実行します。

バックドアは、PowerSploit リフレクティブローダーでラップされるか、単純な仮想マシン(VM)メカニズムを使用してペイロードを復号し、インジェクトするカスタムビルドドロッパの形をとります。

ツールセット

  • SombRAT:カスタムバックドア(x86 バージョンと x64 バージョンの両方が存在)
  • CostaBricks:VM ベースのカスタムペイロードローダー(これまでのところ x86 SombRAT ペイロードのみで確認)
  • • PowerSploit のリフレクティブ PE インジェクションモジュール(x64 SombRAT ペイロードで確認)
  • HTTP および逆引き DNS ペイロードステージャー
  • nmap:ポートスキャナ
  • PsExec

PS1 ローダー(x64)

64 ビットバックドアは、ごく標準的な方法でデプロイされます。一連のスクリプトおよび暗号化ファイルとして配布され、Invoke-ReflectivePEInjection PowerSploit モジュールをベースにした PowerShell ローダーを使用して最終ペイロード DLL を復号し、メモリにインジェクトします。

ファイル名

機能

autorun.bat

PowerShell 実行ポリシーを無制限に設定し、autorun.ps1 を実行する、難読化されたバッチスクリプト

autorun.ps1

ntuser.c ファイルに格納された別の PowerShell ローダーを復号して実行する、難読化された PowerShell スクリプト

ntuser.a

PowerShell ローダーおよびペイロードバイナリの復号に使用される XOR キー

ntuser.b

XOR エンコードされたペイロードバイナリ

ntuser.c

改造によりペイロード復号ルーチンが追加され、XOR エンコードされた Invoke-ReflectivePEInjection モジュール


CostaBricks ローダー (x86)

32 ビットバックドアとともに使用されるこのローダーのほうが、技術的に注目すべき点があります。埋め込まれたバイトコードを実行してペイロードを復号し、メモリにインジェクトする単純なカスタムビルド仮想マシンメカニズムを実装しています。

この難読化の試みは目新しいものではありませんが、標的型攻撃との関連ではかなりまれです。コード仮想化は、はるかに高度なソリューションを使用する商用ソフトウェアプロテクタに最もよく見られています。幅広い金融クライムウェアによって使用されている既製の悪意のあるパッカーは、より単純な仮想マシンを備えていることもあります。とはいえ、この特定の実装は珍しく(パブリックドメインではほんの数例しかありません)、使用しているのは SombRAT ペイロードだけのようです。だとすると、その攻撃者専用のカスタムビルトツールと考えられます。

アンチマルウェアソリューションをさらに惑わすために、 Blink (https://github.com/crosire/blink)と呼ばれる合法的なオープンソースアプリケーションのまったく難読化されていないコードも含んでいますが、実行されることはありません。

図 1:Blink のコードに属する文字列

また、使用されない zlib 解凍ルーチンもありますが、古いバージョンの名残のコードと思われます。

コンパイルのタイムスタンプは、ローダーと埋め込まれたペイロードの両方が同じ日に(ほんの数秒の差で)コンパイルされたことを示しています。

ローダーの 1 つには次の PDB パスが含まれており、プロジェクトの内部呼称が CostaRicto/CostaBricks であることを示唆しています。

図 2:x86 ローダーサンプルの 1 つからの PDB パス

仮想マシンの内部

仮想マシンメカニズムは、C++ オブジェクトおよびクラスを使用して実装されています。20 種類の VM 命令があり、それぞれ 0 ~ 3 個のオペランドがあります。実行するバイトコードへのポインタは、パラメータとして VM 初期化ルーチンに渡されます。

図 3:仮想マシンの初期化

VM インスタンスは、命令ポインタ、ゼロフラグ、命令リスト、およびレジスタへのポインタを含むコンテキスト構造の設定によって初期化されます。

オフセット

フィールド

説明

0x00

Instruction pointer

実行するバイトコード命令のインデックス

0x04

Zero flag

条件付きジャンプに使用されます。

0x08

Instructions_list.first

リスト内の最初の命令を指し示します。

0x0C

Instructions_list.current

リスト内の現在の命令を指し示します。

0x10

Instructions_list.next

リスト内の次の命令を指し示します。

0x14

Registers pointer

レジスタのリストを指し示します。

0x18

Registers count

新しいレジスタが割り当てられるとインクリメントされます。


命令とオペランド

命令、オペランド、およびオペコードハンドラは、二重連結リストとして実装されています。各 VM 命令には独自のインデックスがあり、オペコード数、フラグ、オペランド数、オペランドなどの情報を含んでいます。

図 4:SUB オペコードの VM 命令形式の例

オペランドは、即値または「レジスタ」をとることができます。動的に割り当てられる「レジスタ」は、二重連結リストによって辞書オブジェクト形式で編成された小さなメモリ領域です。各レジスタには、最大 8 バイトのデータ(メモリバッファへのポインタなど)を格納でき、読み取りまたは書き込みが可能な独自のインデックスがあります。

オペランドのメタデータがインデックス値を指定している場合、オペランドは「レジスタ」であり、それ以外の場合は即値を含んでいます。値(即値または「レジスタ」によって指された値)は整数です。デフォルトでは qword ですが、メタデータで異なる長さ(バイト、ワード、またはダブルワード)を指定できます。

オフセット

フィールド

備考

0x00

Instruction index

0 から始まる連続番号

0x04

Opcode

0 – 0x13 (19.)

0x06

Skip bool

設定した場合、命令が無視されます。

0x08

Operands count

0 – 3

0x0C

Operand type

読み取り(0)または書き込み(1)

0x0E

Operand flag

長さを指定します。0x10 = バイト、0x20 = ワード、0x40 = ダブルワード

0x10

Operand register index

0x9435C739 から始まる連続番号

0x14

Operand value

即値(オペランドがレジスタでない場合)

0x1C

Operand 2

オプション

0x2C

Operand 3

オプション


オペコード

各オペコードには、メイン VM ループで実行される独自のハンドラルーチンがあります。

図 5:VM 命令の処理ループ

ハンドラルーチンは、オペランドの番号およびタイプが有効かどうかをチェックし、VM「レジスタ」からオペランド値を読み取り、特定のアクション(計算/バイト操作、比較、ジャンプ、API コール)を実行し、結果を宛先「レジスタ」に保存します。

図 6:XOR オペコードハンドラルーチン

オペコード(16 進)

オペランド

命令

説明

0x00

dst, src

mov

src(即値またはポインタ/レジスタ)から dst のレジスタに移動します。オペランドがない場合は NOP 命令として機能し、主にジャンプ先へのラベルとして使用されます。

0x01

dst, src

xor

dst と src を排他的論理和し、結果を dst によって指し示します。

0x02

dst, src

add

src と dst を加算し、結果を dst によって指し示します。

0x03

dst, src

and

dst と src を論理積し、結果を dst によって指し示します。

0x04

dst, src

sub

dst から src を減算し、結果を dst によって指し示します。

0x05

addr

call

オペランド 1(即値またはレジスタ)のアドレスを呼び出します。

0x06

-

ret

リターン 1

0x07

mem_ptr, size

virtual_alloc

オペランド 2 のサイズのメモリを割り当て(VirtualAlloc を呼び出し)、ポインタをオペランド 1(レジスタ)に返します。

0x08

mem_ptr

virtual_free

メモリを解放し(VirtualFree)、ポインタをオペランド 1(レジスタ)に返します。

0x09

dst, src, size

memmove

ソースはオペランド 2、宛先はオペランド 1、サイズはオペランド 3 によって指し示します。

0x0A

dst, src

cmp

dst(レジスタ)と src(即値またはレジスタ値)の値を比較し、VM コンテキスト構造内にゼロフラグを設定します。

0x0B

dst, src

alldiv

オペランド 1 のレジスタを被除数、オペランド 2(即値またはレジスタ値)を除数とし、結果をオペランド 1 のレジスタに返します。

0x0C

dst

jnz

ゼロフラグが設定されていない場合、オペランドによって指定された位置にジャンプします。

0x0D

dst

jz

ゼロフラグが設定されている場合、オペランドによって指定された位置にジャンプします。

0x0E

dst

jmp

無条件ジャンプ。命令ポインタをオペランドの値に設定します。

0x0F

dll_handle, dll_name

load_library

オペランド 2(レジスタ)をライブラリ名へのポインタ、オペランド 1(レジスタ)をロードされたライブラリへのハンドルとして、LoadLibraryA を呼び出します。

0x10

dll_handle, proc_name, api_address

get_proc_addr

オペランド 1 を DLL ハンドルへのポインタ、オペランド 2 をプロセス名へのポインタとして GetProcAddress を呼び出し、API アドレスをオペランド 3 に返します(オペランドはすべてレジスタ)。

0x11

-

exit_proc

ExitProcess(0) を呼び出します。

0x12

dst, src

shr

右シフトします(dst を src で除算します)。

0x13

dst, src

shl

左シフトします(dst と src を乗算します)。


バイトコード

BlackBerry がこれまで確認した x86 ローダーはすべて、長さが 1800(0x708)行のまったく同じバイトコードを埋め込みます。これらの 1800 行の命令のほとんどは不要(つまり、コードの機能に影響しない)で、難読化のためだけに挿入されていました。

バイトコードの目的は、埋め込まれたペイロードを復号し、メモリにリフレクティブにロードし、実行することです。

図 7:VM バイトコードの断片 - 復号キーの設定

ペイロード復号ルーチンは、ハードコーディングされたキーにより演算およびバイトシフト命令に基づくカスタム対称アルゴリズム(SHL/SHR/SUB/ADD/XOR の組み合わせ)を使用します。

これらの定数値は、これまで確認されたすべての x86 SombRAT ドロッパで使用されています。

図 8:ペイロード復号アルゴリズム

SombRAT バックドア

上述のローダーで配布されるバックドアは、オブジェクト、クラス、およびインターフェイスを多用して開発され、C++ でコンパイルされた実行可能プログラムです。その他の悪意のあるペイロード(独自のプラグインまたはスタンドアロンのバイナリ)のダウンロードと実行に主に使用される足掛かり RAT のプラグインアーキテクチャと基本機能を備えています。そのほかにも、システム情報の収集、プロセスのリスト作成や強制終了、C2 へのファイルのアップロードといった単純な操作を実行することもできます。

特徴

  • ハードコーディングされたドメイン名および DGA 生成サブドメインとの DNS トンネル通信
  • RSA-2048 で暗号化された C2 トラフィック
  • AES 暗号化されたカスタム格納形式を使用して構成、プラグイン、および収集したデータを格納
  • 各サンプルに固有のバージョン番号

図 9:バックドアのクラス階層

64 ビットサンプルに見られる PDB パスによると、プロジェクトは当初 Sombra と呼ばれていました。これは、おそらくOverwatch game characterに関連しています。

図 10:プロジェクト名「Sombra」を含む 64 ビットバックドアの PDB パス

Overwatch ゲームの世界では、Sombra は「Talon」と呼ばれる敵対者組織のエージェントです。彼女はコンピュータのハッキングと暗号に熟練し、スパイと情報分析を専門としています。

「世界で最も悪名高いハッカーの1人である Sombra は、情報を利用して権力者を手玉に取る。

Sombra のスキルにはコンピュータハッキングと暗号が含まれる。彼女はこれらの活動を大いに楽しんでおり、ロックをかいくぐり、秘密を解き明かしたいという欲求がその性格に染みついているというほどである。Reaper の仲間として知られ、スパイと情報分析を専門とする。

ステルス攻撃で敵を衰弱させる Sombra は強力な侵入者である。ハッキングによって敵を混乱させて簡単に抹殺できることに加え、EMP によって一度に複数の敵に対して優位に立つことも可能である。また、移動となりすましの能力が高いため、突き止めることが難しいターゲットである。」1

各サンプルにはハードコーディングされたバージョン番号が埋め込まれています。これまで確認されたバージョンは次のとおりです。

バージョン

コンパイルタイムスタンプ

アーキテクチャ

0.0.1.114499

31-10-2019 21:22:39 UTC

x86

0.0.1.14630 (T)

09-11-2019 21:53:44 UTC

x86

0.1.60 (DT)

11-11-2019 14:55:45 UTC

x86

0.1.208 (DT)

17-11-2019 20:58:25 UTC

x86

0.1.724 (DT)

24-12-2019 10:33:41 UTC

x64

0.2.404 (DT)

20-08-2020 01:36:50 UTC

x64


バックドアサンプルの 1 つ(0.1.60 (DT))は、http[://]159.65.31[.]84/svolcdst.exe でホストされていたことが判明しています。

振る舞い

このバックドアは、コマンド処理ループに入る前に、サービスとして実行されているかどうかをチェックし、%HOSTNAME% と実行されたときの特権によって「S」、「U」、または「SU」のポストフィックスからなる、1 回のみ実行されるミューテックスを作成します。

DNS 通信の C2 ドメイン名はハードコーディングされ、XOR を使用して難読化されています。バックドアは、カスタムドメイン生成アルゴリズム(DGA)を使用してサブドメインを生成し、DNS トンネル経由で C2 への初期ビーコンの送信を試みます。

図 11:C2 ドメイン名の復号

構成は、ダウンロードされたプラグインと収集されたすべてのデータとともに、%TEMP% ディレクトリ内にある 1 つのファイルの内部にカスタムデータベース形式で格納されます。ファイル名はハードコーディングされ、XOR によって難読化されています。格納ファイルは、ハードコーディングされたキーを使用して AES-256 で暗号化され、マルウェアによる読み取りまたは書き込みが必要になるたびに復号され、新たなデータが追加された後に再び暗号化されます。

図 12.ハードコーディングされたストレージ暗号化用 AES キー

バックドアコマンドとして、および C2 に送信されるメッセージのデバッグに使用される文字列は、単純なアルファベット置換で暗号化されています。これらは被害者側のバックドアによっては復号されず、復号キーはバイナリ内には存在しません。まず間違いなく、バックドアクライアントがローカルで復号するものと考えられます。

 

図13:置換暗号化された文字列

コマンドアンドコントロール(C2)

C2 通信は、DNS トンネルまたは TCP ソケット経由で実行できます。トラフィックは SSL 暗号化され、HTTP/SOCKS5 プロキシを通過できます。C2 ドメイン名はバイナリ内にハードコーディングされ、サンプル間で異なる 1 バイト XOR キーで難読化されています。マルウェアは、通信を確立するために、まず DGA(ドメイン生成アルゴリズム)を使用して接続先のサブドメインを生成します。内部ブール設定によって、次の URL 形式のいずれかが使用されます。

  •  images%x.%s
  •  images%x.elmako.%s

ここで、%s はハードコーディングされたドメイン名、%x は GetTickCount API の結果に基づいて生成される 8 個の16 進数文字を含んでいます。

接続に失敗した場合、バックドアは同じアルゴリズムを使用して、今度は「images」プレフィックスを付けずに、同じドメイン内に他の URL をいくつか生成し、接続を試みます。

ほとんどの場合、マルウェアが DNS_TYPE_TEXT リクエストを使用してデータを送信する間、攻撃者は DGA によって生成されたサブドメインに関連付けられた IP アドレスで TCP チャネルを介してコマンドを別途発行するものと思われます。

通信はすべて zlib によって圧縮され、AES によって暗号化されます。さらに、AES 鍵交換を保護するために埋め込まれた RSA 公開鍵が使用されます。

図 14:C2 トラフィックの暗号化に使用される RSA キー

バックドアのコマンド

x86 バージョンと x64 バージョンのバックドアは共に、6 つのグループに編成された約 50 種類のコマンドを備えており、グループごとにインターフェイスが異なります。

  • コア
  • タスク管理
  • 構成
  • 格納
  • デバッグ
  • ネットワーク

コマンド  

タイプ  

説明 

networkdisconnected broadcast 

コア

「networkdisconnected」メッセージをブロードキャストします。

informationaccepted broadcast 

コア

提供されたセッション ID をメモリ構造に保存し、「informationaccepted」メッセージをブロードキャストします。

networkconnected broadcast

コア 

セッション ID とシステム情報をブロードキャストします。

ping 

コア 

C2 サーバーに「ping」を送信します。

loadasdll 

コア 

メモリに追加の DLL をロードします。

loadfromstorage 

コア 

(ストレージから)メモリに DLL をインジェクトします。

loadfromfile 

コア 

(ディスクから)メモリに DLL をインジェクトします。

loadfrommem

コア

(メモリから)メモリに DLL をインジェクトします。

loadplugincomplete

コア

すでにロードされているプラグインを実行します。

initializeandloadpluginby-
uniqid

コア 

プラグインをロードして実行します。プラグインは、圧縮された AES 暗号化 PE ファイルとしてストレージ内部に格納され、固有 ID によって参照されます。

getinfo 

コア 

環境文字列、コンピュータ名、ユーザー名、OS バージョン情報、システム時間などを取得します。

restart 

コア 

ShellExecuteW を使用して再作成します。

shutdown 

コア 

プロセスを終了します。

uninstall 

コア 

(未実装)

updatemyself 

コア 

自身のバックアップ(拡張子「.old」)を作成し、CreateProcessW によって新規インスタンスを作成します。

pluginunload 

コア 

ストレージからプラグインをアンロードして削除します。

getprocesslist 

タスク管理 

実行中のプロセスのリストを取得します。

killprocessbypid 

タスク管理 

PID によってプロセスを終了させます。

killprocessbyname 

タスク管理 

名前によってプロセスを終了させます。

get

構成 

指定された値をストレージ内の .config ファイルから読み取り、C2 に送信します。

set 

構成 

特定の config フィールドを設定し、ストレージ内の .config ファイルに保存します。

del 

構成 

指定された config フィールドをストレージ内の .config ファイルから削除します。

initdefaults 

構成 

config フィールドをデフォルト値で初期化し、ストレージ内の .config ファイルに保存します。

clear 

構成 

特定の config フィールドをゼロに、ストレージ内の .config ファイルに保存します。

save 

構成 

与えられた config 値をストレージ内の .config ファイルに保存します。

enum 

構成 

ストレージ内の .config ファイルからメモリに値を読み込みます。

write 

格納 

データを暗号化して格納ファイルに書き込みます。

create 

格納 

新しい暗号化格納ファイルを作成します。

close 

格納 

データを暗号化して格納ファイルにフラッシュします。

drop 

格納 

提供されたファイル内容を格納ファイルに書き込みます。

delete 

格納 

指定された ID のファイルをストレージから削除し、ストレージ内のファイルを列挙します。

enum 

格納 

ストレージ内のファイルを列挙します(名前、書き込み、サイズ)。

upload 

格納 

指定された ID のファイルを格納ファイルから復号してアップロードします。

clearall

格納

ストレージからすべてのファイルを削除します。

archivebypath 

格納 

指定されたパスからファイルを読み取り、格納ファイルに保存し、ストレージを列挙します。

restorestorage 

格納 

格納ファイルを削除し、新しいストレージを開きます。

cancel1 / closeanddeletestorage 

格納 

ストレージからすべてのファイルを削除し、一時格納ファイルを削除します。

closestorage 

格納 

一時格納ファイルを閉じます。

openstorage 

格納 

一時格納ファイルを開きます。

getcontent 

格納 

(未実装)

awaitcreate 

格納 

新しい暗号化格納ファイルを作成します。

await&putcontent 

格納 

C2 から読み取り、格納ファイルに保存します。

await&getcontent 

格納 

ストレージから内容を読み取り、C2 通信経由で送信します。

debuglog 

デバッグ 

デバッグロギングを有効化します。 

broadcast

ネットワーク 

networkconnected または networkdisconnected ブール値をメモリ内に設定します。

touchconnect 

ネットワーク 

Networkconnected ブール値設定を C2 に送信します。

stats 

ネットワーク 

送信/受信バイト数の詳細を送信します。

reconnect 

ネットワーク 

ソケットを閉じ、再接続します。

disconnect 

ネットワーク 

ソケットを閉じます。

switchtotcp 

ネットワーク

C2 通信を TCP/IP に切り替えます。

switchdns 

ネットワーク

C2 通信を DNS に切り替えます。

setproxy2

ネットワーク

プロキシタイプ、ホスト、ポート、ドメイン、ユーザー、パスワードを設定します。

checkproxy2

ネットワーク

(未実装)

getproxy3

ネットワーク

現在のプロキシ構成を C2 に送信します。

resetproxy3

ネットワーク

(未実装)

1 – v0.1.60t 以前
2 – 少なくとも v0.1.208 以降
3 – 少なくとも v0.1.724 以降

ネットワーク

Infosportals[.]com

2019 年 10 月に初めて開設された infosportals[.]com は、初期の SombRAT によって主要 C2 ドメインとして利用されていました。その後、IP アドレスを何度か変え、2 月から 5 月の間に閉鎖されましたが、5 月下旬から 6 月中旬にかけて別の攻撃の一環として一時的に再開されました。

図15:infosportals[.]com の IP 解決のタイムライン

図 16:infosportals[.]com の IP 解決テーブル

 Sbibd[.]net

正規の sbibd.com (登録者:インドステート銀行バングラデシュ支店)を偽装したフィッシングドメイン sbibd[.]net は、2019 年 11 月初旬から 12 月の間の短期間に初めて開設しました。その後、2020 年 2 月から 3 月の間に再開され、SombRAT のいくつかの亜種で主要 C2 として使用されました。

図 17:sbibd[.]net の IP 解決のタイムライン

図 18:sbibd[.]net の IP 解決テーブル

Akams[.]in

2019 年 12 月下旬から 2020 年 1月中旬までの数週間に初めて開設された akams[.]in も、複数の SombRAT サンプルによって C2 通信用として使用されていました。IP 45.89.175.206 の事前解決の 1 つは、mail[.]kub-gas[.]com と呼ばれる別のドメインと重複している点において特に興味深く、Area 1 Security のレポートに APT-28/Fancy Bear/Sofacy フィッシングキャンペーンとの関連性が示唆されていました。しかし、精査した結果、SombRAT キャンペーンと APT-28 アクティビティの間に直接的なつながりはない可能性が高いようです。

図19:akams[.]in の IP 解決のタイムライン

図 20:akams[.]in の IP 解決テーブル

newspointview[.]com

2020 年 6 月下旬に登録され開設された newspointview[.]com は、SombRAT のつい最近の亜種で主要 C2 ドメインとして使用されています。

図 21:newspointview[.]com の IP 解決のタイムライン

図 22:newspointview[.]com の IP 解決テーブル

タイムライン

次のタイムラインは、主要ドメイン/IP 解決と既知の SombRAT リリースを示しています。

図23:IP 解決のタイムラインと SombRAT のバージョン

結論

CostaRicto の背後にいる脅威アクターが傭兵グループであるという仮説につながった要因はいくつかあります。

  • CostaRicto キャンペーンに使用されたツールセットは、2019 年 10 月頃に出現し、それ以降めったに出回っていない特製のマルウェアで構成されています。したがって、この特定の攻撃者専用と考えられます。

  • また、継続的な開発、詳細なバージョン管理システム、容易な機能拡張が可能なしっかりした構成のコードはいずれも、ツールセットが一度限りのキャンペーンではなく、長期プロジェクトの一環であることを示唆しています。

  • APT28 による以前の一見無関係に見えるフィッシングキャンペーンとのネットワークインフラストラクチャの明らかな共有に加え、無関係の被害者に対する攻撃における C2 サーバーとしてのフィッシングドメイン名の再利用は、さまざまな攻撃の背後に同じエンティティがいることを示しています。

  • さらに、被害者の多様性と地域も特定の国が支援するキャンペーンという図式に当てはまりません。むしろ、その標的の内訳は、そのさまざまなエンティティによって依頼された異なる任務によって説明がつきます。

RaaS(サービスとしてのランサムウェア)の紛れもない成功に伴い、サイバー犯罪市場のポートフォリオは拡大し、フィッシングやスパイ活動の専用キャンペーンが不正サービスのリストに追加されていることは驚くに当たりません。攻撃または攻撃の特定部分を無関係の傭兵グループにアウトソーシングすることは、攻撃者にとって時間の節約、リソースの削減、手順の簡素化などのメリットがあります。しかし、最も重要なメリットは、間接層を加えることで脅威アクターの本当の身元を保護する助けとなることです。

研究者や捜査当局は、戦術/手法/手順の類似性、コードの再利用、および物理的インフラストラクチャの重複に基づいて攻撃者を分類しがちです。多くの場合、属性は地政学的状況との関連でキャンペーンの標的の性質および地域を分析することで得られます。しかし、傭兵 APT のケースでは被害者の選定は無作為のように見えるかもしれず、キャンペーンの背後にある動機の全体像が明らかになることはまれです。

キャンペーンをアウトソーシングする脅威アクターに対処する場合、攻撃を実行したエンティティしか追跡できず、従来よりも実際の加害者を捕まえにくくなっています。

侵入の痕跡 (IoCs):

痕跡  

タイプ

説明 

130fa726df5a58e9334cc28dc62e3ebaa0b7c0d637fce1a66daff66ee05a9437

SHA256

SombRAT x86 ローダー

8062e1582525534b9c52c5d9a38d6b012746484a2714a14febe2d07af02c32d5

SHA256

SombRAT x86 ローダー

d69764b22d1b68aa9462f1f5f0bf18caebbcff4d592083f80dbce39c64890295

SHA256

SombRAT x86 ローダー

f6ecdae3ae4769aaafc8a0faab30cb66dab8c9d3fff27764ff208be7a455125c

SHA256

SombRAT x86 ローダー

561bf3f3db67996ce81d98f1df91bfa28fb5fc8472ed64606ef8427a97fd8cdd

SHA256

SombRAT x86 ペイロード(メモリダンプ)

8323094c43fcd2da44f60b46f043f7ca4ad6a2106b6561598e94008ece46168b

SHA256

SombRAT x86 ペイロード

ee0f4afee2940bbe895c1f1f60b8967291a2662ac9dca9f07d9edf400d34b58a

ee0f4afee2940bbe895c1f1f60b8967291a2662ac9dca9f07d9edf400d34b58a

SHA256

SombRAT x86 ペイロード (UPX)

70d63029c65c21c4681779e1968b88dc6923f92408fe5c7e9ca6cb86d7ba713a

SHA256

エンコードされた SombRAT ペイロード (x64)

79009ee869cec789a3d2735e0a81a546b33e320ee6ae950ba236a9f417ebf763

SHA256

復号された SombRAT ペイロード (x64)

d8189ebdec637fc83276654635343fb422672fc5e3e2818df211fb7c878a3155

SHA256

ペイロードステージャー

fa74f70baa15561c28c793b189102149d3fb4f24147adc5efbd8656221c0960b

SHA256

GO-socks5 プロキシ

c0db3dadf2e270240bb5cad8a652e5e11e3afe41b8ee106d67d47b06f5163261

SHA256

Pcheck プロキシ

6df8271ae0380737734b2dd6d46d0db3a30ba35d7379710a9fb05d1510495b49

SHA256

Pcheck プロキシ

7424d6daab8407e85285709dd27b8cce7c633d3d4a39050883ad9d82b85198bf

SHA256

Pscan ポートスキャナ

svolcdst.exe

Filename

SombRAT ローダー

tunnusvcen.exe

Filename

SombRAT ローダー

C:\Projects\Sombra\_Bin\x64\Release\Sombra.pdb

PDB path

SombRAT x64

C:\Wokrflow\CostaRicto\Release\CostaBricks.pdb

PDB path

SombRAT ローダー

%HOSTNAME%UI724

Mutex

1 回のみ実行されるミューテックス

%HOSTNAME%SUI724 

Mutex

1 回のみ実行されるミューテックス

sbibd[.]net

Domain

SombRAT C2

infosportals[.]com

Domain

SombRAT C2

akams[.]in

Domain

SombRAT C2

newspointview[.]com

Domain

SombRAT C2

159.65.31.84

IP

SombRAT ホスティング場所

212.83.61.227

IP

sbibd[.]net 

144.217.53.146 

IP

sbibd[.]net, akams[.]in, infosportals[.]com

45.89.175.206

IP

akams[.]in

45.138.172.54

IP

newspointview[.]com

212.114.52.98

IP

infosportals[.]com

 

MITRE ATT&CK:

戦術

ID

名称

説明

初期アクセス

T1078

有効なアカウント

盗まれた資格情報による初期侵害の疑い

実行

T1106

API による実行

SombRAT – C2 コマンド

T1053/005

スケジュールされたタスク/ジョブ:スケジュールされたタスク

SombRAT ローダーのダウンロードに使用

T1059/001

コマンドおよびスクリプト言語インタープリタ:PowerShell

x64 SombRAT のロードに使用

防御回避

T1055

プロセスインジェクション

Invoke-ReflectivePEInjection PowerSploit モジュール

T1140

ファイルまたは情報の難読化解除/復号

SombRAT – 復号文字列およびカスタム格納データ

Discovery

T1057

プロセス発見

SombRAT – C2 コマンド

T1082

システム情報発見

SombRAT – C2 コマンド

T1124

システム時間発見

SombRAT – C2 コマンド

T1046

ネットワークサービススキャン

pscan, nmap

収集

T1560/003

収集データのアーカイブ:カスタム方法によるアーカイブ

SombRAT – カスタム格納ファイル

コマンドアンドコントロール

T1572

プロトコルトンネリング

SombRAT - C2 用 DNS トンネリング

T1071/001

アプリケーションレイヤープロトコル:Web プロトコル

SombRAT – C2 用 HTTP

T1573/002

暗号化チャネル:非対称暗号

SombRAT – C2 暗号化用 RSA

T1090/002

プロキシ:外部プロキシ

pcheck HTTP/S プロキシ、GO SOCKS5 プロキシ、PuTTY

流出

T1041

C2 チャネル経由での流出

SombRAT

 

Yara Hunting ルール:

import "pe"
import "hash"

rule costaricto_vm_dropper

{
    meta:
        description = "Rule to detect SombRAT loader by code similarity"
        author = "BlackBerry Threat Hunting and Intelligence Team"

    strings:
        // vm class name
        $classname = "VMBASERUNNER" ascii wide nocase

        // start of vm bytecode
        $vmbytecode = {37C7359438C73594}

        // start of encrypted payload
        $encpayload_1 = {77D2C7AC59B2EB0DF37028AC950971FB}

       // binary string from enc payload (some payloads differ only in the header)
        $encpayload_2 = {06359D29C83125C321C201CF9AE7D1626B8F4281C33617EECE86BD106C628FE593936F00C2C
68E28843BE5374F876840FCD1BFD014D5DEFF4BA8EB6A5FFFB24F932138B04C1BE6D5BD8BB572B8116799AE1C8F0
D5DB774ABA4884B9E706981FC3740B4CD891F8A0EA6900D41B675CFC98A}

        // vm execution loop
        $vmcode_1 = {8B ?? 08 8B ?? 0C 89 ?? 29 ?? C1 ?? 02 39 ?? 74 4E 83 ?? ?? 08 8D ?? ?? 8B ?? ?? 8D ?? 01 89 ?? 8B ?? ?? 66 83 ?? 08 00 75 28 8B ?? ?? 8D ?? 04 5? 5? E8 ?? ?? FF FF 8B ?? ?? 83 ?? 0C 5? 8B ?? 0C 89 ?? 5? FF ?? 14 83 C4 08 8B ?? 8B ?? 08 8B ?? 0C 89 ?? 29 ?? C1 ?? 02 39 ?? 89 ?? 75 B9}

        // vm execution loop (sample from Nov 2019)
        $vmcode_2 = {8B ?? 4? 89 ?? 8B ?? 08 8B ?? 88 33 ?? 66 39 ?? 08 75 19 8D ?? 04 5? 8D ?? 08 E8 ?? ?? 00 00 8B ?? 8D ?? 0C 5? 5? FF ?? 5? 5? 8B ?? 8B ?? 0C 2B ?? 08 C1 ?? 02 3B ?? 75 C7}

    condition:
        uint16(0) == 0x5a4d and filesize < 5MB and filesize > 20KB and any of them
}

rule costaricto_vm_dropper_pdb_path
{
    meta:
        description = "Rule to detect samples with CostaRicto PDB path"
        author = "BlackBerry Threat Hunting and Intelligence Team"
        pdb_string = "C:\\Wokrflow\\CostaRicto\\Release\\CostaBricks.pdb"

    strings:
        $a = "CostaRicto" ascii wide nocase
        $b = "CostaBricks.pdb" ascii wide nocase
        $c1 = "C:\\Wokrflow\\" ascii wide nocase
        $c2 = "Release" ascii wide nocase
        $c3 = ".pdb" ascii wide nocase      

    condition:
        uint16(0) == 0x5a4d and filesize < 5MB and filesize > 20KB and ($a or $b or all of ($c*))
}

rule costaricto_sobmrat_pdb_path
{
    meta:
        description = "Rule to detect samples with SombRAT PDB path"
        author = "BlackBerry Threat Hunting and Intelligence Team"
        pdb_string = "C:\\Projects\\Sombra\\_Bin\\x64\\Release\\Sombra.pdb"
        pdb_string_2 = "c:\\projects\\sombra\\libraries"

    strings:
        $a = "\\Projects\\Sombra\\" ascii wide nocase
        $b = "Sombra.pdb" ascii wide nocase

     condition:
        uint16(0) == 0x5a4d and filesize < 5MB and filesize > 20KB and ($a or $b)
}

rule costaricto_backdoored_blink
{    
    meta:
        description = "Rule to detect backdoored Blink application"
        author = "BlackBerry Threat Hunting and Intelligence Team"

    strings:
        $a1 = "Failed to open target application process!"
        $a2 = "Machine architecture mismatch between target application and this application!"
        $a3 = "Failed to create new communication pipe!"
        $b = "Plauger, licensed by Dinkumware, Ltd."

   condition:
     uint16(0) == 0x5a4d and filesize < 5MB and filesize > 50KB and ($b and 1 of ($a*))
}

rule costaricto_rich_header
{
    meta:
        description = "Rule to detect Rich header associated with CostaRicto campaign"
        author = "BlackBerry Threat Hunting and Intelligence Team"

    condition:
        pe.rich_signature.toolid(0xf1, 40116) and
        pe.rich_signature.toolid(0xf3, 40116) and
        pe.rich_signature.toolid(0xf2, 40116) and
        pe.rich_signature.toolid(0x105, 26706) and
        pe.rich_signature.toolid(0x104, 26706) and
        pe.rich_signature.toolid(0x103, 26706) and
        pe.rich_signature.toolid(0x93, 30729) and
        pe.rich_signature.toolid(0x109, 27023) and      
        pe.rich_signature.toolid(0xff, 27023) and
        pe.rich_signature.toolid(0x97, 0) and
        pe.rich_signature.toolid(0x102, 27023)
}

rule costaricto_rich_header_august
{
    meta:
        description = "Rule to detect Rich header associated with CostaRicto campaign"
        author = "BlackBerry Threat Hunting and Intelligence Team"

    condition:
        pe.rich_signature.toolid(0xf1, 40116) and
        pe.rich_signature.toolid(0xf2, 40116) and
        pe.rich_signature.toolid(0xf3, 40116) and
        pe.rich_signature.toolid(0x102, 26428) and
        pe.rich_signature.toolid(0x103, 26131) and
        pe.rich_signature.toolid(0x104, 26131) and
        pe.rich_signature.toolid(0x105, 26131) and
        pe.rich_signature.toolid(0x103, 26433) and
        pe.rich_signature.toolid(0x104, 26433) and
        pe.rich_signature.toolid(0x109, 26428) and
        pe.rich_signature.toolid(0x93, 30729) and
        pe.rich_signature.toolid(0xff, 26428)
}

rule costaricto_rich_xor_key
{
    meta:
        description = "Rule to detect Rich header associated with CostaRicto campaign"
        author = "BlackBerry Threat Hunting and Intelligence Team"     

    condition:
        // x86 droppers
        pe.rich_signature.key == 0x2e8d923f or
        pe.rich_signature.key == 0x97d94c45 or

        // x86 payload
        pe.rich_signature.key == 0xef257087 or
        pe.rich_signature.key == 0x4f257087 or
        pe.rich_signature.key == 0x1e816e7e or

        // x64 payload
        pe.rich_signature.key == 0xd1e5ae6c or
        pe.rich_signature.key == 0x5df9c60b
}

rule costaricto_sombrat_unpacked
{
    meta:
        description = "Rule to detect unpacked SombRAT backdoor"
        author = "BlackBerry Threat Hunting and Intelligence Team"

    strings:
        // class names
        $a1 = "PEHeadersBackup"
        $a2 = "PeLoaderDummy"
        $a3 = "PeLoaderLocal"
        $a4 = "PeLoaderBaseClass"
        $a5 = "PDTaskman"
        $a6 = "PDMessageParamArray"
        $a7 = "NetworkDriverLayerWebsockets"
        $a8 = "NetworkDriverLayerDNSReader"
        $a9 = "WaitForPluginIOCPFullyClosed"

        // substitution-encrypted strings
        $b1 = "~ydcv{{rs{~|r"           // installedlike
        $b2 = "~yg{vcqxez"              // winplatform
        $b3 = "~yqxezvc~xyvttrgcrs"     // informationaccepted
        $b4 = "xvsqexzdcxevpr"          // loadfromstorage
        $b5 = "xvsqexzzrzxen"           // loadfrommemory
        $b7 = "xgrydcxevpr"             // openstorage
        $b8 = "g{bp~y{xvstxzg{rcr"      // pluginloadcomplete
        $b9 = "g{bp~yby{xvs"            // pluginunload

        // AES-encrypted strings
        $c1 = {44 5B 7F 52 0C 13 52 1A 16 45 4C 75 65 72 60 53}

        // RSA public key
        $d1 = {EF C9 77 B9 A3 8E 48 92 77 C8 E1 E1 0C 46 35 2B}

    condition:
        uint16(0) == 0x5a4d and filesize < 5MB and filesize > 20KB and any of them
}

rule costaricto_pcheck_proxy
{
    meta:
        description = "Rule to detect a custom proxy tool related to the CostaRicto campaign"
        author = "BlackBerry Threat Hunting and Intelligence Team"      

    strings:
        $a = "exe.exe host host_port proxy_host proxy_port"
        $b = "Tool jobs done"

    condition:
        uint16(0) == 0x5a4d and filesize < 500KB and filesize > 10KB and ($a or $b)
}

rule costaricto_pscan_port_scanner
{
    meta:
        description = "Rule to detect a custom proxy tool related to the CostaRicto campaign"
        author = "BlackBerry Threat Hunting and Intelligence Team"      

    strings:
        $a1 = "Invalid arguments count (ver "
        $a2 = "Example: ./pscan"
        $a3 = "127-130.0.0.1"
        $b1 = "[output.txt]"
        $b2 = "Invalid ip address range"

    condition:
        uint16(0) == 0x5a4d and filesize < 500KB and filesize > 10KB and any of ($a*) or all of ($b*)
}

IDAPython スクリプト:

#!/usr/bin/python

import sys, os, struct, array

​fin = sys.argv[1]
fout = "%s_decoded" %(fin)
f = open(fin, "r+w+b")
f2 = open(fout, "w+b")
encsize = os.path.getsize(fin) / 4

​key_1 = 0x14820285
key_2 = 0x26820323
key_3 = 0x35223562
key_4 = 0x41256421
cst_1 = 0x61C88647
cst_2 = 0x9E3779B9

​enc = array.array('I')
enc.read(f, encsize)

​i = 0

while i < encsize:
    encdw_1 = enc[i]
    encdw_2 = enc[i+1]

    tmp_1a = encdw_1 << 4 & 0xffffffff
    tmp_1b = encdw_1 >> 5 & 0xffffffff
    tmp_1c = encdw_1 - cst_1 & 0xffffffff
    tmp_2a = tmp_1a + key_3 & 0xffffffff
    tmp_2b = tmp_1b + key_4 & 0xffffffff
    tmp_3 = tmp_2a  ^ tmp_1c

    keydw_2 = tmp_3 ^ tmp_2b
    decdw_2 = encdw_2 - keydw_2 & 0xffffffff

    magic_1 = decdw_2 << 4 & 0xffffffff
    magic_2 = decdw_2 >> 5 & 0xffffffff
    key_1a = key_1 + magic_1 & 0xffffffff
    key_2a = key_2 + magic_2 & 0xffffffff
    cst_2a = cst_2 + decdw_2 & 0xffffffff
    tmp_5 = key_1a ^ cst_2a

​    keydw_1 = tmp_5 ^ key_2a
    decdw_1 = encdw_1 - keydw_1 & 0xffffffff

    data1 = struct.pack('I', decdw_1)
    data2 = struct.pack('I', decdw_2)

​    f2.seek(i*4)
    f2.write(data1)
    f2.seek(i*4+4)
    f2.write(data2)

    i = i + 2

図 24:SombRAT ペイロード復号スクリプト

 

import idc, idaapi, idautils
import idautils
import string, array, struct, binascii

def isprintable(s, codec='ascii'):
    try: s.decode(codec)
    except UnicodeDecodeError: return False
    else: return True

def get_int(addr):
    return struct.unpack('I', get_bytes(addr, 4))[0]

def add_comment(offset, comment):
    idc.MakeComm(offset, comment)
    target = idc.DfirstB(offset)
    while target != BADADDR:
        idc.MakeComm(target, comment)
        target = idc.DnextB(offset, target)

def substitution(start, size, patch):
    dec = ""
    enclen = size
    plain = "`abcdefghijklmnopqrstuvwxyz{|}~H&\x7F"
    key =   "wvutsrqp\x7F~}|{zyxgfedcba`onmlkji&Hh"
    if len(key) != len(plain):
        warning("Lenght differs!")
    i = 0
    for i in range(enclen):
        c = Byte(start + i)
        idx = key.find(str(chr(c)))
        if idx != -1:
            c = plain[idx]
        else:
            c = str(chr(c))
        dec = dec + c
        if patch == True:
            patch_byte(start + i, c)
        i += 1
    return dec

​# iterate over all segments
for s in idautils.Segments():
    if ".data" in idc.SegName(s):
        start = idc.GetSegmentAttr(s, idc.SEGATTR_START)
        end = idc.GetSegmentAttr(s, idc.SEGATTR_END)
        num = 0
        while start < end - 4:
            if get_int(start) == 0:
                enclen = get_int(start+4)
                encstrcheck = get_int(start+8)
                if enclen > 1 and enclen < 100 and encstrcheck > 0x2020:
                    encstr = idc.get_bytes(start+8, enclen)
                    if isprintable(encstr) == True:
                        num += 1
                        startaddr = start+8

                        print("#%i") %num
                        print("address = 0x{:08x}".format(start))
                        print("len = %i") %enclen
                        print("encstr = %s") %encstr
                        decstr = ""
                        decstr = substitution(startaddr, enclen, 0)
                        print("decstr =%s") % decstr
                        print("-----------------------------------------")
                        idc.MakeComm(start, "{}".format(decstr))
                        decname = "s_" +
                          (
''.join(e for e in decstr if e.isalnum()))[:20]
                        decname = decname.strip()
                        res = MakeNameEx(start, decname,
                                         SN_NOCHECK | SN_NOWARN | 0x800)                      

            start += 4

図25:SombRAT 文字列符号 IDA Python スクリプト(x86 ペイロード用)


The BlackBerry Research and Intelligence Team

About The BlackBerry Research and Intelligence Team

BlackBerry の Research and Intelligence Team は、新たに生じている脅威と持続的な脅威を検証し、セキュリティ担当者とその所属企業のために、インテリジェンス解析を提供しています。