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 |