CrossC2 Expanding Cobalt Strike Beacon to Cross-Platform Attacks
From September to December 2024, JPCERT/CC has confirmed incidents involving CrossC2, the extension tool to create Cobalt Strike Beacon for Linux OS. The attacker employed CrossC2 as well as other tools such as PsExec, Plink, and Cobalt Strike in attempts to penetrate AD. Further investigation revealed that the attacker used custom malware (hereafter referred to as "ReadNimeLoader") as a loader for Cobalt Strike. Information submitted to VirusTotal suggests that this attack campaign may have been observed across multiple countries, not only in Japan. This article explains CrossC2 and Cobalt Strike, the malware used in the campaign, as well as other tools employed by the attacker. A tool released by JPCERT/CC to support the analysis of CrossC2 is also introduced at the end.
CrossC2
CrossC2 is an unofficial Beacon and builder compatible with Cobalt Strike version 4.1 and above, developed in C language. It is designed to operate on Linux (x86, x64) and macOS (x86, x64, M1) architectures. While the builder is publicly available on GitHub[1], allowing users to create Beacons, the source code for both the builder and the Beacon are not released.
Upon execution, CrossC2 immediately forks itself, and the main processing is carried out in the child process. The C2 information is retrieved from the configuration, while the C2 server host and port number can also be obtained from the environment variables "CCHOST" and "CCPORT". Once executed, CrossC2 is capable of executing various Cobalt Strike commands after establishing communication with the Cobalt Strike TeamServer. However, the range of executable commands is limited compared to the full functionality of standard Cobalt Strike. The Beacon contains the following multiple anti-analysis features:
- String encoding using single-byte XOR
- Insertion of a large amount of junk code
Figure 1 shows a part of the inserted junk code. A significant amount of such code is embedded in key functions. However, the obfuscation can be easily removed by replacing the following byte sequence with NOP instruction.
8B 85 ?? ?? ?? ?? 2D ?? ?? ?? ?? 89 85 ?? ?? ?? ?? 0F 84 ?? ?? ?? ?? E9 00 00 00 00
The configuration data is stored at the end of the file. CrossC2 first retrieves its own file path using the readlink function and then fread its own code. It keeps searching for the string "HOOK" to locate the address of the configuration data. The structure of the configuration is as shown below. The encrypted configuration data can be decrypted using AES128-CBC(no padding). CrossC2 uses OpenSSL library functions to perform the decryption.
0x0: "HOOK" search tag 0x4: Size of the configuration data 0x8: Encrypted configuration data
CrossC2 can create Beacon using legitimate TeamServer extensions. By default, the generated Beacon is packed with UPX, but attempting to unpack it with UPX fails due to the configuration information at the end of the file. To unpack the Beacon successfully, the configuration block must first be removed. After unpacking using UPX, the configuration block needs to be reinserted at the end.
Cobalt Strike
Figure 2 illustrates the flow of Cobalt Strike execution. The process is initiated by a legitimate java.exe file, which is executed from a Task Scheduler job registered by the attacker. This java.exe loads jli.dll through DLL sideloading. The DLL file is ReadNimeLoader, which is written in Nim language. ReadNimeLoader reads a data file named readme.txt from the same directory, decrypts it, and executes its content in memory. This file contains OdinLdr[2], an open-source Shellcode-format loader, which decodes the embedded Cobalt Strike Beacon and executes it in memory. All related files, including ReadNimeLoader, were located under "C:\$recycle.bin\" on the affected system. In addition, some ReadNimeLoader samples were found to contain the following PDB path.
D:\BuildServer\bna-4\work-git\phoenix-repository\phoenix\Release\Battle.net Launcher.exe.pdb
ReadNimeLoader
ReadNimeLoader incorporates the following four anti-analysis techniques:
- Detect debugging by checking BeingDebugged value in PEB
- Detect debugging by checking CONTEXT_DEBUG_REGISTER value
- Measure the difference of elapsed time and proceed to debag checking when the value exceeds 0x512
- Detect debugging by causing an exception and checking whether an exception handler is obtained
A part of the decryption key required to decode OdinLdr is embedded within the functions for the abovementioned anti-analysis techniques. As a result, unless these functions are executed, the correct decryption key is not generated, and OdinLdr cannot be decrypted. In addition to these anti-analysis mechanisms, a large amount of junk code is also inserted. Figure 3 shows a part of the code.
Strings used by ReadNimeLoader are encoded, and they are decoded using two distinct XOR-based decoding functions. Figure 4 shows a portion of each code.
The encoded strings can be decoded using the Python script shown below. In earlier versions of ReadNimeLoader do not contain the decode02 function, indicating that it was added in a later version.
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 uses AES256-ECB mode to decrypt the malware payload. The key is created by combining specific strings decoded by the aforementioned decoding functions, which is then converted into hexadecimal format, transformed to uppercase, and zero-padded. This decryption can be performed using the following Python script:
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
After execution, OdinLdr decrypts the internally encoded Cobalt Strike Beacon and runs it in memory. To avoid detection, the Beacon is periodically re-encrypted using a randomly generated XOR key and stored in newly allocated heap memory. It is a distinctive characteristic that there is the string "OdinLdr1337" at the beginning of the heap memory. Additionally, it has been confirmed that there are two types of Shellcode deployed by ReadNimeLoader: some samples execute the Cobalt Strike Beacon through OdinLdr, while others run the Beacon directly. Appendix B outlines the relations between ReadNimeLoader versions and their corresponding decryption keys, the specific readme.txt files loaded, and the encoded malware payloads. A part of the Cobalt Strike configuration used is included in the appendix.
Tools used by the attacker
Among the tools used by the attacker, multiple ELF versions of SystemBC were identified. For more information on the differences from the Windows version of SystemBC, please refer to the report by ANY.RUN [3]. Other confirmed tools include PsExec, commonly used for lateral movement; GetNPUsers [4], often leveraged in AS-REP Roasting attacks; Plink, an SSH client tool; and privilege escalation tools for Windows systems.
Attribution
Despite architectural differences, confirmed identical characteristics suggest that this attacker and the attack campaign have a potential connection to BlackBasta. More specifically, the domain confirmed to be used for the C2 in this campaign matches the one listed in Rapid7’s report on BlackBasta [5]. Further similarities include the use of the files named jli.dll and readme.txt. Additionally, SystemBC was leveraged, and when attacking AD, AS-REP was also used.
Tools for analyzing CrossC2
As an analysis tools for CrossC2, a configuration parser is publicly available on JPCERT/CC’s GitHub.
GitHub: JPCERTCC/aa-tools/parse_crossc2beacon_config.py
https://github.com/JPCERTCC/aa-tools/blob/master/parse_crossc2beacon_config.py
CrossC2 can generate binaries for macOS, not only for Linux, and this parser is designed to support macOS binaries as well. Figure 5 shows a sample output from running the configuration parser.
In Closing
While there are numerous incidents involving Cobalt Strike, this article focused on the particular case in which CrossC2, a tool that extends Cobalt Strike Beacon functionality to multiple platforms, was used in attacks, compromising Linux servers within an internal network. Many Linux servers do not have EDR or similar systems installed, making them potential entry points for further compromise, and thus more attention is required. We hope the information provided in this article will be useful to you in incident response and malware analysis. For details on confirmed C2 servers and malware hash values, please refer to the Appendix.
Yuma Masubuchi (Translated by Takumi Nakano)
References
[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: Example of CrossC2 configuration
C2: 162.33.179[.]247:8443 PUBLICKEY: -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCaW 34Iv7znqVuomjiJn4Yr1ck9YSWylfAoiy20DnR0ab CoHtdPK3L05CgOjnLGSfM5Vji0IRd8xtCGpU699Jt FCa/Jg7zmuejilkKTFpMB36+49UQtaYp4KjFuImRC z72NdzszsLzHDlVWAPmn5CSTfsTIzceomQfmCDY// IygzQIDAQAB -----END PUBLIC KEY-----
Appendix B: The relations between ReadNimeLoader and malware payloads
Table 1: The relations between ReadNimeLoader and malware payloads
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: Example of Cobalt Strike configuration
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: Malware
Table 2: List of malware and tools
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-related tool | hhupd.exe | d74eac55eeaa3138bc1e723c56013bb1af7709f0a77308bfbf268d4e32b37243 |