Re-implement (the currently incorrect & unreferenced / unused) audit_rules_privileged_commands
RHEL-6 check.

The idea behind the check is roughly as follows -- the check works on comparing of two sets: * set A originally contains list of all privileged (setuid or setgid bit set) files found on the system (intentionally speaking about files, not executables above. Since former setuid / setgid can have the executable bit temporarily removed due some reason, we check - it's enough the file to have one of setuid / setgid set [IOW not checking if the file is executable])

* for each item from set A we prefix it with: --a always, exit ... -F path= prefix, and suffix it with -F ... -k privileged suffix. In other words for each setuid / setgid file found on the system we generate the full / expanded form of audit rule, we expect to be found.

* second set B contains list of instances, following / matching the expected audit rule pattern,
  we have retrieved by looking into /etc/audit/audit.rules file

* for each instance found (item from set B) we compare it for match with each item
  (pregenerated full audit rule form) from set A

* besides the above, we need to ensure the dimensions / cardinality of both sets matches (e.g. what could happen being /etc/audit/audit.rules would contain all expected audit rules for setuid files, but none rule for setgid files. Checking just that each audit.rules rule is present in pregenerated list would succeed in this case too, even when it should fail. Therefore we add second, variable_test which compares if the cardinality of set A matches the cardinality of set B. If so, the test succeeds [the count of found audit.rules matches and has expected form than count of various setuid / setgid files, present on the system],
  otherwise failure is returned).


Regardless of the OVAL check being such complex already currently, there are three limitations
I am aware of wrt to it:
* it will return success only in case the audit.rules have exactly the form (meaning order of various arguments) as expected / defined in the comment. Will have a look at possible permutations of -F ... arguments in the future yet (so it would pass also in case the rules
  are present there, but have one of the permutated forms),

* it doesn't check if there isn't "Delete all rules" statement present somewhere in between / behind the audit rules definition (resulting not all of the rules to be actually taking into account by auditd). This is again space for future enhancement (will have a look),

* for now the check has been tested & implemented just for RHEL-6. It's enhancement to cover RHEL-7 too will require more time & more testing. Again to come in subsequent version.


Testing status:
-------------------
The proposed check has been tested on RHEL-6 considering the following sub-cases that
can happen & returns expected / appropriate result in each of them:

1) blank audit.rules file on the system -> returns FAIL V 2) audit.rules present, but no suid, no sgid rules defined -> returns FAIL V 3) audit.rules present, just suid audit rules defined -> returns FAIL V 4) audit.rules present, just sgid audit rules defined -> returns FAIL V 5) audit.rules present, both suid, sgid rules defined -> returns PASS v 6) audit.rules present, both suid / sgid, heading / trailing whitespace -> returns PASS v

auditd doesn't allow comments in its config file (fails to restart if inline comment present) => this
case isn't necessary to consider / cover.


Please review.

Thank you && Regards, Jan.
---
Jan iankko Lieskovsky / Red Hat Security Technologies Team

P.S.: Should you need to share testing scripts / scenario let me know.

>From 15f327359d03ee935c6fb7010b1f1c00c9571533 Mon Sep 17 00:00:00 2001
From: Jan Lieskovsky <[email protected]>
Date: Thu, 3 Jul 2014 11:27:15 +0200
Subject: [PATCH 2/2] [RHEL/6] (Re-)Implement audit_rules_privileged_commands
 OVAL check & start using it

Signed-off-by: Jan Lieskovsky <[email protected]>
---
 .../checks/audit_rules_privileged_commands.xml     | 188 ++++++++++++++++++---
 RHEL/6/input/system/auditing.xml                   |  16 +-
 2 files changed, 177 insertions(+), 27 deletions(-)

diff --git a/RHEL/6/input/checks/audit_rules_privileged_commands.xml b/RHEL/6/input/checks/audit_rules_privileged_commands.xml
index 7ca2e9e..e9349ea 100644
--- a/RHEL/6/input/checks/audit_rules_privileged_commands.xml
+++ b/RHEL/6/input/checks/audit_rules_privileged_commands.xml
@@ -1,31 +1,181 @@
 <def-group>
-  <definition class="compliance"
-  id="audit_rules_privileged_commands" version="1">
+  <definition class="compliance" id="audit_rules_privileged_commands"
+  version="1">
     <metadata>
