Sysrv Infection (Linux Edition)

Table of Contents


On a recent incident response case, a customer contacted us regarding their EDR detecting a crypto miner on a Linux endpoint. The identified malicious file, named 41hs1z, is accessible on VirusTotal. The folders and paths associated with each execution of the crypto miner may differ; however, here are some paths we encountered:

  • /backup/files/excel/41hs1z
  • /backup/files/xml/dotnet115/BeID/41hs1z
  • /backup/files/xml/dotnet115/layouts/defaults/41hs1z

Upon analysis, we discovered that the malware is a component of the Sysrv botnet. In this short blog post, we will examine the ELF binary to uncover its capabilities and identify IOCs associated with the sample.

For further insights into Sysrv, we recommend referring to the following three informative blog posts:


At the time of writing this blog post, the loader script remains available online at[.]sh (VirusTotal). This shell script was executed on the target host, presumably after exploiting a vulnerability in the internet-facing web application. While the server was no longer accessible for a thorough investigation, we discovered traces of the script’s execution. Part of the file

Figure 1: Part of the file

Many other blogs, including UltimaCybr’s, have thoroughly examined the loader script (which is why we won’t duplicate the analysis here). One notable difference in our case is that the loader does not possess the capabilities to gather and use SSH keys for subsequent propagation, as highlighted in a report by TheDFIRReport.

A recovered version of this script shows that it uses a clever technique for self-propagation on Linux. In addition to disabling UFW and killing several running services, the script then turns to enumerating all the private keys stored on the hosts, parsing all the hosts in the known_hosts files, as well as username associated with any keys found.

GO-Binary Reversing

Upon opening the binary with Ghidra, we are presented with… not much information. The functions pane appears largely empty. Functions within Ghidra

Figure 2: Functions within Ghidra

Additionally, the included strings from the binary do not make much sense. Defined strings within Ghidra

Figure 3: Defined strings within Ghidra

Dorka Palotay wrote an excellent article titled Reverse Engineering Go Binaries with Ghidra, shedding light on why extracting strings from our GO binary poses challenges. After reading about the problems in the blog of Dorka, I stumbled upon the GhidraScripts maintained by Max Kersten. After loading the scripts into the Script Manager from Ghidra and running them (the GhidraScripts GitHub repository contains a README that will guide through every step), the magic behind those scripts found more function names and readable strings (Figure 4). Script Manager within Ghidra

Figure 4: Script Manager within Ghidra

Returning to the functions pane, we now have function names that are more or less meaningful: More functions within Ghidra<

Figure 5: More functions within Ghidra

Performing the same search for “cron,” as previously demonstrated (refer to Figure 3), yields more meaningful results: Readable strings within Ghidra

Figure 6: Readable strings within Ghidra


We utilize strace for the dynamic analysis of the malware. See my post [s|l]trace - Linux Malware Analysis as a strace primer. Upon executing the binary in a controlled environment (with strace and logging activated), the binary operates under the name kthreaddk, a frequently observed identifier for this strain of malware, as numerous Google search results indicate infections attributed to Sysrv.

