SCAP Security Guide now has an HTML guide for each profile

In the past the SCAP Security Guide project built one or just a few HTML guides for some chosen profiles. The build system also used a special profile called allrules which is no longer supported since OpenSCAP 1.1.0. This caused issues when building SSG against new versions of OpenSCAP.

To fix it once and for all I have created a pull request that has been merged and has been released as part of SSG 0.1.24. Since then SSG builds one guide for each profile and provides an index file that allows user to switch between the profiles. The reasoning for building so many guides is that if we ship a profile it is important enough to warrant shipping an HTML guide for it as well.

Here is how the new profile switcher looks like:

ssg_new_guides

I have uploaded the RHEL6 guides with the profile switcher to fedorapeople, take a look:

https://mpreisle.fedorapeople.org/ssg_new_guides/ssg-rhel6-guide-index.html

We plan to install these guides in downstream packages (e.g. Fedora). Instead of bundling them with the main package we will create a subpackage -doc with the guides and other optional documentation material.

Feedback appreciated! Do you think we should upload these guides somewhere for people to browse? Are there any features missing?

Customizing HTML reports and guides in OpenSCAP 1.1.0 and higher

Introduction

OpenSCAP 1.1.0 introduced brand new HTML5 report and guide styles. These were a result of an almost complete rewrite of all the XSLT code. See openscap HTML report redesign for more info.

This rewrite changed the way the reports and guides can be customized. This blog post will go through all the steps necessary to customize the reports from both the downstream packager perspective and the user perspective. We will focus on branding because this is the most requested customization. Users will be able to change the logo, header and footer of reports and guides.

Downstream branding

After installing openscap of version 1.1.0 or higher, let us look at various files in /usr/share/openscap/xslt.

$ ls -1 /usr/share/openscap/xsl/

legacy-fixtpl-bash.xml
legacy-fix.xsl
legacy-xccdf-share.xsl
oval-results-report.xsl
xccdf_1.1_remove_dangling_sub.xsl
xccdf_1.1_to_1.2.xsl
xccdf-branding.xsl
xccdf-guide-impl.xsl
xccdf-guide.xsl
xccdf-report-impl.xsl
xccdf-report-oval-details.xsl
xccdf-report.xsl
xccdf-resources.xsl
xccdf-share.xsl

The xccdf-report.xsl is the entry point to the XSLT stylesheet, it specifies which parameters are needed and does some initial negotiation like guessing which benchmark the user wants to generate for. The xccdf-report-impl.xsl is the most interesting file, it contains most of the logic. xccdf-share.xsl contains various template code needed in both guide and report, to avoid code duplication.

Let us focus on a file called xccdf-branding.xsl. This file was designed specifically to help with downstream branding. If we look inside we will see 5 named templates:

  • xccdf-branding-logo
  • xccdf-report-header
  • xccdf-report-footer
  • xccdf-guide-header
  • xccdf-guide-footer

Their meaning should be self explanatory. The downstreams can patch those to insert a different logo or even different texts. Changes to this file will affect every user that runs oscap xccdf generate guide or oscap xccdf generate report.

Example of changed xccdf-report-header – different header:

<xsl:template name="xccdf-report-header">
    <nav class="navbar navbar-default" role="navigation">
        <div class="navbar-header" style="float: none">
            <a class="navbar-brand" href="#">
                <xsl:call-template name="xccdf-branding-logo"/>
            </a>
            <div><h1>Security Compliance Report</h1></div>
        </div>
    </nav>
</xsl:template>

Example of changed xccdf-report-footer – downstream ticket system hint:

<xsl:template name="xccdf-report-footer">
    <footer id="footer">
        <div class="container">
            <p class="muted credit">
                Please report any issues to the <a href="https://bugs.my-cool-distro.tld">ticket system</a>. Generated using <a href="http://www.open-scap.org">OpenSCAP</a>
                <xsl:if test="$oscap-version">
                    <xsl:value-of select="concat(' ', $oscap-version)"/>
                </xsl:if>
            </p>
        </div>
    </footer>
</xsl:template>

The OpenSCAP team would really appreciate if you kept some link to the upstream but the license does not enforce or even require that.

User branding

Sometimes you might want to change the branding just for this one use-case without affecting all users on the system.

This is not commonly used and as such may have more issues than when using the system-wide XSLTs!

Let us copy the XSLTs as they are into a folder where we will do all the changes we need.

cp -r /usr/share/openscap/xsl ~/custom-oscap-xsl
cd ~/custom-oscap-xsl

We can now do all the customizations similarly to the previous section. Lets change the header from OpenSCAP Evaluation Report to Security Compliance Report in xccdf-branding.xsl. Save the changes and proceed to generate a report. Instead of using oscap xccdf generate report we have to use oscap xccdf generate custom --stylesheet $OUR_STYLESHEET

cd ~/custom-oscap-xsl
oscap xccdf generate custom --stylesheet ~/custom-oscap-xsl/xccdf-report.xsl arf.xml > report.html
firefox report.html

