wazuh / wazuh

Wazuh - The Open Source Security Platform. Unified XDR and SIEM protection for endpoints and cloud workloads.
https://wazuh.com/
Other
10.41k stars 1.6k forks source link

Rootcheck produce false positives #15168

Open Rebits opened 1 year ago

Rebits commented 1 year ago
Wazuh version Component Install type Install method Platform
4.4.0-1 Rootcheck Manager Packages Any

Description

Rootcheck produces false positives.

Regarding SUSE Linux Enterprise 15 SCA Policy duplicated check ids 7521 and 7522, it was detected possible false positives in Open Suse Enterprise EC2 host. @wazuh/threat-intel.

In this case, some alerts were triggered in a new environment:

** Alert 1665661185.406360: - ossec,rootcheck,pci_dss_10.6.1,gdpr_IV_35.7.d,
2022 Oct 13 11:39:45 ip-172-31-20-225->rootcheck
Rule: 510 (level 7) -> 'Host-based anomaly detection event (rootcheck).'
Rootkit 'ZK' detected by the presence of file '/etc/sysconfig/console/load.zk'.
title: Rootkit 'ZK' detected by the presence of file '/etc/sysconfig/console/load.zk'.

** Alert 1665661188.406727: - ossec,rootcheck,pci_dss_10.6.1,gdpr_IV_35.7.d,
2022 Oct 13 11:39:48 ip-172-31-20-225->rootcheck
Rule: 510 (level 7) -> 'Host-based anomaly detection event (rootcheck).'
File '/dev/.blkid.tab' present on /dev. Possible hidden file.
title: File present on /dev.
file: /dev/.blkid.tab

Those rules are related to ZK rootcheck rules (ruleset/rootcheck/db/rootkit_trojans.txt)

# ZK rootkit (http://honeyblog.org/junkyard/reports/redhat-compromise2.pdf)
/etc/sysconfig/console/load.zk   !/bin/sh! ZK rootkit
/etc/sysconfig/console/load.zk   !usr/bin/run! ZK rootkit

It is required to refactor the rootcheck database to avoid false positives.

jnasselle commented 1 year ago

Update

RCA

It was found that is_file() function is not working as expected, returning true (1) when testing a non-existent file.

Steps to reproduce

This is the case of /etc/sysconfig/console/load.zk, debugger shows what comments says

int is_file(char *file_name)
{
    struct  stat statbuf;
    int     ret = 0;
    FILE    *fp = NULL;
    DIR     *dp = NULL;

    if (!file_name) { // file_name exist, continue
        mterror(ARGV0, "RK: Invalid file name: %s!", file_name);
        return ret;
    }

    dp = opendir(file_name);
    if (dp) {
        closedir(dp);
        ret = 1;
#ifndef WIN32
    } else if (errno == ENOTDIR) {
        ret = 1; // Code enter here, since file_name is not a dir. But why is not setting errno to `ENOENT`
#endif
    }

    /* Trying other calls */
    if ((stat(file_name, &statbuf) < 0) &&
#ifndef WIN32
            (access(file_name, F_OK) < 0) &&
#endif
            ((fp = fopen(file_name, "r")) == NULL)) {
        return ret; //Code return here, since `file_name` cannot be stated, accessed not opened
    }

    if (fp) {
        ret = 1;
        fclose(fp);
    }

    return ret;
}

Conclusion

This could or not be a false-positive, it does not matter, because the function that relies on is not working as expected

thilohille commented 7 months ago

On opensuse 15.5 the false positive still exists. I think the problem occurs if a parent-folder of file_name exists as file.

For example when testing '/etc/sysconfig/console/load.zk' the function is assuming /etc/sysconfig/console is a directory or not existing. At least in opensuse there is a file '/etc/sysconfig/console'.

errno will be ENOTDIR then as can be verified with cat

ls -l /etc/sysconfig/console
-rw-r--r-- 1 root root 1544 Jul  21  2023 /etc/sysconfig/console

cat /etc/sysconfig/console2/load.zk
cat: /etc/sysconfig/console2/load.zk: No such file or directory

You could try to open the containing folder as well and only return only 1 if that folder exists as well.