FritzFrog is a highly sophisticated peer-to-peer (P2P) botnet that has been actively breaching SSH servers worldwide. With its decentralized infrastructure, it distributes control among all its nodes.
In this network with no single point-of-failure, peers constantly communicate with each other to keep the network alive, resilient and up-to-date.
P2P communication is done over an encrypted channel, using AES for symmetric encryption and the Diffie-Hellman protocol for key exchange.
Unlike other P2P botnets, FritzFrog combines a set of properties that makes it unique: it is fileless, as it assembles and executes payloads in-memory.
It is more aggressive in its brute-force attempts, yet stays efficient by distributing targets evenly within the network. Finally, FritzFrog’s P2P protocol is proprietary and is not based on any existing implementation.
The malware, which is written in Golang, is completely volatile and leaves no traces on the disk. It creates a backdoor in the form of an SSH public key, enabling the attackers ongoing access to victim machines. Since the beginning of the campaign, we identified 20 different versions of the malware executable.
Guardicore Labs first noticed this campaign as part of its ongoing Botnet Encyclopedia research. On January 9, new attack incidents appeared where malicious processes named ifconfig and nginx were executed.
Guardicore Labs started monitoring the campaign’s activity, which rose steadily and significantly with time, reaching an overall of 13k attacks on Guardicore Global Sensors Network (GGSN). Since its first appearance, we identified 20 different versions of the Fritzfrog binary.
What was intriguing about this campaign was that, at first sight, there was no apparent command and control (CNC) server being connected to. It was shortly after the beginning of the research when we understood no such CNC existed in the first place.
To intercept the FritzFrog network, Guardicore Labs has developed a client program in Golang, which performs the key-exchange process with the malware and is capable of sending commands and receiving their outputs.
This program, which we named frogger, allowed us to investigate the nature and scope of the network. Using frogger, we were also able to join the network by “injecting” our own nodes and participating in the ongoing P2P traffic.
FritzFrog was found to brute-forces millions of IP addresses, among which are governmental offices, educational institutions, medical centers, banks and numerous telecom companies.
It has successfully breached over 500 SSH servers, including those of known high-education institutions in the U.S. and Europe, and a railway company.
A Fileless P2P Botnet
Although GoLang based botnets have been observed before, such as Gandalf and GoBrut, FritzFrog appears to share some similarities with Rakos, another Golang-based Linux backdoor that was previously found to infiltrate target systems via brute force attempts at SSH logins.
But what makes FritzFrog unique is that it’s fileless, meaning it assembles and executes payloads in-memory, and is more aggressive in carrying out brute-force attacks, while also being efficient by distributing the targets evenly within the botnet.
Once a target machine is identified, the malware performs a series of tasks involving brute-forcing it, infecting the machine with malicious payloads upon a successful breach, and adding the victim to the P2P network.
To slip under the radar, the malware runs as ifconfig and NGINX, and begins listening on port 1234 to receive further commands for execution, including those for syncing the victim with the database of network peers and brute-force targets.
The commands themselves are transmitted to the malware through a series of hoops designed to avoid detection. The attacker node in the botnet first latches onto a specific victim over SSH and then uses the NETCAT utility to establish a connection with a remote server.
What’s more, the payload files are exchanged between nodes in BitTorrent-style, employing a segmented file transfer approach to send blobs of data.
“When a node A wishes to receive a file from its peer, node B, it can query node B which blobs it owns using the command getblobstats,” Harpaz said.
“Then, node A can get a specific blob by its hash, either by the P2P command getbin or over HTTP, with the URL ‘https://node_IP:1234/blob_hash.’ When node A has all the needed blobs, it assembles the file using a special module named Assemble and runs it.”
Aside from encrypting and encoding the command responses, the malware runs a separate process, named “libexec,” to mine Monero coins and leaves a backdoor for future access to the victim by adding a public key to the SSH’s “authorized_keys” file so that logins can be authenticated without having to rely on the password again.
The Fritzfrog attackers implemented an encrypted command channel with over 30 different commands. Command parameters and responses are transferred in designated data structures and serialized (“marshalled”) to JSON format. Prior to sending, the data is encrypted using AES symmetric encryption and encoded in Base64. To agree upon the encryption key, the involved nodes use the Diffie-Hellman key exchange protocol.
|FritzFrog’s P2P Commands|
|Database Operations||Payloads Operations||Administration Operations|
Nodes in the FritzFrog network keep in close contact with each other. They constantly ping each other to verify connectivity, exchange peers and targets and keep each other synced. The nodes participate in a clever vote-casting process, which appears to affect the distribution of brute-force targets across the network. Guardicore Labs observed that targets are evenly distributed, such that no two nodes in the network attempt to “crack” the same target machine.
Delving into the Malware
FritzFrog’s binary is an advanced piece of malware written in Golang. It operates completely in-memory; each node running the malware stores in its memory the whole database of targets and peers. The malware spawns multiple threads to perform various tasks simultaneously, as detailed in the table below.
FritzFrog defines the following states with regards to the management of victim and target machines.
- Target – a machine found in the target queue will next be fed to the Cracker module, which in turn will scan and try to brute-force it;
- Deploy – a machine which was successfully breached is queued for malware infection by the DeployMgmt module;
- Owned – a machine which was successfully infected will be added to the P2P network by the Owned module.
|Cracker||Brute force targets|
|CryptoComm + Parser||Encrypted P2P communication|
|CastVotes||Voting mechanism for target distribution|
|TargetFeed||Ingesting targets from peers|
|DeployMgmt||Worm module, deploying malware on breached (“cracked”) machines|
|Owned||Connecting to victims after malware deployment|
|Assemble||In-memory file assembling from blobs|
|Antivir||Competitors elimination. Kills CPU-demanding processes with the string “xmr”|
Each node that runs the malware has a worker thread which is responsible for receiving commands, parsing them and dispatching them to the appropriate function in the code.
The malware is transient – it does attempt to survive system reboots. However, a backdoor is left to enable future access to the breached victim, whose login credentials are saved by the network peers. The malware adds a public SSH-RSA key to the authorized_keys file. This simple backdoor allows the attackers – who own the secret private key – for passwordless authentication, in case the original password was modified. FritzFrog has used only a single public key which is given in the box below.
The malware file runs various shell commands on the local machine, some of them periodically, to monitor the system state. For example, it runs free -m to check for available RAM, uptime, journalctl -S @0 -u sshd to monitor SSH logins, and other commands which output the CPU usage statistics. These statistics are available for other nodes in the network to consume, and are used to determine, for example, whether to run a cryptominer or not.
The malware runs a separate process – named libexec – to mine the Monero coin. The miner is based on the popular XMRig miner and connects to the public pool web.xmrpool.eu over port 5555.
An Evil Torrent-Like Network
Fritzfrog relies on the ability to share files over the network, both to infect new machines and run malicious payloads, such as the Monero cryptominer.
To share and exchange files between nodes, Fritzfrog uses a stealthy, fileless approach. Files are split into blobs – bulks of binary data – which are kept in memory. The malware keeps track of the available blobs by storing them in a map together with each blob’s hash value.
When a node A wishes to receive a file from its peer, node B, it can query node B which blobs it owns using the command getblobstats. Then, node A can get a specific blob by its hash, either by the P2P command getbin or over HTTP, with the URL http://:1234/. When node A has all the needed blobs – it assembles the file using a special module named Assemble and runs it.
Tracking the operators of a P2P botnet is a complicated task; due to its distributed nature, commands can be sent to and from any node in the network. Still, we’ve attempted to compare it to previous P2P botnets seen in the threat landscape.
Even when compared with past P2P botnets, FritzFrog appears unique; it does not use IRC like IRCflu, it operates in-memory unlike DDG, and runs on Unix-based machines – as opposed to the InterPlanetary Storm botnet.
If any, it bears some resemblance – especially with regards to function naming and version numbers – to Rakos, a P2P botnet written in Golang and analyzed by ESET back in 2016.
Check whether your machines are part of the botnet
Detecting a cryptominer on a machine running an SSH server is not proof that it’s been infected, as the malware checks whether the machine can expend power to mine and decides against it if it can’t.
Admins can use a detection script that searches for the aforementioned fileless processes, evidence of malware listening on port 1234 and of TCP traffic over port 5555 (network traffic to the Monero pool).
While a reboot of the affected machine/device will remove the malware from memory and terminate the malware process, since a victim is immediately ‘logged’ to the P2P network along with its login credentials, it will be re-infected in no time.
Instead, admins should:
- Terminate the malicious processes
- Change the SSH password to a strong one and use public key authentication
- Remove FritzFrog’s public key from the authorized_keys file to “close” the backdoor
- Consider changing routers’ and IoT devices’ SSH port or completely disabling SSH access to them if the service is not needed
Guardicore Labs provides a FritzFrog detection script to run on SSH servers. It looks for the following FritzFrog indicators:
- Running processes nginx, ifconfig or libexec whose executable file no longer exists on the file system (as seen below)
- Listening port 1234
In addition, TCP traffic over port 5555 can indicate network traffic to the Monero pool.
[email protected]:~$ ./detect_fritzfrog.sh FritzFrog Detection Script by Guardicore Labs ============================================= [*] Fileless process nginx is running on the server. [*] Listening on port 1234 [*] There is evidence of FritzFrog's malicious activity on this machine.
FritzFrog takes advantage of the fact that many network security solutions enforce traffic only by the port and protocol. To overcome this stealth technique, process-based segmentation rules can easily prevent such threats.
Weak passwords are the immediate enabler of FritzFrog’s attacks. We recommend choosing strong passwords and using public key authentication, which is much safer.
In addition, it is crucial to remove FritzFrog’s public key from the authorized_keys file, preventing the attackers from accessing the machine.
Routers and IoT devices often expose SSH and are thus vulnerable to FritzFrog; consider changing their SSH port or completely disabling SSH access to them if the service is not in use.