Welcome back to Programming Thursday, where today we will leave Python behind and enter the world of compiled languages. Python is great for prototyping; Go is for deployment.
In the last five years, there has been a massive shift in the malware ecosystem. Threat groups and Red Teams alike are abandoning C# and PowerShell for Go (Golang). Why?
- Cross-Compilation: You can compile a Windows binary from your MacBook with one command.
- Binaries are Static: No dependency hell. No “Python not installed.” No “.NET framework version mismatch.”
- Speed: It’s near-C speed with Python-like readability.
1. The Cross-Compilation Superpower#
The killer feature of Go is building for any target OS without installing a VM.
Scenario: You are on a Kali Linux machine, but you need an exploit (exploit.exe) for a Windows server.
# Build for Windows 64-bit
GOOS=windows GOARCH=amd64 go build -o loader.exe main.go
# Build for Linux (e.g., a router or IoT device)
GOOS=linux GOARCH=mips go build -o botnet main.go
2. Stealth: Hiding the Console#
By default, a Go binary on Windows opens a cmd.exe window when run. This is bad OpSec for a background beacon.
The Fix: Use linker flags (-ldflags) to tell the Windows GUI subsystem to run it without a window.
go build -ldflags "-H=windowsgui -w -s" -o stealth.exe main.go
-H=windowsgui: Hides the console window.-w -s: Strips debug symbols (makes the binary smaller and harder to reverse engineer).
3. Interacting with Windows API (Syscalls)#
You don’t need C++ to call VirtualAlloc. Go can do it via the syscall or golang.org/x/sys/windows packages. This is crucial for process injection.
Example: The Message Box (The “Hello World” of WinAPI)
package main
import (
"syscall"
"unsafe"
)
var (
user32 = syscall.NewLazyDLL("user32.dll")
procMessageBox = user32.NewProc("MessageBoxW")
)
func main() {
title, _ := syscall.UTF16PtrFromString("Red Team")
text, _ := syscall.UTF16PtrFromString("Go Native WinAPI Call")
// Call MessageBoxW(0, text, title, 0)
procMessageBox.Call(
0,
uintptr(unsafe.Pointer(text)),
uintptr(unsafe.Pointer(title)),
0,
)
}
4. Building a Simple Port Scanner#
Why use Nmap (which requires installation and flags bells) when you can write a focused scanner in 50 lines?
package main
import (
"fmt"
"net"
"time"
)
func scan(target string, port int, results chan int) {
address := fmt.Sprintf("%s:%d", target, port)
conn, err := net.DialTimeout("tcp", address, 1*time.Second)
if err == nil {
results <- port
conn.Close()
} else {
results <- 0
}
}
func main() {
target := "192.168.1.1"
results := make(chan int)
// Parallel scanning using Goroutines
for i := 1; i <= 100; i++ {
go scan(target, i, results)
}
// Collect results
for i := 1; i <= 100; i++ {
port := <-results
if port != 0 {
fmt.Printf("[+] Open: %d\n", port)
}
}
}
5. Major Tools Written in Go#
You probably use these tools every engagement. They prove Go’s dominance:
- Chisel: A fast TCP tunnel over HTTP. Essential for pivoting.
- Gobuster: The standard for directory/DNS brute forcing.
- Merlin: A C2 framework that uses HTTP/2.
- Ligolo-ng: The modern replacement for VPN pivoting.
Conclusion#
Go allows you to write tools that are easy to maintain but deploy as weaponized, standalone binaries. If you know Python, learning Go takes a weekend. For a Red Teamer, that weekend pays unmatched dividends in operational flexibility.
UncleSp1d3r