Developing Custom Offensive Tools in Go and Rust
For decades, the languages of choice for malware development were C and C++. They offered unparalleled, low-level access to the Windows API, memory management, and execution speed. However, as Endpoint Detection and Response (EDR) solutions have matured, they have become incredibly adept at analyzing and flagging compiled C/C++ binaries.
To stay ahead of the curve, modern Red Teams and threat actors are shifting their tool development to newer languages: Go (Golang) and Rust. In this post, we will explore why these languages are dominating the offensive security space and how they complicate the lives of Blue Teams.
Why the Shift? The Problem with C and C#
While C/C++ are powerful, they require developers to manually manage memory, which often introduces bugs that crash the payload (a massive OPSEC failure during an operation).
On the other hand, C# and the .NET framework became highly popular for offensive tools (like BloodHound and Covenant) because they are easy to write and interact seamlessly with Windows. However, as we discussed in previous posts, Microsoft introduced AMSI (Anti-Malware Scan Interface) and extensive .NET telemetry, making C# execution extremely noisy and highly scrutinized.
Go and Rust offer the perfect middle ground: they are compiled languages that offer memory safety, massive standard libraries, and most importantly, they generate binaries that traditional EDRs struggle to analyze effectively.
The Power of Go (Golang) in Red Teaming
Google’s Go language has become a staple in offensive security (powering tools like the Mythic C2 framework, Chisel, and Sliver).
1. Cross-Compilation Magic
Red Teams operate in heterogeneous environments. Go’s biggest advantage is its ability to effortlessly cross-compile. From a single Linux development machine, a Red Teamer can compile a payload for Windows, macOS, and Linux architecture with a single command:
GOOS=windows GOARCH=amd64 go build -o payload.exe
2. Statically Linked Binaries
By default, Go creates statically linked binaries. This means every library the payload needs to run is packed directly into the final executable. The malware doesn't need to rely on the victim's machine having specific DLLs or runtimes installed. While this makes the file size significantly larger (often 5MB+), this large size actually bypasses many older AV scanners that refuse to scan large files to save CPU cycles.
3. EDR Evasion
Because Go relies on its own runtime and handles system calls differently than standard C programs, the assembly code it generates looks very foreign to traditional EDR heuristics. Identifying malicious API hooks in a Go binary requires specialized analysis that many security products lack.
The Rise of Rust
Rust is rapidly gaining traction as the ultimate language for stealthy malware and custom loaders.
1. Memory Safety and OPSEC
Rust’s defining feature is its strict compiler, which guarantees memory safety without using a garbage collector. This means Red Teams can write highly complex, low-level kernel exploits or shellcode injectors that are mathematically guaranteed not to cause a segmentation fault. A stable payload is a stealthy payload.
2. Direct Syscalls and FFI
Rust has excellent Foreign Function Interface (FFI) support, making it incredibly easy to interact with the native Windows API (ntdll.dll). Red Teamers use Rust to implement Direct System Calls (Syscalls) to bypass user-mode EDR hooks, mapping shellcode into memory with ruthless efficiency.
3. Obfuscation by Compiler
The LLVM compiler used by Rust applies aggressive optimizations. When reverse engineers open a compiled Rust binary in a disassembler like Ghidra or IDA Pro, the resulting assembly code is a chaotic, optimized labyrinth. It is notoriously difficult for malware analysts to reverse-engineer Rust binaries compared to C/C++, significantly slowing down the Blue Team's incident response time.
The Defensive Perspective
The shift to Go and Rust poses a significant challenge for defenders.
- Signature Evasion: Traditional hash-based signatures are useless, as simply recompiling a Go or Rust payload changes the entire structure of the binary.
- Behavioral Detection is Key: Blue Teams must move away from static analysis. It doesn't matter what language the malware is written in; if it attempts to inject code into
lsass.exeto dump passwords, the EDR must catch that behavior via kernel-level telemetry or API monitoring.
Conclusion
Offensive security is a continuous arms race. As Microsoft and EDR vendors lock down C# and scrutinize C++ binaries, attackers will adapt. By leveraging the cross-platform capabilities of Go and the low-level stealth of Rust, Red Teams can develop highly resilient, evasive tools that simulate the most advanced persistent threats (APTs) in the world today.