Security Monitoring and Enforcement with Cfengine 3

Cfengine is well known as a powerful system configuration management tool, but did you know you also can use it to secure your systems?
Monitoring for Suspicious Filenames

Cfengine has a special cf-agent control variable called suspiciousnames. You can put a list of names into it to warn about during any file search (such as was done during the MD5 hash check). If Cfengine sees these names during recursive (depth) file searches, it will warn about them. If suspiciousnames is not set, cf-agent won't check for them. It's not set by default.

Let me demonstrate how this works by adding the following control block to

body agent control
suspiciousnames => { ".mo", "lrk3", "rootkit" };

A cf-agent control block controls the behavior of cf-agent. This is where you can set things like dry-run mode (don't change anything but report only on what changes would have been made—useful for learning Cfengine), the largest file size Cfengine will edit and so on. So the suspiciousnames variable is set in the agent control block. It's an array of strings.

Let's create a suspiciously named file to see cf-agent get excited:

# date > /etc/rootkit
# cf-agent -IKf
Suspicious file rootkit found in /etc

So, if you're scanning your system directories for an MD5 hash check, you can add the suspicious name check too.

Monitoring Running Processes

I follow the best practice of securing servers by disabling unnecessary services. I often want to make sure my Web servers are not running CUPS—usually, a Web server does not need to print!

The example shown in Listing 2 is based on the Cfengine unit test

The line of interest in Listing 2 is:

processes: "cupsd"  signals => { "term", "kill" };

This means if there is an entry in the process table matching “cupsd”, that process will be sent TERM and then KILL signals:

# cf-agent -IKf
 -> Signalled 'term' (15) to observed process match '28140'
 -> Signalled 'kill' (9) to observed process match '28140'

But, let's not be so brutal. Cfengine can report suspicious process names. You can keep an eye out for password sniffers, crackers, IRC bots and so on with the policy shown in Listing 3.

The key line here is:

vars: "suspicious_process_names" slist => { "sniff",
    "eggdrop", "r00t", "^\./", "john", "crack" };

A variable called “suspicious_process_names” is a list of strings; what we deem as suspicious process names includes, let's say, any processes starting with ./. As you can see, this list can include regular expressions. Cfengine uses Perl-compatible regular expressions.

You can set the contents of this array to reflect what you consider suspicious process names. Then, Cfengine scans the entire process table (that's the processes: .*) and loops over the contents of the “suspicious_process_names” array. Cfengine has implicit looping over arrays, so if you have an array @{suspicious_process_names} and you reference ${suspicious_process_names}, you're actually saying:

for ${suspicious_process_names} in (@{suspicious_process_names}

That's what happens when you say process_select => proc_finder("$(suspicious_process_names)"); You're actually saying, for each element in @(suspicious_process_names), find processes that match that regex.

Anyway, I want this to be a security demonstration rather than a language primer, so let's continue:

# cf-agent -IKf
 !! Matched: root     20044 20002 20044  0.0  0.0  
    4956  19   664    1 22:05 00:00:00 ./eggdrop 

The first numeric field (20044) is the PID. The last field is the process name. (Why is there an IRC bot on my Web server?)


Aleksey Tsalolikhin has been a UNIX/Linux system administrator for 14 years.