Cobalt Strike Beaconの機能をクロスプラットフォームへと拡張するツール「CrossC2」を使った攻撃

JPCERT/CCでは、2024年9月から12月にかけて、Linux上で動作するCobalt Strike Beaconを作成可能な拡張ツールCrossC2を使ったインシデントを確認しました。この攻撃者は、CrossC2以外にもPsExecやPlink、Cobalt Strikeを使用してADへの侵入を試みていました。さらに、Cobalt Strikeのローダーとして独自のマルウェア(以下、「ReadNimeLoader」という。)を使用していることを確認しています。この攻撃キャンペーンは、VirusTotalのSubmit情報から、日本だけでなく複数の国で観測されていた可能性があります。

今回は、この攻撃キャンペーンで確認したマルウェアCrossC2およびCobalt Strike、攻撃者が使用するツールについて解説します。また、最後にJPCERT/CCが公開したCrossC2の分析をサポートするツールについても紹介します。

CrossC2

CrossC2はC言語で作成されたCobalt StrikeのVersion 4.1以上に対応した非公式のBeaconとそのビルダーです。Linux(x86、x64)、macOS(x86、x64、M1)のアーキテクチャで動作するよう開発されています。CrossC2のビルダーはGitHub[1]で公開されており、Beaconを作成することができますが、ビルダーのソースコードや、Beaconのソースコードは公開されていません。

CrossC2は実行するとすぐにForkし、メインの処理は子プロセス上で行われます。通信先はコンフィグから取得しますが、環境変数"CCHOST""CCPORT"からC2サーバーのホストとポート番号を取得することも可能です。実行後、CrossC2はCobalt StrikeのTeamServerと通信を行い、Cobalt Strikeの各種コマンドを実行することができますが、実行可能なコマンドは本来のCobalt Strikeの機能と比べて多くはありません。Beaconの特徴として次に示す複数の解析妨害機能が実装されています。

  • 1バイトXORによる文字列のエンコード
  • 大量の無意味なコードの挿入

図1に挿入されている無意味なコードの一部を示します。主要な関数には大量に無意味なコードが挿入されていますが、次のバイト列をNOP命令に置換することで容易に難読化解除が可能です。

8B 85 ?? ?? ?? ?? 2D ?? ?? ?? ?? 89 85 ?? ?? ?? ?? 0F 84 ?? ?? ?? ?? E9 00 00 00 00

図1:CrossC2の難読化コードの一部


コンフィグデータはファイル末尾に格納されており、CrossC2はreadlink関数にて自身のファイルパスを取得後、自身のコードをfreadし、"HOOK"という文字列が見つかるまで検索することでコンフィグデータのアドレスを取得しています。コンフィグの構造は以下のようになっており、暗号化されたコンフィグデータはAES128-CBC(no-padding)で復号することができます。なお、CrossC2はOpenSSLライブラリの関数を使用して復号しています。

0x0:"HOOK" 検索タグ
0x4:コンフィグデータのサイズ
0x8:暗号化されたコンフィグデータ

CrossC2は正規のTeamServerの拡張機能を利用してBeaconを作成することができます。作成されたBeaconはデフォルトの設定ではUPXでパックされていますが、UPXでアンパックしようとすると失敗してしまうため、アンパックする場合は、一度ファイル末尾のコンフィグ情報を取り除いた後にUPXにてアンパックを行い、アンパック後のファイル末尾にコンフィグ情報を追加する必要があります。

Cobalt Strike

図2にCobalt Strikeが実行されるまでの流れを示します。マルウェアの実行の起点となるのは、攻撃者によって登録されたタスクスケジューラから実行される正規ファイルのjava.exeです。java.exeは、DLLサイドローディングによってReadNimeLoaderであるjli.dllをロードします。ReadNimeLoaderは、Nim言語で作成されたローダーです。ReadNimeLoaderは同一フォルダーにあるデータファイルreadme.txtを読み込み、復号した後、メモリ上で実行します。readme.txtには、オープンソースのShellcode形式ローダーであるOdinLdr[2]が含まれており、OdinLdrが内部にエンコードされているCobalt Strike Beaconをデコードし、メモリ上で実行します。なお、ReadNimeLoaderなどファイル一式は被害端末の"C:\$recycle.bin\"のパスに保存されていました。また、一部のReadNimeLoaderに以下のPDBパスが設定されていたことを確認しています。

D:\BuildServer\bna-4\work-git\phoenix-repository\phoenix\Release\Battle.net Launcher.exe.pdb