-      <title>Ensure auditd Collects Information on the Use of
-      Privileged Commands</title>
+      <title>
+        Ensure auditd Collects Information on the Use of Privileged Commands
+      </title>
       <affected family="unix">
         <platform>Red Hat Enterprise Linux 6</platform>
       </affected>
-      <description>Audit rules about the Information on the Use of
-      Privileged Commands are enabled</description>
+      <description>Audit rules about the Information on the Use of Privileged
+      Commands are enabled</description>
+      <reference source="JL" ref_id="RHEL6_20140703" ref_url="test_attestation"/>
     </metadata>
     <criteria>
-      <criterion comment="/etc/audit/audit.rules contains -a always,exit -F path=/bin/ping -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged"
-      test_ref="test_20165" />
+
+      <criterion comment="/etc/audit/audit.rules contains -a always,exit
+      -F path=path_to_binary -F perm=x -F auid&gt;=500 -F auid!=4294967295
+      -k privileged for each setuid or setgid executable on the system"
+      test_ref="test_audit_rules_privileged_commands" />
+
+      <criterion comment="check if count of privileged commands on the system
+      matches the count of defined audit.rules in the expected form"
+      test_ref="test_sets_dimension_match" />
+
     </criteria>
   </definition>
-  <ind:textfilecontent54_test check="all"
-  check_existence="at_least_one_exists"
-  comment="/etc/audit/audit.rules contains -a always,exit -F path=/bin/ping -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged"
-  id="test_20165" version="1">
-    <ind:object object_ref="obj_20165" />
-  </ind:textfilecontent54_test>
-  <ind:textfilecontent54_object id="obj_20165"
+
+
+  <!-- *** Test #1: Check that all setuid / setgid files on the system have proper audit rule definition in /etc/audit/audit.rules *** -->
+
+  <!-- Get the list of setuid / setgid files on the system by traversing the
+       filesystem excluding /dev, /proc, and /sys directories for better
+       performance -->
+  <unix:file_object id="object_system_privileged_commands"
+  comment="system files with setuid or setgid permission set"
+  version="1">
+    <unix:behaviors recurse="directories" recurse_direction="down"
+    recurse_file_system="local" max_depth="-1" />
+    <unix:path operation="equals">/</unix:path>
+    <unix:filename operation="pattern match">^.*$</unix:filename>
+    <filter action="include">state_setuid_or_setgid_set</filter>
+    <filter action="exclude">state_irrelevant_system_dirs</filter>
+  </unix:file_object>
+
+  <unix:file_state id="state_setuid_or_setgid_set" version="1" operator="OR">
+    <unix:suid datatype="boolean">true</unix:suid>
+    <unix:sgid datatype="boolean">true</unix:sgid>
+  </unix:file_state>
+
+  <unix:file_state id="state_irrelevant_system_dirs" version="1">
+    <unix:filepath operation="pattern match">^/(dev|proc|sys)/.*$</unix:filepath>
+  </unix:file_state>
+
+  <!-- Based on the above list create a variable holding full / expanded
+       form of particular expected audit.rules rule for each setuid / setgid
+       file found on the system -->
+  <local_variable id="variable_audit_rules_privileged_commands_full_form"
+  comment="full for of audit rules for privileged commands"
+  datatype="string" version="1">
+    <concat>
+      <literal_component>-a always,exit -F path=</literal_component>
+      <object_component object_ref="object_system_privileged_commands" item_field="filepath" />
+      <literal_component> -F perm=x -F auid>=500 -F auid!=4294967295 -k privileged</literal_component>
+    </concat>
+  </local_variable>
+
+  <!-- The actual implementation of the first test -->
+  <ind:textfilecontent54_test id="test_audit_rules_privileged_commands"
+  check="all" check_existence="all_exist"
+  comment="/etc/audit/audit.rules contains -a always,exit
+  -F path=path_to_binary -F perm=x -F auid&gt;=500 -F auid!=4294967295
+  -k privileged for each setuid or setgid binary on the system"
   version="1">