2530  execve("./9d9150e2def883bdaa588b47cf5300934ef952bea3acd5ad0e86e1deaa7d89c5", ["./9d9150e2def883bdaa588b47cf5300934ef952bea3acd5ad0e86e1deaa7d89c5"], 0x7fff61b40138 /* 17 vars */) = 0
2537  execve("kthreaddk", ["kthreaddk"], 0xc420138090 /* 17 vars */ <unfinished ...>


One of the initial steps following execution involves establishing persistence through a cronjob, utilizing randomized paths, as we will explore subsequently. Take note of the string “/usr/bin/crontab -,” which matches the string we uncovered within Ghidra after utilizing the Ghidra Scripts to extract readable strings from the binary (refer to Figure 6).

2550  execve("/bin/sh", ["/bin/sh", "-c", "echo '* * * * * /dev/disk/by-partuuid/3hxr47' | /usr/bin/crontab -"], 0xc420138120 /* 17 vars */ <unfinished ...>


At intervals of one minute, the sample establishes a connection to localhost through a predetermined port (in our instance, 51933). The malware refrains from re-infecting the system if the port is open.

src_port = 44388
dst_ip =
dst_port = 51933
protocol = TCP

Process listing

The binary is copied around to different paths. Here’s an example of running ps on the infected machine, revealing the malicious binary executed under the following path: /etc/apparmor.d/abstractions/ubuntu-browsers.d/3hxr47.

# ps aux 

root 3711  0.0  0.0   2616   496 ? Ss 15:12 0:00 /bin/sh -c /etc/apparmor.d/abstractions/ubuntu-browsers.d/3hxr47
root 3712  2.4  2.8 115804 100868 ? Sl 15:12 1:06 /etc/apparmor.d/abstractions/ubuntu-browsers.d/3hxr47

Cron Jobs

The various and changing paths of the malware are recorded within the cron log files, as illustrated in the following excerpt:

Feb 18 15:11:01 miner cron[752]: (root) RELOAD (crontabs/root)
Feb 18 15:11:01 miner CRON[3692]: (root) CMD (/etc/apparmor.d/abstractions/ubuntu-browsers.d/3hxr47)
Feb 18 15:12:01 miner CRON[3711]: (root) CMD (/etc/apparmor.d/abstractions/ubuntu-browsers.d/3hxr47)
Feb 18 15:12:03 miner crontab[3725]: (root) REPLACE (root)
Feb 18 15:13:01 miner CRON[3819]: (root) CMD (/dev/block/mujqjo)
Feb 18 15:13:04 miner crontab[3830]: (root) REPLACE (root)
Feb 18 15:14:01 miner cron[752]: (root) RELOAD (crontabs/root)


Steven Folek (@Pir00t) used the watch command in his blog post (see the link in the introduction section) to fetch a copy of the config.json file. We can employ strace once more to observe the contents of the JSON file as it’s being written to disk. However, we need to augment the maximum string length to capture using the parameter -s when initiating strace. Otherwise, strace only captures the initial 32 characters of the content.

While running strace command on DVOCmd command, the string size is by default 32 characters. You will see “…” after 32 characters, preventing from getting useful information. To get the maximum length of a string to display, you need to use -s strsize option in the strace command. By default, the limit is to display 32 characters only.

2532  openat(AT_FDCWD, "/etc/byobu/3hxr47/config.json", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0777) = 7
2532  write(7, "{\n    \"api\": {\n    [..]]{ \"url\": \"\" } ],\n    \"retries\": 5,\n    
\"retry-pause\": 5,\n    \"syslog\": false,\n    \"user-agent\": null,\n    \"verbose\": 0,\n   
 \"watch\": false,\n    \"pause-on-battery\": false\n}", 1047) = 1047
2532  close(7)    

Within the configuration file, we encounter the same IP address from which the loader script was retrieved (194.38.23[.]2), albeit with a different port (8080).


As observed by other researchers, the Sysrv malware family integrates several exploits. These exploits are employed against random targets across the internet, aiming to exploit vulnerable systems and propagate to further hosts. Presented below is a sample exploit aimed at a WordPress site within our analyzed sample. Built-In WordPress exploit

Figure 7: Built-In WordPress exploit

We identify the identical URL (highlighted in green in Figure 7) within publicly available exploit code on Exploit-DB, aligning the exploit code found on Exploit-DB with the exploit code contained within the malware sample. Same URL as in the Built-In exploit above

Figure 8: Same URL as in the Built-In exploit above

In addition to numerous other exploits not discussed in this blog post, we also uncover a list of hardcoded username/password combinations utilized for brute-forcing login pages. List of username/password combination

Figure 9: List of username/password combination

And the moral of the story is …

  • Patch Management: It is crucial to promptly patch your externally facing applications and devices to mitigate potential security vulnerabilities. Regularly updating software and firmware helps safeguard against emerging threats and enhances overall system security.

  • DNS Logging (Crypto Mining): Whenever I analyze a crypto miner infection, I must think about Florian’s tweet. List of username / password combination

  • EDR all assets: Whenever possible, deploy an Endpoint Detection and Response (EDR) agent or leverage agentless solutions to continuously monitor your devices and hosts for signs of compromise.


In an upcoming blog post, we will explore the intersection of system monitoring and security in Linux environments, focusing on the tools Sysmon for Linux and Kunai. Sysmon for Linux, an adaptation of Microsoft’s renowned Sysinternals tool, brings powerful system monitoring capabilities to Linux systems. Meanwhile, Kunai, offers a comprehensive solution for analyzing, correlating, and responding to security events in real-time. By combining the capabilities of Sysmon for Linux and Kunai,we can proactively identify suspicious activities.