図2:Cobalt Strikeが実行されるまでの動作フロー


ReadNimeLoader

ReadNimeLoaderの特徴として次に示す4つの耐解析機能があります。

  • PEBのBeingDebuggedの値によるデバッグの有無のチェック
  • CONTEXT_DEBUG_REGISTERの値によるデバッグの有無のチェック
  • 経過時間の差分を取得し、その値がある0x512以上であればデバッグの有無のチェック
  • 例外を発生させ、例外ハンドラーが取得されるかをチェックすることによるデバッグの有無のチェック

上記の耐解析機能の関数内部にOdinLdrの復号に必要な鍵の一部が格納されており、その関数を実行しないと正しい鍵が生成されず、OdinLdrを復号できない仕組みになっています。また、それ以外の耐解析機能として無意味なコードが挿入されています。そのコードの一部を図3に示します。

図3:妨害コードの一部


ReadNimeLoaderが使用する文字列はエンコードされており、XORをベースとした2つの特徴的なデコード関数が使用されます。そのコードの一部を図4にそれぞれ示します。

図4:各デコード関数


エンコードされた文字列は、次に示すPythonスクリプトでデコードすることが可能です。なお、古いバージョンのReadNimeLoaderではPythonスクリプトのdecode02の関数に該当するデコード関数は存在しておらず、バージョンアップによって後から追加された関数と考えられます。

def BYTE1(in_data):
    return (in_data >> 8) & 0xff


def BYTE2(in_data):
    return (in_data >> 16) & 0xff


def BYTE3(in_data):
    return (in_data >> 24) & 0xff


def decode02(enc_bytes, xor_key):
    result = []
    for enc_byte in enc_bytes:
        enc_byte ^= BYTE3(xor_key) & 0xEE ^ BYTE2(xor_key) & 0xEE ^ (xor_key ^ BYTE1(xor_key)) & 0xEE
        result.append(i)
        enc_byte += 1
    return result


def decode01(enc_bytes, xor_key):
    xor_table = [ 0, 8, 0x10, 0x18]
    result = []
    for enc_byte in enc_bytes:
        for j in range(4):
            enc_byte ^= ((xor_key >> xor_table[j]) & 0xEE)
        result.append(i)
    return result

ReadNimeLoaderはマルウェア本体の復号方法にAES256-ECBモードを使用します。復号に使用する鍵は前述したデコード関数でデコードされた特定の文字列をつなげて一つの文字列にし、それらを16進数へと変換した後、文字列として大文字へ変換し、ゼロパディングしたものを使用します。次に示すPythonスクリプトで復号することが可能です。

from Crypto.Cipher import AES
import binascii

def ZeroPadding(hexstr, num):
    padding_num = num - len(hexstr)
    if padding_num < 0:
        return hexstr
    return  hexstr + b"\x00" * padding_num


def decrypt(readme_data, key_string):
    capitalized_key = binascii.hexlify(ascii_to_bytes(key_string)).upper()
    key = ZeroPadding(capitalized_key, 32)
    Cipher = AES.new(key, AES.MODE_ECB)
    return Cipher.decrypt(readme_data)

OdinLdr

OdinLdrは実行後に内部にエンコードされたCobalt Strike Beaconを復号し、メモリ上で動作しますが、一定周期でランダムに生成されるXOR鍵をもとに新しく確保したヒープメモリ上に暗号化される仕組みであり、メモリのスキャンなどを回避することを狙って使用されたものと思われます。ヒープメモリの先頭アドレスに"OdinLdr1337"という文字列がある点が特徴としてあげられます。なお、ReadNimeLoaderが展開するShellcodeにはOdinLdrを介してCobalt Strike Beaconを実行するものと直接Cobalt Strike Beaconを実行するサンプルも確認されています。

Appendix BにReadNimeLoaderのバージョンとマルウェア本体をデコードする際に使用する鍵、ロードするreadme.txt、エンコードされるマルウェア本体の対応関係を記載します。なお、使用されたCobalt Strikeのコンフィグの一部をAppendixに記載しています。

攻撃者が使用するツール

攻撃者によって使用されたツールとして、複数のELF版のSystemBCが使用されていました。Windows版SystemBCとの差分などの情報はanyrunによる報告[3]をご覧ください。その他使用されたツールとして、横展開に使用されることが多いPsExec、AS-REP Roasting攻撃に使用されるGetNPUsers[4]、SSHクライアントツールのPlink、Windowsにおける権限昇格ツールなどが確認されています。