-    <ind:path>/etc/audit</ind:path>
-    <ind:filename>audit.rules</ind:filename>
-    <ind:pattern operation="pattern match">^\-a\salways,exit\s-F\spath=/bin/ping\s-F perm=x\s\-F\sauid&gt;=500\s\-F\sauid!=4294967295\s\-k\sprivileged</ind:pattern>
-    <ind:instance datatype="int">1</ind:instance>
+    <ind:object object_ref="object_audit_rules_privileged_commands" />
+    <ind:state state_ref="state_audit_rules_privileged_commands" />
+  </ind:textfilecontent54_test>
+
+  <!-- Search /etc/audit/audit.rules file for lines matching:
+
+       -a always, exit ... -k privileged
+
+       pattern -->
+  <ind:textfilecontent54_object id="object_audit_rules_privileged_commands" version="1">
+    <ind:filepath>/etc/audit/audit.rules</ind:filepath>
+    <!-- Select only those rows containing the expected rule form, but different paths,
+         IOW allow the /etc/audit/audit.rules to contain also other definitions -->
+    <ind:pattern operation="pattern match">^[\s]*(-a always,exit -F path=[^\n]+ -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged)[\s]*$</ind:pattern>
+    <ind:instance operation="greater than or equal" datatype="int">1</ind:instance>
+    <!-- But exclude from the set of found instances those where the executable
+         listed after the -F path= argument isn't from the list of setuid / setgid
+         ones - we require all setuid / setgid binaries to have such rule. But if
+         there's custom rule for non setuid / setgid binary, allow the test to pass
+         also in this case -->
+    <filter action="exclude">state_proper_always_exit_rule_but_for_unprivileged_command</filter>
   </ind:textfilecontent54_object>