We can see that the report has “Security Compliance Report” as heading instead of “OpenSCAP Evaluation Report”.

The oscap xccdf generate custom code path in the oscap tool does not offer as many parameters as generate report or generate guide do. There parameters may have to be passed in a different way, even hard-coded into the XSL template if necessary! It all depends on the use-case.

What about OpenSCAP 1.0.x?

The method outlined in User branding also works with OpenSCAP 1.0.x. While the new reports are not regularly tested with OpenSCAP 1.0.x they seem to work fine. Use at your own risk!

$ cd ~/custom-oscap-xsl
$ oscap --v
OpenSCAP command line tool (oscap) 1.0.11
Copyright 2009--2015 Red Hat Inc., Durham, North Carolina.
...

oscap xccdf generate custom --stylesheet ~/custom-oscap-xsl/xccdf-report.xsl arf.xml > report.html
firefox report.html

Scanning remote machines with OpenSCAP

Introduction

oscap-ssh has recently been merged into OpenSCAP 1.2.x and is available in the OpenSCAP 1.2.3 release, see https://github.com/OpenSCAP/openscap/pull/69. This new tool enables painless transparent remote machine scanning with the familiar oscap argument syntax. The functionality was inspired by SCAP Workbench remote scan.

Prerequisites

The script is designed to be as lean as possible. It is usable even outside the openscap context. It requires just bash, ssh, scp and mktemp to perform OVAL and XCCDF evaluation of remote machines. These tools are readily available on all Linux distributions, BSDs, MacOS X and even Windows via Cygwin.

The remote machine has to have oscap installed and in $PATH. This can be accomplished by installing openscap-scanner (or openscap-utils if openscap-scanner is not available) on the remote machine. On the local machine in most cases you just need to download the script and chmod +x it.

What follows is a walk through a typical usage of the script. The output has been shortened for brevity. OVAL evaluation would be very similar, the documentation included in the script should be enough to get it working.

Usage

oscap-ssh user@host SSH_PORT --v
oscap-ssh user@host SSH_PORT info INPUT_CONTENT
oscap-ssh user@host SSH_PORT xccdf eval INPUT_CONTENT
oscap-ssh user@host SSH_PORT oval eval INPUT_CONTENT

Example 1

The following command evaluates a remote Fedora machine as root. HTML report is written out as report.html on the local machine. Can be executed from any machine that has ssh, scp and bash. The local machine does not need to have openscap installed.

$ oscap-ssh root@192.168.1.13 22 xccdf eval --profile xccdf_org.ssgproject.content_profile_common --report report.html /usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml

The output:

Connecting to 'root@192.168.1.13' on port '22'...
root@192.168.1.13's password:
Connected!
Copying input file '/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml' to remote working directory '/tmp/tmp.yEsdWV54ry'...

Starting the evaluation...
Title   gpgcheck Enabled In Main Yum Configuration
Rule    xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated
Result  pass

Title   gpgcheck Enabled For All Yum Package Repositories
Rule    xccdf_org.ssgproject.content_rule_ensure_gpgcheck_never_disabled
Result  fail

[snip]

Title   Enable the NTP Daemon
Rule    xccdf_org.ssgproject.content_rule_service_ntpd_enabled
Result  fail

Title   Specify a Remote NTP Server
Rule    xccdf_org.ssgproject.content_rule_ntpd_specify_remote_server
Result  fail

oscap exit code: 2
Copying back requested files...

Removing remote temporary directory...
Disconnecting ssh and removing master ssh socket directory...

report.html is now on the local machine and can be opened there. The connection to the remote machine is closed, no temporary data remains on the remote machine.

Example 2

A more full example, uses a tailoring file and also copies back ARF and XCCDF results. The tailoring file is automatically copied from local machine to remote.

$ oscap-ssh root@192.168.1.13 22 xccdf eval --profile xccdf_org.ssgproject.content_profile_common --report report.html --results results.xml --results-arf arf.xml --tailoring-file ssg-fedora-ds-tailoring.xml /usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml

The output:

Connecting to 'root@192.168.1.13' on port '22'...
root@192.168.1.13's password:
Connected!
Copying input file '/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml' to remote working directory '/tmp/tmp.yVy6snyC88'...

Copying tailoring file 'ssg-fedora-ds-tailoring.xml' to remote working directory '/tmp/tmp.yVy6snyC88'...

Starting the evaluation...
Title gpgcheck Enabled In Main Yum Configuration
Rule xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated
Result pass

Title gpgcheck Enabled For All Yum Package Repositories
Rule xccdf_org.ssgproject.content_rule_ensure_gpgcheck_never_disabled
Result fail

[snip]

Title Enable the NTP Daemon
Rule xccdf_org.ssgproject.content_rule_service_ntpd_enabled
Result fail

Title Specify a Remote NTP Server
Rule xccdf_org.ssgproject.content_rule_ntpd_specify_remote_server
Result fail

oscap exit code: 2
Copying back requested files...

Removing remote temporary directory...
Disconnecting ssh and removing master ssh socket directory...

Future plans