帰属

確認したCobalt StrikeのC2に使用されたドメインがRapid7によって公開されているBlackBastaの記事[5]のC2と同一である点、ReadNimeLoaderに使用されるjli.dllとreadme.txtというファイル名の各ファイルが使用された点、動作するアーキテクチャは異なるもののSystemBCを使用する点やADへの攻撃にAS-REPを使用する点も一致していることから、本攻撃者および攻撃キャンペーンはBlackBastaと何らかの関係がある可能性が考えられます。

CrossC2の分析ツール

CrossC2用分析ツールとして、コンフィグパーサーをGitHub上で公開していますので、ご活用ください。

GitHub:JPCERTCC/aa-tools/parse_crossc2beacon_config.py
https://github.com/JPCERTCC/aa-tools/blob/master/parse_crossc2beacon_config.py

なお、CrossC2はLinuxだけでなく、macOS向けのバイナリを生成することもできますが、本コンフィグパーサーはmacOS向けバイナリにも対応しています。図5にコンフィグパーサーの実行結果の例を示します。

図5:コンフィグパーサーの動作例


おわりに

Cobalt Strikeを使ったインシデントは数多く存在しますが、Cobalt Strike Beaconの機能をクロスプラットフォームへと拡張するツールCrossC2が攻撃に利用され、内部ネットワークにあるLinuxサーバーが侵害される事例を今回確認しました。LinuxサーバーにはEDRなどが導入されていない場合も多く、侵害範囲を拡大する起点になり得るため、注意が必要です。今回解説した情報をインシデント対応や分析などにご活用いただければ幸いです。確認したマルウェアの通信先やハッシュ値については、Appendixに記載していますのでそれぞれご確認ください。

インシデントレスポンスグループ 増渕 維摩

参考情報

[1] CrossC2
https://github.com/gloxec/CrossC2

[2] OdinLdr
https://github.com/emdnaia/OdinLdr

[3] ANY.RUN
A new SystemBC RAT is targeting Linux-based platforms
https://x.com/anyrun_app/status/1884207667058463188

[4] GetNPUsers.py
https://github.com/fortra/impacket/blob/master/examples/GetNPUsers.py

[5] Rapid7
BlackSuit Continues Social Engineering Attacks in Wake of Black Basta’s Internal Conflict
https://www.rapid7.com/blog/post/2025/06/10/blacksuit-continues-social-engineering-attacks-in-wake-of-black-bastas-internal-conflict/

Appendix A:CrossC2のコンフィグの例

C2: 162.33.179[.]247:8443
PUBLICKEY: 
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCaW
34Iv7znqVuomjiJn4Yr1ck9YSWylfAoiy20DnR0ab
CoHtdPK3L05CgOjnLGSfM5Vji0IRd8xtCGpU699Jt
FCa/Jg7zmuejilkKTFpMB36+49UQtaYp4KjFuImRC
z72NdzszsLzHDlVWAPmn5CSTfsTIzceomQfmCDY//
IygzQIDAQAB
-----END PUBLIC KEY-----

Appendix B:ReadNimeLoaderとマルウェア本体との対応関係

表1 ReadNimeLoaderとマルウェア本体との対応関係

ReadNimeLoader Hash(SHA256) Version Key readme.txt Hash(SHA256) Encoded Malware
56b941f6dcb769ae6d6995412559012abab830f05d5d8acf2648f7fa48c20833 New toupper(to_hex("mfzuyqroasv")) + zero padding 6246fb5c8b714707ac49ade53e6fe5017d96442db393b1c0ba964698ae24245d OdinLdr + CobaltStrike
dfe79b9c57cfb9fc10597b43af1c0a798991b6ceeec2af9b1e0ed46e6a8661c8 New toupper(to_hex("vbewtdsmmswfweoz")) acdf2a87ed03f2c6fe1d9899e8a74e8b56f7b77bb8aed5adf2cc374ee5465168 OdinLdr + CobaltStrike
3f96b6589996e57abc1c4d9b732528d2d11dea5c814f8241170c14ca2cd0281d New toupper(to_hex("lgehaoevolq")) + zero padding 6b80d602472c76b1d0f05bcce62e0a34de758232d9d570ba61b540784c663c01 CobaltStrike
0ab709728666f8759ad8db574d4009cf74ebce36ef2572ef52b058997a9b2a25 New toupper(to_hex("ffjazoinsmsiywwt")) 3079a29575a0adff91f04c5493a7f3e1c89795e3a90cf842650cd8bd45c4e1bc CobaltStrike
ecca3194613b0bab02059c3544fdc90f6d4af5a4c06518c853517eb1d81b9735 Old toupper(to_hex("bcstctskmngpjjax")) Unknown Unknown
ad90a4490d82c7bd300fdbbdca0336e5ad2219d63ea0f08cebc33050d65b7ef2 Old toupper(to_hex("lklzndaawijhd")) + zero padding 70b3b8e07752c1f3d4a462b2ab47ca3d9fb5094131971067230031b8b2cd84f2 CobaltStrike
99d6b73b1a9e66d7f6dcb3244ea0783b60776efd223d95c4f95e31fde434e258 Old toupper(to_hex("ifovxtgokm|yzjwz")) Unknown Unknown