+
+  <!-- List those instances found, having similar form of audit rule, but being a non setuid /
+       setgid binary. If such rule is found, compare it (in one step) for non-equality with
+       all the predefined rules -->
+  <ind:textfilecontent54_state id="state_proper_always_exit_rule_but_for_unprivileged_command"
+  version="1">
+    <ind:subexpression operation="not equal" datatype="string"
+    var_ref="variable_audit_rules_privileged_commands_full_form"
+    var_check="all" />
+  </ind:textfilecontent54_state>
+
+  <!-- Compare the (restricted) list of instances found from /etc/audit/audit.rules file
+       (following the expected audit rule pattern) with the pre-generated list of
+       full forms of rules for each setgid / setuid binary found on the system
+       (on one-by-one basis - it's enough if such rule is found at least once
+       in the pregenerated list) -->
+  <ind:textfilecontent54_state version="1"
+  id="state_audit_rules_privileged_commands">
+    <ind:subexpression operation="pattern match" datatype="string"
+    var_ref="variable_audit_rules_privileged_commands_full_form"
+    var_check="at least one"/>
+  </ind:textfilecontent54_state>
+
+  <!-- *** EndOfTest #1: Check that all setuid / setgid files on the system have proper audit rule definition in /etc/audit/audit.rules *** -->
+
+
+
+  <!-- *** Test #2: Check that count of setuid / setgid binaries rules found in /etc/audit/audit.rules actually matches the count
+                    of pre-generated full form rules we require to be present on this particular system *** -->
+
+  <!-- Create variable holding cardinality / dimension of the set containing
+       list of setuid / setgid binaries we have found on this system -->
+  <local_variable id="variable_dimension_of_object_system_privileged_commands"
+  comment="cardinality of system privileged commands set"
+  datatype="int" version="1">
+    <count>
+      <object_component item_field="filepath"
+      object_ref="object_system_privileged_commands" />
+    </count>
+  </local_variable>
+
+  <!-- Create variable holding cardinality / dimension of the set containing
+       list of audit rules for setuid / setgid binaries we have found in
+       /etc/audit/audit.rules file on this system -->
+  <local_variable id="variable_dimension_of_object_audit_rules_privileged_commands"
+  comment="cardinality of audit.rules privileged commands having expected rule definition set"
+  datatype="int" version="1">
+    <count>
+      <object_component item_field="subexpression"
+      object_ref="object_audit_rules_privileged_commands" />
+    </count>
+  </local_variable>
+
+  <!-- Perform the actual second test -->
+  <ind:variable_test id="test_sets_dimension_match"
+  check="all" check_existence="all_exist"
+  comment="check if count of found privileged commands on the system is equal
+  to count of audit.rules privileged commands definitions" version="1">
+    <ind:object object_ref="object_dimension_of_object_system_privileged_commands" />
+    <ind:state state_ref="state_set_dimension_match" />
+  </ind:variable_test>
+
+  <!-- Create variable object from the first variable (count of setuid / setgid
+       binaries found on the system) -->
+  <ind:variable_object id="object_dimension_of_object_system_privileged_commands"
+  version="1">
+    <ind:var_ref>variable_dimension_of_object_system_privileged_commands</ind:var_ref>
+  </ind:variable_object>
+
+  <!-- And compare it with the value of the second variable (count of audit rules
+       involving setuid / setgid binaries found in audit.rules file.
+
+       If the count matches, we can be sure audit.rules file contains definition
+       for each of setuid / setgid binary found on the system. If not, something
+       is wrong and the test should return failure -->
+  <ind:variable_state id="state_set_dimension_match" version="1">
+    <ind:value operation="equals" datatype="int"
+    var_ref="variable_dimension_of_object_audit_rules_privileged_commands"
+    var_check="at least one" />
+  </ind:variable_state>
+
+  <!-- *** EndOfTest #2: Check that count of setuid / setgid binaries rules found in /etc/audit/audit.rules actually matches the count$
+                         of pre-generated full form rules we require to be present on this particular system *** -->
+
 </def-group>
diff --git a/RHEL/6/input/system/auditing.xml b/RHEL/6/input/system/auditing.xml
index 9923680..70ad93a 100644
--- a/RHEL/6/input/system/auditing.xml
+++ b/RHEL/6/input/system/auditing.xml
@@ -1152,20 +1152,20 @@ these events could serve as evidence of potential system compromise.</rationale>
 <Rule id="audit_privileged_commands">
 <title>Ensure <tt>auditd</tt> Collects Information on the Use of Privileged Commands</title>
 <description>At a minimum the audit system should collect the
-execution of privileged commands for all users and root. 
-To find the relevant setuid programs:
+execution of privileged commands for all users and root.
+To find the relevant setuid / setgid programs:
 <pre># find / -xdev -type f -perm -4000 -o -perm -2000 2>/dev/null</pre>
-Then, for each setuid program on the system, add a line of the following form to 
-<tt>/etc/audit/audit.rules</tt>, where <i>SETUID_PROG_PATH</i> is the full path to each setuid program
+Then, for each setuid / setgid program on the system, add a line of the following form to
+<tt>/etc/audit/audit.rules</tt>, where <i>SETUID_PROG_PATH</i> is the full path to each setuid / setgid program
 in the list:
 <pre>-a always,exit -F path=<i>SETUID_PROG_PATH</i> -F perm=x -F auid&gt;=500 -F auid!=4294967295 -k privileged</pre>
 </description>
 <ocil clause="it is not the case">
-To verify that auditing of privileged command use is configured, run the following command to find relevant setuid programs:
+To verify that auditing of privileged command use is configured, run the following command to find relevant setuid / setgid programs:
 <pre># find / -xdev -type f -perm -4000 -o -perm -2000 2>/dev/null</pre>
 Run the following command to verify entries in the audit rules for all programs found with the previous command:
 <pre># grep path /etc/audit/audit.rules</pre>
-It should be the case that all relevant setuid programs have a line in the audit rules.
+It should be the case that all relevant setuid / setgid programs have a line in the audit rules.
 </ocil>
 <rationale>Privileged programs are subject to escalation-of-privilege attacks,
 which attempt to subvert their normal role of providing some necessary but
@@ -1173,9 +1173,9 @@ limited capability. As such, motivation exists to monitor these programs for
 unusual activity.
 </rationale>
 <ident cce="26457-2" />
-<!-- <oval id="audit_rules_privileged_commands" /> -->
+<oval id="audit_rules_privileged_commands" />
 <ref nist="AC-17(7),AU-1(b),AU-2(a),AU-2(c),AU-2(d),AU-2(4),IR-5" disa="40" />
-<tested by="DS" on="20121024"/>
+<tested by="JL" on="20140703"/>
 </Rule>
 
 <Rule id="audit_media_exports">
-- 
1.8.3.1

-- 
SCAP Security Guide mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/scap-security-guide
https://github.com/OpenSCAP/scap-security-guide/

Reply via email to