In my previous post I made a skeleton XCCDF document. By now, we can create a well documented "baseline" (best practice) for our subject (say PostgreSQL). But for now I only talked about <description> whereas XCCDF allows many other tags as well.

You can add metadata information for a particular Group. It is recommended to use the dublin core notation:

``` {lang="xml"}

CISecurity Benchmark Center for Internet Security MySQL Benchmark

If you use metadata information however, it should **not** be used
*instead* of XCCDF elements.

Another set of elements that can be used are `warning` elements:

``` {lang="xml"}

Enabling this might require additional licenses to be purchased.

The <rationale> element can be used to explain in more detail why a rule is important.

``` {lang="xml"}

Enabling audit logging allows for tracing back changes or doing forensic analysis.

Some elements we saw before also apply on the specific `<Group>`
elements, such as `<status>` or `<version>`. The combination of these
elements should allow for a pretty good explanation of the secure setup
we want to achieve.

But documentation is one thing - how about checking something
automatically? Enter the XCCDF `Rule` element.

Rules are particular tests, checks if you wish, that you want to have
executed. To start off, let's look at a `Rule` element that, as
automated approach, calls a script. To accomplish this, we use the **SCE
(Script Check Engine)** method. This is *not* part of the SCAP standard
by itself (SCAP uses OVAL for automated checks - I'll discuss OVAL
later) but XCCDF allows for other check systems to be used. And SCE is
supported by [openscap](

``` {lang="xml"}

  Test if the hardened toolchain is used

    Use a hardened Gentoo profile and select the default compiler (not vanilla
    nor any of the hardenedno* ones).

First of all, we have the Rule element itself, with the specially crafted id attribute as seen before. There are three attributes used in the example:

  1. selected="false" tells the XCCDF interpreter that the Rule should not be automatically selected. In other words, only if a Profile refers to the rule will be rule be triggered (and the check executed).
  2. severity="low" is a matter of documenting how severe a non-compliant rule is.
  3. weight="0.0" gives a weight on the Rule. In this case, the weight is 0, meaning that the rule might be recommended but by itself does not introduce a security vulnerability or mismatch. Of course, you are free to use whatever value suits you best.

We also notice a fixtext element. When the rule failed (the system is not compliant to the rule) then the fixtext should assist administrators in securing the system again. In other words, fixtext are the human-readable instructions on remediating the system.

Finally, we have the check element. This element tells the XCCDF interpreter that an automated validation is defined. The type of automated validation is provided by the system attribute, which in this case refers to the SCE system. The check-content-ref element refers to the script to be executed.

Let's look at the contents of the script:

``` {lang="bash"}


Get CHOST value

echo "Getting CHOST variable content through portageq."; my_chost=$(portageq envvar CHOST); if [ -z "${my_chost}" ]; then echo "-- The portageq command failed. Falling back to glibc build info."; my_chost=$(cat /var/db/pkg/sys-libs/glibc-*/CHOST | tail -1); fi echo "-- Got CHOST=${my_chost}";

Get current GCC version

echo "Getting current GCC version through /etc/env.d/gcc/config-"; current_gcc=$(grep CURRENT /etc/env.d/gcc/config- | sed -e "s:CURRENT=${my_chost}-::g" | sed -e "s:([0-9.-r]){$,-.$}:\1:g" ); echo "-- Got version=${current_gcc}";

Get type

echo "Getting compiler type (profile/spec) through its CURRENT= value."; current_type=$(grep CURRENT /etc/env.d/gcc/config-* | sed -e "s:CURRENT=${my_chost}-${current_gcc}::g" | sed -e 's:^-::g'); echo "-- Got type=${current_type}";

echo "Checking USE flags of gcc-${current_gcc} for hardened USE flag."; grep -q hardened /var/db/pkg/sys-devel/gcc-${current_gcc}/USE; current_hardened_use=$?; if [ ${current_hardened_use} -ne 0 ]; then echo "!! GCC ${current_gcc} is not build with USE=hardened!"; echo "!! Please enable a hardened profile."; exit ${XCCDF_RESULT_FAIL}; else echo "-- GCC ${current_gcc} is build with USE=hardened."; if [ -z "${current_type}" ]; then echo "-- The default type is used which is a hardened type."; exit ${XCCDF_RESULT_PASS}; else echo "!! A non-default type is used: ${current_type}"; echo "!! This means not all hardened toolchain measures are enabled."; exit ${XCCDF_RESULT_FAIL}; fi fi

As you can see, the script can give output when needed, but the most
important part is that it has to return a particular return value. This
return value is provided through environment variables

All we need to do now is to include this `Rule` in the `Profile`.

``` {lang="xml"}


We can now evaluate the XCCDF file on the system if we refer to the right profile. By selecting the profile, the XCCDF interpreter will also automatically check the rules referred to by the profile (and the rules that do not have selected="false" set too).

# oscap xccdf eval --profile ... gentoo-xccdf.xml

Title   Test if the hardened toolchain is used
Result  pass

Title   Test if sulogin is used for single-user boot (/etc/inittab)
Result  fail

Now, if you want to check this on several systems, you would need to distribute not only the XCCDF file, but also all files referred to by the XCCDF document. As this is counterproductive, SCAP supports Data Streams. A data stream is a single file that includes the content of all files. With openscap, data streams can be made as follows:

# oscap ds sds-compose postgresql-xccdf.xml postgresql-ds.xml

So now we have a document explaining the secure setup of a component, and included automated checks to validate system compliance with the document using scripts. In the next post, I'll go on with OVAL.

This post is part of a series on SCAP content:

  1. Documenting security best practices - XCCDF introduction
  2. An XCCDF skeleton for PostgreSQL


To comment as a guest, use "Or sign up with disqus" and then select the "I'd rather post as guest" option.

comments powered by Disqus