Appendix C:Cobalt Strikeのコンフィグの例

BeaconType                       - HTTPS
Port                             - 443
SleepTime                        - 30000
MaxGetSize                       - 2097328
Jitter                           - 40
MaxDNS                           - Not Found
PublicKey_MD5                    - d67a7903c6777d64b69845b6fcd5db65
C2Server                         - 64.95.10[.]209,/Collector/2.0/settings/,179.60.149[.]209,/Collector/2.0/settings/,64.52.80[.]62,/Collector/2.0/settings/
UserAgent                        - Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Teams/1.4.00.2879 Chrome/80.0.3987.165 Electron/8.5.1 Safari/537.36
HttpPostUri                      - /MkuiIJzM2IZs
Malleable_C2_Instructions        - Remove 46 bytes from the end
                                   Remove 130 bytes from the beginning
                                   NetBIOS decode 'a'
HttpGet_Metadata                 - ConstHeaders
                                        Accept: json
                                        Host: westeurope-teams.azureedge.net
                                        Referer: https://teams.microsoft.com/_
                                        x-ms-session-id: f73c3186-057a-d996-3b63-b6e5de6ef20c
                                        x-ms-client-type: desktop
                                        x-mx-client-version: 27/1.0.0.2021020410
                                        Accept-Encoding: gzip, deflate, br
                                        Origin: https://teams.microsoft.com
                                   ConstParams
                                        qsp=true
                                        client-id=NO_AUTH
                                        sdk-version=ACT-Web-JS-2.5.0&
                                   Metadata
                                        base64url
                                        parameter "events"
HttpPost_Metadata                - ConstHeaders
                                        Connection: Keep-Alive
                                        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                                   SessionId
                                        base64url
                                        parameter "id"
                                   Output
                                        base64url
                                        print
PipeName                         - Not Found
DNS_Idle                         - Not Found
DNS_Sleep                        - Not Found
SSH_Host                         - Not Found
SSH_Port                         - Not Found
SSH_Username                     - Not Found
SSH_Password_Plaintext           - Not Found
SSH_Password_Pubkey              - Not Found
SSH_Banner                       -
HttpGet_Verb                     - GET
HttpPost_Verb                    - POST
HttpPostChunk                    - 0
Spawnto_x86                      - %windir%\syswow64\powercfg.exe
Spawnto_x64                      - %windir%\sysnative\powercfg.exe
CryptoScheme                     - 0
Proxy_Config                     - Not Found
Proxy_User                       - Not Found
Proxy_Password                   - Not Found
Proxy_Behavior                   - Use IE settings
Watermark_Hash                   - NtZOV6JzDr9QkEnX6bobPg==
Watermark                        - 987654321
bStageCleanup                    - True
bCFGCaution                      - True
KillDate                         - 0
bProcInject_StartRWX             - True
bProcInject_UseRWX               - False
bProcInject_MinAllocSize         - 8096
ProcInject_PrependAppend_x86     - Empty
ProcInject_PrependAppend_x64     - Empty
ProcInject_Execute               - ntdll.dll:RtlUserThreadStart
                                   NtQueueApcThread-s
                                   SetThreadContext
                                   CreateRemoteThread
                                   kernel32.dll:LoadLibraryA
                                   RtlCreateUserThread
