Analyzing A GO Malware
Hello Friends,
This post covers my analysis of a Linux-based Go malware sample. It used anti-VM evasion techniques, which made it harder for sandbox environments to detect. Reverse engineering this sample was really interesting, especially the C2 agent and data exfiltration parts, which operated in unexpected ways.
Overview
The sample analyzed was a multi-stage Go-based loader designed to fetch, decrypt, and execute multiple payloads. Its modular structure allowed each stage to handle a specific responsibility, gradually building toward full system compromise and data exfiltration.
Stage 1 – Initial Loader
The first stage downloads two components:accessandinter_ddns. The access binary is responsible for decrypting inter_ddns, enabling the next execution phase.Stage 2 – Core Loader (inter_ddns)
Once decrypted, inter_ddns operates as the core loader. It retrieves four additional binaries —access2,server2,access3, anddrive— and executes them sequentially.Stage 3 – Command & Control
The server2 binary establishes communication with the Command-and-Control (C2) server, enabling remote access control.Stage 4 – Data Exfiltration
The drive binary is responsible for exfiltrating files to Google Cloud Platform (GCP), completing the attack chain.
Why Go is a Popular Choice for Threat Actors
So, why are threat actors turning to Go? The answer is simple and lies in some of the language's core features:
Static Linking: Go binaries are statically linked by default, which means they include all necessary dependencies. This makes the malware highly portable, as it can be run on any system without worrying about missing libraries. This also often results in a larger binary size, which can help it evade some signature-based detection systems.
Native Cross-Compiling: Go's built-in support for cross-compilation is a huge advantage. A developer can write a single codebase and easily compile it for different operating systems (like Windows, macOS, and Linux) and architectures.
Ease of Use: Compared to languages like C or C++, Go is relatively easier to code.
With the help of AI it is even easier to write custom malware and C2 infrastructures using go lang.
Note
There are many resources available for detailed information on Go Lang binary internals, which you can check out here :-
Golang Reverse Engineering Tips - Travis Mathison
Go Internals and Symbol Recovery - Google Threat Intelligence
Including all those topics would make this blog too long, so feel free to explore them separately.
Analysis
Except for the server2 payload, all other payloads were Go-based. I used the following tools to analyze them:
IDA Free performed better than Ghidra and Binary Ninja when decompiling Go binaries, as IDA automatically rebuilds the PCLN and recovers most of the symbols.
redress is an excellent tool for analyzing stripped Go binaries. It provides detailed information about Go packages and source files.
Finally, CAPE was used to extract C2 information from the server2 payload, as it was a MeshAgent.
Loader 1
The name of the file may vary depending on the delivery method used by the threat actors, so I would refer to the binary as the Initial Loader. The purpose of the Initial Loader is to deliver an encrypted second-stage component, which then downloads and executes the final C2 agent and exfiltrator payloads.
Using the Redress tool, we obtained a clear overview of the Go binary, including the original package name, ddns. The analysis also indicated that the threat actors were building these malware payloads in a Kali VM.
Functions List
The loader first checks if the system is running inside a virtual machine by calling RealCheck function. It then verifies if the internet connectivity is present through HomeChecker. If no connection is detected, a Zenity error dialog is displayed with "Boss Internet Issue". If the loader detects VM, it self-deletes and remove all traces by calling the HiddenHome function.
Finally, the loader decrypts a set of encrypted URLs using the decrypt function. From these URLs, it retrieves additional stagers via the downloadFile function and executes them.
The loader attempted to determine whether it was running inside a virtual machine by reading system files such as /sys/class/dmi. Probably the threat actors used ChatGPT or similar AI tools based on the level of plain VM checks.
The HomeChecker function verifies internet connectivity by sending a ping request to Google. If the connection check fails, the loader assumes the system is offline and halts further execution.
The decrypt function accepts three arguments: the ciphertext, the DES key, and the IV. It first decodes the ciphertext from Base64, then initializes a DES cipher in CBC mode using the provided key and IV. After decryption, the resulting plaintext is used as configuration data, such as payload download URLs.
Based on the disassembly, I crafted an potential source code for the function.
func decrypt(cipherEncoded string, keyEncoded string, ivEncoded string) {
cipher, _ := base64.StdEncoding.DecodeString(cipherEncoded)
key, _ := base64.StdEncoding.DecodeString(keyEncoded)
iv, _ := base64.StdEncoding.DecodeString(ivEncoded)
block, _ := des.NewCipher(key)
mode := cipher.NewCBCDecrypter(block, iv)
plain := make([]byte, len(cipher))
mode.CryptBlocks(plain, cipher)
}
The loader contained three encrypted strings: two corresponding to drive URLs and one serving as the password required to decrypt the inter_ddns payload.
The threat actors used the email address simonedaira@gmail.com to share the payloads via Google Drive. A lookup in Epieos revealed that the account had been updated only recently.
After downloading the two files, the loader decrypts the final string and uses it as an argument when executing the access binary.
The loader tries to execute access binary with args -f inter_ddns and -d WOrkiNgtoDesksSS8123whyme?youseethis.
After that, the loader executes the decrypted inter_ddns payload and then calls the HiddenHome function to remove all of its traces.
The remaining responsibilities are handed over to inter_ddns, but before analyzing it, let’s first examine the access binary.
Decrypter
The access binary was packed with UPX and functioned as an encrypter/decrypter. It supported help argument that displayed all available options. The binary was capable of both RC4 and AES decryption.
Functions List
The decrypter first calls the processFile function, which receives the provided password and file name as arguments. Depending on the selected decryption option (aes or rc4), the password is hashed using either SHA-256 (for AES) or MD5 (for RC4). The function then reads the target file and passes the data to the processBytes function, which handles the actual decryption. Inside processBytes, execution branches to either aesDecryptEncrypt or rc4DecryptEncrypt, depending on the chosen algorithm.
For AES decryption, the malware uses CTR mode. The encryption key is derived by computing the SHA-256 hash of the provided password. This derived key is then used to perform decryption on the target data.
Using the password WOrkiNgtoDesksSS8123whyme?youseethis we decrypted inter_ddns which was another go based binary.
Loader 2
Unlike the first loader, this second-stage loader carries broader responsibilities beyond just downloading and executing payloads. It establishes persistence on the system and deploys the final C2 agent along with the Exfiltrator payload.
Functions List
The loader begins by checking for VM artifacts. If none are found, it proceeds to download access2 and server2 via the download function. The loader then decrypts the password required by access2 to unlock server2, which is subsequently executed as the C2 agent. To maintain long-term access, the livingoftheland functions establishes persistence, after which the selfdelete function removes the binary to minimize forensic traces.
In the next stage, the loader retrieves and executes access3 and drive. Once executed, access3 is deleted while persistence remains intact. The process concludes with the removal of the inter_ddns binary, completing the full attack cycle.
The newly downloaded access binaries are essentially same as the first access binary.
The first function, livingoftheland1, establishes persistence for the server2 C2 agent by creating a systemd service under $HOME/.config/systemd/user/. Once the service is created, it is immediately started and enabled to run on user login.
The second function, livingoftheland2, performs a similar role to the previous function. However, in this instance, it establishes persistence specifically for the drive binary
C2 Agent
What stands out in this case is that, instead of deploying a custom C2 agent, the threat actors leveraged MeshAgent, an open-source remote management tool.
This agent can be connected to their custom hosted MeshCentral server which allows all sort of Remote access.
For simplicity, the sample was run inside the CAPE sandbox, as it didn't had any evasion techniques and we were able to extract the C2 server information :
boss-servers.gov.in.indianbosssystems.ddns.net
While checking this C2 domain we got the information about server which was hosted in AWS EC2.
Further investigation of the domain revealed that multiple domains were pointing to the same EC2 IP address: 54.144.107.42
The portal had some login page however couldn't interact with it much.
Exfiltrator
The exfiltrator had many functions for maximum data collection and leveraged a Google Cloud Platform (GCP) service account to exfiltrate data directly to Google Drive.
Similar to previous payloads, it performs anti-VM checks, examines os-release using the EasyFel function, and additionally collects the device's MAC address, username, and hostname metadata.
It scans for all common non-zero byte files present in user local directories and mounted paths, collects the hosts file, and generates metadata for all files, which are uploaded alongside the files. It also monitors directories and mount paths for new files and repeats the exfiltration process whenever new files are found.
Functions List
They check for all kind of files with the help of find command and collect them from user's home directory and local directories.
It also checks for USB drives mounted on the system and exfiltrate from the drives.
In this function the service account token is being decrypted.
However, when I checked the associated service account were already deactivated or removed.
Finally the collected files are uploaded to drive.