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
コンフィグデータはファイル末尾に格納されており、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
ReadNimeLoader
ReadNimeLoaderの特徴として次に示す4つの耐解析機能があります。
- PEBのBeingDebuggedの値によるデバッグの有無のチェック
- CONTEXT_DEBUG_REGISTERの値によるデバッグの有無のチェック
- 経過時間の差分を取得し、その値がある0x512以上であればデバッグの有無のチェック
- 例外を発生させ、例外ハンドラーが取得されるかをチェックすることによるデバッグの有無のチェック
上記の耐解析機能の関数内部にOdinLdrの復号に必要な鍵の一部が格納されており、その関数を実行しないと正しい鍵が生成されず、OdinLdrを復号できない仕組みになっています。また、それ以外の耐解析機能として無意味なコードが挿入されています。そのコードの一部を図3に示します。
ReadNimeLoaderが使用する文字列はエンコードされており、XORをベースとした2つの特徴的なデコード関数が使用されます。そのコードの一部を図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にコンフィグパーサーの実行結果の例を示します。
おわりに
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 |