Skip to content

Customizing stix to html transform

mattcoarr edited this page Jan 16, 2014 · 20 revisions

Quick Customization Via Stylesheet Parameters

NOTE: There is an example of passing in custom parameters in the git repo at stix-to-html/examples/examples-custom-stylesheet-parameters

The following parameters can be passed into the stylesheet to customize the html:

  • includeFileMetadataHeader [default: true]
  • includeStixHeader [default: true]
  • enablePreformattedDescriptions [default: false]
  • displayConstraints [default: true]

These stylesheet parameters can be passed in when you're calling stix_to_html.xsl. How you do varies with your xslt engine.

For saxon, you'd run something like the following (the question mark before the parameter tells saxon the parameter will be interpreted as xpath):

java -jar /opt/saxon/saxon9he.jar -xsl:$STIX_TO_HTML_HOME/stix_to_html.xsl -s:stix_sample.xml -o:stix_sample.html '?enablePreformattedDescriptions=true()'

Customizing the Title/Header/Footer/CSS

NOTE: There is an example of customizing these elements in the git repo at stix-to-html/examples/examples-custom-title-header-footer-css.

The header, footer, title, and css can easily be customized.

Inside stix_to_html.xsl there are four corresponding named templates:

  • customHeader
  • customFooter
  • customTitle
  • customCss

The easiest and cleanest way to customize this is to create your own stylesheet, import stix_to_html.xsl, and then define your own named templates with the above names.

There is an example of this in stix_to_html__customized.xsl

The css that determines the color scheme for the main top level items (Observables, TTPs, Indicators, etc) is contained in theme_default.css. The colors are defined with css's hsl() color definitions. The general color can be tweaked by just adjusting the first parameter, the hue (which is specified in degrees and varies from 0-359). By adjusting the saturation and lightness, the darness or lightness can be adjusted.

There are also three stylesheet parameters that may be used to control the output. Each one is a boolean and can be passed in on the command-line or programatically.

Here are the three stylesheet parameters. Each one defaults to true.

  • includeFileMetadataHeader
  • includeStixHeader
  • displayConstraints

"includeFileMetadataHeader" determines if the header with the stix version, filename, and html generation date is going to be displayed.

"includeStixHeader" determines if the header table (generated from the stix:STIX_Header contents) is dislayed.

"displayContraints" determines if the contraint properties on cybox:Properties (and other similary formatted data elements) will be displayed. This includes such information what type of matching is performed (equals or string match).

List of Object-specific Templates

  • cybox
    • URIObject (cybox_objects.xsl)
    • WindowsRegistryKeyObjectType (cybox_objects.xsl)
    • HTTP_Request_Response (cybox_objects.xsl)
    • EmailMessageObjectType (cybox_object.xsl)
    • [not really object-specific] any cybox:Properties text node with ##comma## delimited range or list (cybox_objects.xsl)
  • indicator
    • sighting (stix_objects.xsl)
    • any description element in any namespace (stix_objects.xsl)

Customizing a Basic Object Template

There are two main types of objects, those that fall directly inside of a Observable, and those that are nested somewhere inside of the main observable object. The templates that you need to create are a little bit different in each case.

Objects directly inside Observable (the main object)

First, for the case of an object nested directly inside of an Observable...

Here's an abridged version of an indicator having an observable that contains a email object [the full file is located in the stix-to-html repo at stix-to-html/blob/beta3/examples/STIX_Phishing_Indicator.xml]:

<stix:Indicator xsi:type="indicator:IndicatorType"
  id="example:Indicator-19e5d914-cc0e-478f-a523-b099a34383f7">
  <indicator:Title>"US-China" Phishing Indicator</indicator:Title>
  <indicator:Observable
    id="example:Observable-Pattern-5f1dedd3-ece3-4007-94cd-7d52784c1474">
    <cybox:Object id="example:Object-3a7aa9db-d082-447c-a422-293b78e24238">
      <cybox:Properties xsi:type="EmailMessageObj:EmailMessageObjectType">
        <EmailMessageObj:Header>
          <EmailMessageObj:From category="e-mail">
            <AddressObj:Address_Value condition="Contains">@state.gov</AddressObj:Address_Value>
          </EmailMessageObj:From>
        </EmailMessageObj:Header>
      </cybox:Properties>
    </cybox:Object>
  </indicator:Observable>
</stix:Indicator>

The important thing to note here is that ou have a cybox:Object with an immediate child cybox:Properties that has @xsi:type="EmailMessageObj:EmailMessageObjectType".

Because we're using xslt without schema validation (and not using psvi -- post schema validation infoset), the xsi:type attribute is just treated as a string like any other attribute. So we'll have to do a little fancy leg work to get the "EmailMessageObj:" prefix parsed properly.

