CVE-2024-20328: Command Injection Vulnerability in ClamAV's VirusEvent Feature
Executive Summary
CVE-2024-20328 is a command injection vulnerability discovered in the VirusEvent
feature of ClamAV, a widely used open-source antivirus engine. This vulnerability allows a local attacker to execute arbitrary commands on the system with the privileges of the user running the ClamAV daemon (clamd
). The root cause lies in the improper sanitization of file names when constructing command strings for execution. Attackers can exploit this issue when VirusEvent
is enabled in configurations, effectively injecting malicious commands into the system.
The vulnerability has been addressed in software updates for affected ClamAV versions, and users are encouraged to patch their systems immediately. No workarounds are currently available; disabling vulnerable configurations or upgrading software is necessary to mitigate this vulnerability.
Technical Details
CVE-2024-20328 impacts the following versions of ClamAV:
- All versions of ClamAV 0.104 (including patch versions)
- ClamAV 0.105 (all patch versions)
- ClamAV 1.0.0 through 1.0.4 (LTS)
- ClamAV 1.1 (all patch versions)
- ClamAV 1.2.0 and 1.2.1
The VirusEvent
feature, configured in clamd.conf
, enables users to execute custom commands when a virus is detected. These commands use placeholders like %v
(virus name) and %f
(file name), which are dynamically replaced during execution. However, the improper handling of %f
leads to command injection.
For example, VirusEvent
might be configured as:
VirusEvent "echo VIRUS DETECTED: %v in %f >> /dev/stdout"
Here, %f
is replaced with the file name of the infected file. If the file name is crafted maliciously (e.g., containing shell commands), it may execute arbitrary code.
Code Vulnerability
The vulnerability resides in the virusaction
function defined in clamd/clamd_others.c
. Below is the relevant snippet of the vulnerable code:
void virusaction(const char *filename, const char *virname, const struct optstruct *opts) {
...
buffer_cmd = (char *)calloc(len + v * strlen(virname) + f * strlen(filename) + 1, sizeof(char));
if (!buffer_cmd) {
...
return;
}
for (i = 0, j = 0; i < len; i++) {
if (i + 1 < len && opt->strarg[i] == '%' && opt->strarg[i + 1] == 'f') {
strcat(buffer_cmd, filename);
j += strlen(filename);
i++;
} else {
buffer_cmd[j++] = opt->strarg[i];
}
}
...
_exit(execle("/bin/sh", "sh", "-c", buffer_cmd, NULL, env));
}
The issue lies in the unsafe handling of filename
when constructing buffer_cmd
. The content of filename
—provided by external inputs—is directly appended to the command string without sanitization. If an attacker crafts a file name containing shell commands, they can execute those commands at the time of processing.
Root Cause Analysis
The root cause is a failure to validate and sanitize inputs in the virusaction
function. The %f
placeholder is replaced by the file name, which attackers can manipulate to include shell characters or commands. This vulnerability demonstrates an improper reliance on direct user-provided input to construct complex command strings.
To illustrate, consider the following malicious file name:
injectedfile;whoami;
When processed, the constructed command string becomes:
echo VIRUS DETECTED: [virus_name] in injectedfile;whoami; >> /dev/stdout
This leads to unintentional execution of the whoami
command, and the output of the command injection would reveal sensitive details like the username associated with the ClamAV service.
The key vulnerable line enabling this behavior is:
_exit(execle("/bin/sh", "sh", "-c", buffer_cmd, NULL, env));
Here, the buffer_cmd
is executed as a shell command without adequate scrutiny of its contents.
Patch Analysis
The ClamAV team addressed this issue by disabling the %f
placeholder entirely. Instead, users must now rely on environment variables for file names. Below is an annotated analysis of the patch provided in commit 9ca550b0a5567ec697910635526196004b0a53dd
:
Key Changes
File: clamd/clamd_others.c
+#define FILENAME_DISABLED_MESSAGE "The filename format character has been disabled due to security concerns, use the 'CLAM_VIRUSEVENT_FILENAME' environment variable instead."
...
-buffer_cmd = (char *)calloc(len + v * strlen(virname) + f * strlen(filename) + 1, sizeof(char));
+buffer_cmd = (char *)calloc(len + v * strlen(virname) + f * strlen(FILENAME_DISABLED_MESSAGE) + 1, sizeof(char));
...
- strcat(buffer_cmd, filename);
- j += strlen(filename);
+ strcat(buffer_cmd, FILENAME_DISABLED_MESSAGE);
+ j += strlen(FILENAME_DISABLED_MESSAGE);
- The
%f
placeholder is replaced with a static warning string (FILENAME_DISABLED_MESSAGE
), indicating that it has been disabled due to security concerns. - The usage of
filename
instrcat()
is removed, eliminating any direct inclusion of user-controlled values in the command string.
File: common/optparser.c
- {"VirusEvent", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "Execute a command when a virus is found. In the command string %v will be replaced with the virus name and %f will be replaced with the file name. Additionally, two environment variables will be defined: $CLAM_VIRUSEVENT_FILENAME and $CLAM_VIRUSEVENT_VIRUSNAME.", "/usr/bin/mailx -s \"ClamAV VIRUS ALERT: %v\" alert < /dev/null"},
+ {"VirusEvent", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "Execute a command when virus is found. Use the following environment variables to identify the file and virus names: - $CLAM_VIRUSEVENT_FILENAME - $CLAM_VIRUSEVENT_VIRUSNAME. ... (continues with details)", "/usr/bin/mailx -s \"ClamAV VIRUS ALERT: %v\" alert < /dev/null"},
- Documentation is updated to reflect the changes.
%f
is no longer valid; users must now use$CLAM_VIRUSEVENT_FILENAME
instead.
Exploitation Techniques
Proof of Concept (PoC)
Configuration:
VirusEvent "echo VIRUS DETECTED: %v in %f >> /dev/stdout"
Malicious File Name:
payload;id;
Exploit:
When an infected file with the above name is scanned, the following command gets executed:
echo VIRUS DETECTED: Multios.Coinminer-6781728 in payload;id; >> /dev/stdout
Output:
VIRUS DETECTED: Multios.Coinminer-6781728 in payload
uid=0(root) gid=0(root) groups=0(root)
Mitigation Strategies
-
Immediate Patch Application:
- Upgrade to ClamAV versions
1.2.2
,1.0.5
, or1.3.0 and above
.
- Upgrade to ClamAV versions
-
Emergency Mitigation:
- Disable the
VirusEvent
feature by commenting it out in theclamd.conf
configuration file:# VirusEvent ...
- Disable the
-
Security Best Practices:
- Never execute commands that directly parse unsanitized inputs.
- When relying on environment variables, validate their contents before using them in scripts or commands.
Timeline of Discovery and Disclosure
Date (2024) | Event |
---|---|
January 2 | Vulnerability discovered and reported to ClamAV team by Amit Schendel |
February 7 | Patch released by ClamAV team |
February - March | Public disclosure and widespread adoption of the patch |