ProcInject_AllocationMethod      - VirtualAllocEx
bUsesCookies                     - False
HostHeader                       -
headersToRemove                  - Not Found
DNS_Beaconing                    - Not Found
DNS_get_TypeA                    - Not Found
DNS_get_TypeAAAA                 - Not Found
DNS_get_TypeTXT                  - Not Found
DNS_put_metadata                 - Not Found
DNS_put_output                   - Not Found
DNS_resolver                     - Not Found
DNS_strategy                     - round-robin
DNS_strategy_rotate_seconds      - -1
DNS_strategy_fail_x              - -1
DNS_strategy_fail_seconds        - -1
Retry_Max_Attempts               - 0
Retry_Increase_Attempts          - 0
Retry_Duration                   - 0

Appendix D:Network

  • 64.52.80[.]62:443
  • 64.95.10[.]209:443
  • 67.217.228[.]55:443
  • 137.184.155[.]92:443
  • 159.65.241[.]37:443
  • 162.33.179[.]247:8443
  • 165.227.113[.]183:443
  • 179.60.149[.]209:443
  • 192.241.190[.]181:443
  • api.glazeceramics[.]com:443
  • doc.docu-duplicator[.]com:53
  • doc2.docu-duplicator[.]com:53
  • comdoc1.docu-duplicator[.]com:53

Appendix E:マルウェア

表2 マルウェア・ツール一覧

Malware Filename Hash(SHA256)
java(Legitimate) java.exe 16b1819186f0803b9408d9a448a176142f8271a4bc0b42cdb78eb4489bce16fe
ReadNimeLoader jli.dll 56b941f6dcb769ae6d6995412559012abab830f05d5d8acf2648f7fa48c20833
ReadNimeLoader jli.dll dfe79b9c57cfb9fc10597b43af1c0a798991b6ceeec2af9b1e0ed46e6a8661c8
ReadNimeLoader jli.dll 3f96b6589996e57abc1c4d9b732528d2d11dea5c814f8241170c14ca2cd0281d
ReadNimeLoader jli.dll 0ab709728666f8759ad8db574d4009cf74ebce36ef2572ef52b058997a9b2a25
ReadNimeLoader jli.dll ecca3194613b0bab02059c3544fdc90f6d4af5a4c06518c853517eb1d81b9735
ReadNimeLoader jli.dll ad90a4490d82c7bd300fdbbdca0336e5ad2219d63ea0f08cebc33050d65b7ef2
ReadNimeLoader jli.dll 99d6b73b1a9e66d7f6dcb3244ea0783b60776efd223d95c4f95e31fde434e258
Cobalt Strike readme.txt 6246fb5c8b714707ac49ade53e6fe5017d96442db393b1c0ba964698ae24245d
Cobalt Strike readme.txt acdf2a87ed03f2c6fe1d9899e8a74e8b56f7b77bb8aed5adf2cc374ee5465168
Cobalt Strike readme.txt 6b80d602472c76b1d0f05bcce62e0a34de758232d9d570ba61b540784c663c01
Cobalt Strike readme.txt 3079a29575a0adff91f04c5493a7f3e1c89795e3a90cf842650cd8bd45c4e1bc
Cobalt Strike readme.txt 70b3b8e07752c1f3d4a462b2ab47ca3d9fb5094131971067230031b8b2cd84f2
CrossC2 gds 28d668f3e1026a56d55bc5d6e36fad71622c1ab20ace52d3ab12738f9f8c6589
CrossC2 gss 9e8c550545aea5212c687e15399344df8a2c89f8359b90d8054f233a757346e7
ELF-SystemBC monitor 74a33138ce1e57564baa4ea4db4a882d6bf51081b79a167a6cb2bf9130ddad7f
ELF-SystemBC monitor 7ccff87db7b4e6bc8c5a7e570f83e26ccb6f3a8f72388210af466048d3793b00
GetNPUsers GetNPUsers_windows.exe e0e827198a70eef6c697559660106cfab7229483b0cd7f0c7abd384a3d2ee504
Tools related to privilege escalation wermgr.exe f79e047ae4834e6a9234ca1635f18b074a870b366fe4368c10c2ddc56dfbb1bc
Tools related to privilege escalation wermgr.exe ac02aee660d44a8bfbc69e9c46cf402fd41e99915e13d0de3977e662ef13b2ca
Plink v0.81 conhost.exe 2e338a447b4ceaa00b99d742194d174243ca82830a03149028f9713d71fe9aab
PsExec v2.43 PsExec.exe 078163d5c16f64caa5a14784323fd51451b8c831c73396b967b4e35e6879937b
cab関連ツール hhupd.exe d74eac55eeaa3138bc1e723c56013bb1af7709f0a77308bfbf268d4e32b37243
≪ 前へ
トップに戻る