That means that our template will look like this:

<xsl:template match="cybox:Properties[fn:resolve-QName(fn:data(@xsi:type), .)=fn:QName('http://cybox.mitre.org/objects#EmailMessageObject-2', 'EmailMessageObjectType')]" priority="20000">
  <div>#####</div>
  <div>CUSTOM EMAIL TEMPLATE</div>
  <div>#####</div>
</xsl:template>

And then you probably want to do something with the contents of that object. Here's a quick example that will print out the field of the "From" header and the operator.

<xsl:template match="cybox:Properties[fn:resolve-QName(fn:data(@xsi:type), .)=fn:QName('http://cybox.mitre.org/objects#EmailMessageObject-2', 'EmailMessageObjectType')]" priority="20000">
  <div>#####</div>
  <div>CUSTOM EMAIL TEMPLATE</div>
  <xsl:variable name="from" select="EmailMessageObj:Header/EmailMessageObj:From/AddressObj:Address_Value" />
  <xsl:if test="$from">
    <xsl:variable name="fromText" select="$from/text()" />
    <xsl:variable name="fromCondition" select="fn:data($from/@condition)" />
    <div>From <xsl:value-of select="$fromCondition"/> "<xsl:value-of select="$fromText"/>"</div>
  </xsl:if>
  <div>#####</div>
</xsl:template>

Objects nested deeper inside observable objects

Second, you might want to customize the appearance of some nested portion of an object.

This is generally simpler because you're just matching directly on xml elements.

One caveat to be aware of is that if you're customizing content that shows up inside content that is shown using the default cybox:Properties styling, you may need to add mode="cyboxProperties" to your template. That is the case if the content before your customizations was showing up as a nested tree.

For instance, this is how the Hash element is formatted:

<xsl:template match="Common:Hash" mode="cyboxProperties">
...
</xsl:template>

Note that this is not in the mode cyboxProperties (because this falls under the file template).

Here's an example of where the Port elements are formatted. In this case the element does show up under a cyboxProperties mode because the parent content uses the cyboxProperties tree view.

<xsl:template match="*:Port[contains(@xsi:type,'PortObjectType')]|*:Port[./*:Port_Value]" mode="cyboxProperties">
...
</xsl:template>

And if you want to support both cases

Sometimes you don't know how the object will appear. You want to support it as the main object in an observable or nested inside some other object.

Here's an example of how to accomplish that (the first part of the match matches http:HTTP_Request_Response elements directly in the text; the second part finds cybox:Properties elements that have an xsi:type with HTTP_Request_Response)...

<xsl:template match="http:HTTP_Request_Response|cybox:Properties[fn:resolve-QName(fn:data(@xsi:type), .)=fn:QName('http://cybox.mitre.org/objects#HTTPSessionObject-2', 'HTTP_Request_Response')]">
...
</xsl:template>

Another node about cyboxProperties tree based view...if you want to customize content whether or not it shows up inside of an cyboxProperties display, you can have one template that matches the pattern with the mode="cyboxProperties" and then applies the template on the context node without the mode like this...

  <xsl:template match="http:HTTP_Request_Response|cybox:Properties[fn:resolve-QName(fn:data(@xsi:type), .)=fn:QName('http://cybox.mitre.org/objects#HTTPSessionObject-2', 'HTTP_Request_Response')]" mode="cyboxProperties">
    <xsl:apply-templates select="." />
  </xsl:template>
  
  <xsl:template match="http:HTTP_Request_Response|cybox:Properties[fn:resolve-QName(fn:data(@xsi:type), .)=fn:QName('http://cybox.mitre.org/objects#HTTPSessionObject-2', 'HTTP_Request_Response')]">
  <!-- details here -->
  ...
  </xsl:template>

Customizing Major Item Tables (Observables, TTPs, etc)

Major Table Items -- The Tables Themselves

The major items on the page are Observables, TTPs, Indicators, etc. Sometimes you'll need to tweak their appearance. This is not really an everyday customization, but a little background will help.

Most of the work for this is done in stix_to_html.xsl and stix_common.xsl.

The root template that sets up the whole page is <xsl:template match="/">

Inside of there, you'll then find div.topLevelCategoryTables (that's div with the class topLevelCategoryTables). This is where you'll find the major item tables being printed out. Each one is printed out by a call to processTopLevelCategory.

Inside processTopLevelCategory, each child item will be looped over to produce a row in the main tables. This is done via a call to printGenericItemForTopLevelCategoryTable. Each items becomes two rows contained within a single tbody. The first row has the expandable toggle; the second row will have the expanded content injected when the item is expanded.

If ou wish to modify the contents of the items themselves, you'll want to edit the printReference templates.

Major Table Items -- the Expanded Contents