Most if not all SCAP content requires root access to evaluate. So it is expected that the user will login as root to a remote machine. At the same time the guidances recommend to disallow root ssh access. This creates ironic situations where remote scanning and remediating the machine cuts of the access.

We hope to solve this in the future by logging in as normal user and running sudo before scanning.

Conclusion

Scanning remote machines is now almost as easy as scanning local ones. For use-cases where the user has public-key authentication setup the scanning is truly painless.

I believe this script might be very valuable for content authors and auditors. In the future I expect SCAP Workbench to use this script instead of its own code for remote scanning. The migration will have to wait until OpenSCAP 1.2.3+ is available on platforms where Workbench ships.

mingw-bundledlls – Automatically bundle DLLs for Windows deployment

Download the script – https://github.com/mpreisler/mingw-bundledlls

I recently had to build an application with mingw32 on Fedora 21 and then prepare the binaries for usage on Windows without any external dependencies.

In the past I used to look at the list of dependencies using depends32.exe or similar tools on Windows and then copy all the DLLs manually. Needless to say that is very repetitive work and gets annoying quickly. Googling for existing solutions did not yield any useful results so I decided to solve this myself.

The solution I came up with is a small Python 3 script that uses objdump  to recursively gather all dependencies of an executable file (WinPE EXE) or a dynamic loaded library (DLL). I published the script on GitHub – https://github.com/mpreisler/mingw-bundledlls.

The script can be run from Linux and only depends on python3 and objdump from binutils. It is very convenient to just run:

mingw32-configure && make && mingw-bundledlls --copy $EXE

After this invocation all the necessary DLLs will be right next to the EXE so you can just pack it all up and upload the release.

Practical example

I will show how I build SCAP Workbench for Windows from scratch on Fedora 21.

git clone https://github.com/OpenSCAP/scap-workbench.git
cd scap-workbench
mkdir build
cd build
mingw32-cmake ../
make -j 4

After the previous command finishes build/scap-workbench contains all the necessary resources including scap-workbench.exe. You however cannot run it on Windows without getting an error message about missing DLLs. Let us now run the script to solve that 🙂

$ mingw-bundledlls ./scap-workbench/scap-workbench.exe

Found the following dependencies:

/usr/i686-w64-mingw32/sys-root/mingw/bin/libstdc++-6.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libpng16-16.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/zlib1.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libcurl-4.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libxslt-1.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/QtGui4.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/iconv.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libxml2-2.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libidn-11.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libintl-8.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libopenscap-8.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libcrypto-10.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/QtNetwork4.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libexslt-0.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libssh2-1.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/QtXmlPatterns4.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libpcre-1.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/QtCore4.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libssl-10.dll

After confirming that the script did not find anything crazy we can proceed to copy the dependencies next to the exe. Use –copy as an option to accomplish that.

$ mingw-bundledlls --copy ./scap-workbench/scap-workbench.exe

Copying enabled, will now copy all dependencies next to the exe_file.

Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libidn-11.dll' to './scap-workbench/libidn-11.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libssh2-1.dll' to './scap-workbench/libssh2-1.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll' to './scap-workbench/libwinpthread-1.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libxml2-2.dll' to './scap-workbench/libxml2-2.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/QtNetwork4.dll' to './scap-workbench/QtNetwork4.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libstdc++-6.dll' to './scap-workbench/libstdc++-6.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/zlib1.dll' to './scap-workbench/zlib1.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libopenscap-8.dll' to './scap-workbench/libopenscap-8.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libpcre-1.dll' to './scap-workbench/libpcre-1.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll' to './scap-workbench/libgcc_s_sjlj-1.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/QtXmlPatterns4.dll' to './scap-workbench/QtXmlPatterns4.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libexslt-0.dll' to './scap-workbench/libexslt-0.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libcurl-4.dll' to './scap-workbench/libcurl-4.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libpng16-16.dll' to './scap-workbench/libpng16-16.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/QtCore4.dll' to './scap-workbench/QtCore4.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libssl-10.dll' to './scap-workbench/libssl-10.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libxslt-1.dll' to './scap-workbench/libxslt-1.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libcrypto-10.dll' to './scap-workbench/libcrypto-10.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/QtGui4.dll' to './scap-workbench/QtGui4.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/iconv.dll' to './scap-workbench/iconv.dll'
Copying '/usr/i686-w64-mingw32/sys-root/mingw/bin/libintl-8.dll' to './scap-workbench/libintl-8.dll'

The script also runs upx on all the binaries if –upx is supplied. That is useful for minimizing installed size of your application.

At this point I just zip build/scap-workbench and test it on Windows.

Runtime loaded DLLs

The script will not find any runtime loaded dependencies. Doing that would be possible by looking for LoadLibrary, LoadLibraryEx, … calls but probably not worth it. Bundling runtime loaded DLLs is a potential nightmare depending on whether relative or absolute paths are used when calling LoadLibrary. Inevitably the script would have to alter the EXE itself or any of the DLLs that is calling LoadLibrary.

Since I did not need this I decided to ignore this issue 🙂