FireEye + Splunk: Intermediate Guide

Transcription

FireEye + Splunk: Intermediate Guide
FireEye + Splunk:
Intermediate Guide
Table of Contents
Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Current Integration Efforts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Creating Advanced Connectors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Splunk Listener . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Splunk Role. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Splunk User . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
FireEye Data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Examining a Raw Event. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Single Line JSON. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Multiline JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Universal Parser. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
According to Splunk: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Parsing Other Formats. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Experimenting with XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Single Line XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Multiline XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Universal Parser. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Summary of Differences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Creating Apps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Moving a Dashboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Customizing an App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1 www.fireeye.com
App Navigation Colors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
App Icons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Dashboard Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Sample FireEye Dashboards. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
NX (web MPS). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Alerts -> Alerts:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Alerts -> Callback Activity:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Time Frames:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Panels to Enhance Visibility. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
NX (web MPS). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Severity Pie Chart: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Malware Pie Chart:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Top 20 Most Active Target IPs: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Top 20 Most Active Destination Ports: . . . . . . . . . . . . . . . . . . . . . . . . 37
Most Active Sensors:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Adding Forms (Filters) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Adding Tokens to Search Strings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Adding User Input Forms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
GeoIP Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
iplocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
geostats. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Adding Drilldowns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2 www.fireeye.com
Requirements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Supporting File Location: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
How to Import Support Files:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Drilldown by Event ID. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Supporting files on the server:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
inpage_drilldown_form.css. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
inpage_drilldown_form.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Using Curl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Splunk Search:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Special Thanks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
About FireEye . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Appendix A. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3 www.fireeye.com
Introduction
Are you a Splunk ninja and now have a FireEye appliance? If so, our previous introductory guide
(http:// www.fireeye.com/resources/pdfs/FireEye-Splunk-intro-to-integration-guide.pdf) and
this intermediate guide should help you understand custom FireEye and Splunk integration
options in no time. The previous introductory paper walks users through integrating the devices
via syslog and some simple Splunk data carving. This paper extends that knowledge by showing
users how to consume more in-depth FireEye (XML and JSON) data via HTTP POST and how
to use some of Splunk’s advanced features to build a more robust dashboard. Those readers
who want to quickly arrive at one possible integration solution should take note of the Current
Integration Efforts section below or the Universal Parser section and then use the sample code
within Appendix A.
Current Integration Efforts
If your organization is using the latest version of Splunk (6.x), try out our free FireEye App for
Splunk Enterprise v3 (http://apps.splunk.com/app/1845/). This new app provides increased
flexibility by supporting multiple FireEye appliances as well as multiple protocols and formats
for sending data to Splunk. This app may not be fully backward compatible because it takes
advantage of many Splunk 6.x features that were not previously available.
If your organization is still using Splunk version 4.x or 5.x, you can easily download and use
the free—but unsupported—Splunk for FireEye v2 app to integrate the two technologies. This
Splunk app utilizes and parses FireEye’s rich extended XML output. This downloadable app is
available here: https://apps.splunk.com/app/409/.
The rest of this article is written for those that want to start from scratch or start from one of
the above apps and learn to customize them. This article will outline various protocols and
formats available from FireEye and explore the parsing options provided by Splunk.
Creating Advanced Connectors
In our previous introductory guide to integrating FireEye and Splunk, we covered creating
connectors between the appliances using CEF or CSV format sent via syslog. When attempting
to pass a more robust format such as extended XML or JSON via syslog, we discovered that the
message was being prematurely truncated. To see the solution, download our new FireEye for
Splunk Enterprise v3 app and check out the props.conf file. In this paper we will show how to
use Splunk’s RESTful API to pass event data in XML or JSON format using an encrypted HTTPS
POST. The steps below should assist in the setup.
4 www.fireeye.com
Splunk Listener
A default installation of Splunk 6 or later should automatically be listening via the RESTful API
on port 8089. However, this can be verified by navigating to this API using a standard web
browser: https://<SplunkBox>:8089
Figure 1: Splunk RESTful API is available on the default port 8089
If for whatever reason, this service is not available, verify the port number using the following
steps:
• Using a web browser, log in to the Splunk web interface: http://<SplunkBox>:8000
• Username: <admin account>
• Password: <password>
5 www.fireeye.com
Set up the Splunk listener:
• Click the "Settings" hyperlink in the top right-hand corner of Splunk
• Under "System", click “System settings"
• Click “General settings”
• Note the value in the “Management port” field
Figure 2 : The port that Splunk uses for its RESTful API
Splunk Role
We now want to create a user in Splunk that will be used for passing the RESTful API data.
However, there is currently no predefined Splunk role that can perform the job while adhering
to the principle of least privilege. We could just assign our new user the “admin” role, but this
would create a more severe situation should this account ever become compromised.
The following instructions will create a Splunk role that has only the ability to accept data via
the RESTful API:
• Log into the Splunk web UI with an admin account
• Click “Settings -> Users and authentication -> Access controls”
• Click “Roles” -> Click the "New" button
• Role Name: RESTfulAPI
• Capabilities: edit_tcp
6 www.fireeye.com
Splunk User
Now that we have created a secure role, we need to create an account that will be used for
authentication to post our event data.
Note: Make sure the account name is alphanumeric only (no whitespaces)
Example username: fireeye
• Again, log into the Splunk web UI with an admin account
• Click “Settings -> Users and authentication -> Access controls”
• Click “Users” -> Click the "New" button
• Fill in the required data
• Privilege Note: Remember to use our newly created “restfulapi” role
• Click the "Save" button
Figure 3: Creating the Splunk admin account that will accept our HTTP POST messages.
7 www.fireeye.com
FireEye Data
Now that Splunk is listening and ready for data, we have to configure FireEye to send HTTP
POST data to the connector. As mentioned in our introductory paper, the FireEye appliances are
very flexible regarding notification output and support the following formats using HTTP POST:
Text – Normal
JSON – Normal
XML – Normal
Text – Concise
JSON – Concise
XML – Concise
Text – Extended
JSON – Extended
XML – Extended
In contrast, when sending data using syslog, all of the above formats are supported with the
addition of CEF, LEEF, and CSV. Don’t worry though, these three additional formats should not
be needed because other formats provide more robust data.
For our first example, we will use Extended JSON—but this does not necessarily mean that it is
the best format. It is just one possible option (see the “Parsing Other Formats” section for more
details as to why we are selecting JSON over XML). Complete the following steps to send data
to Splunk using extended JSON via HTTP POST:
• Log into the FireEye appliance with an administrator account
• Click “Settings”
• Click “Notifications”
• Click the “http” hyperlink
• Make sure the "Event type" check box is selected
• If the Global HTTP Settings are already set—leave them
Next to the "Add HTTP Server" button, type "SplunkHTTP". Then click the "Add HTTP Server"
button. In the newly created “SplunkHTTP” entry, ensure that the following check boxes are
selected:
• Enabled
• Auth
• SSL Enable
8 www.fireeye.com
Enter the following per instance settings (which will override the global setting above): Server
URL: https://<SplunkAD.DR.ESS>:<PORT>/services/receivers/simple?
host=<FireEyeAddress>&source=wmps&sourcetype=fe_json
• Username: fireeye (or username created in Splunk)
• Password: <password created above in Splunk>
Note: The default port used above is 8089—unless it has been changed.
Remember to click the “Update” button when finished.
Figure 4: Steps to configure the FireEye appliance to send data to Splunk
9 www.fireeye.com
Now test the sending and receiving of notifications on the same FireEye Notifications page by
clicking the "Test-Fire" button at the bottom. Flip back over to the Splunk interface and check
out the raw event data.
FireEye events will show up under “Search -> Data Summary” button or by typing
sourcetype=fe_json in the Search box.
Figure 5: The Splunk dashboard now shows events
If raw data is not present, skip down to the “Troubleshooting” section at the bottom of this
guide.
10 www.fireeye.com
Examining a Raw Event
Now that the connectors are working, we can view the raw data.
Pro-tip: FireEye JSON and XML notifications changed in version 7.1 of the appliance from single
line to multiline events. This affects Splunk’s native ability to parse the events; thus, we will
need to create a custom sourcetype for Splunk to handle the change.
Single Line JSON
If using a FireEye appliance prior to software version 7.1 (which uses single line JSON as shown
below), notice that Splunk will natively know when to split the packets. After clicking on the
Data Summary button or searching for “FireEye”, the raw JSON alert notification should be
present. The events will look similar to the following:
{"msg": "extended", "product": "Web MPS", "version":
"7.0.0.138133","appliance": "WebMPS.localdomain", "alert":
{"src": {"mac":"XX:XX:XX:XX:XX:XX", "ip": "169.250.0.1",
"host": "NA-testing.fe-notify-examples.com", "vlan": "0",
"port": "10"}, "severity": "majr", "alert- url": "https://
WebMPS.localdomain/event_stream/events_for_bot?inc_id=1",
"explanation": {"target-os": "WindowsXYZ", "protocol": "tcp",
"service": "FireEye-TestEvent EA Service", "analysis":
"replay", "cnc-services": {"cnc- service": [{"protocol":
"tcp", "port": "200", "channel": "FireEye-TestEvent Channel
1", "address": "FireEye-TestEvent.example.com"}, {"protocol":
"tcp",
"port":
"201",
"channel":
"cncs
2
channel
fields",
"address": "127.0.0.100"}]}, "target-application":
"IEx123", "urls": "2", "malware- detected": {"malware":
[{"content": "lms-0/contents", "url": "compl_0_1- someurl.
x1y2z3.com", "type": "link", "name": "Suspicious.URL"},
{"content": "lms-0/contents", "url": "os-change-anomaly_0_1someurl.x1y2z3.com", "type":"link", "name": "Suspicious.URL"},
{"objurl": "compl_0_1-someurl.x1y2z3.com", "name": "FireEyeTestEvent-SIG"}]}}, "occurred": "2014-04-13T21:02:48Z","id":
"1", "action": "notified", "dst": {"ip": "127.0.0.20",
"mac":"XX:XX:XX:XX:XX:XX", "port": "20"}, "name": "webinfection"}}
11 www.fireeye.com
At first, this data looks a bit confusing. Fortunately, the Splunk dashboard highlights and
separates the data to make it a little easier to view and understand. By clicking the dropdown
arrow, we see how Splunk natively parses JSON into fields that we can use to build our
dashboard.
Figure 6: Search term highlighting and Splunk parsed fields
12 www.fireeye.com
Multiline JSON
With the release of FireEye OS version 7.1, JSON and XML notifications are now multiline (aka
pretty print)—meaning each line ends in a hard return and follow-on lines are indented as shown
in the example below:
{
"msg": "extended",
"product": "Web MPS", "version": "7.1.0.180577",
"appliance": "WebMPS.localdomain", "alert": {
"src": {
"mac": "00:11:33:55:77:99",
"ip": "169.250.0.1",
"host": "DM-testing.fe-notify-examples.com", "vlan": "0",
"port": "10"
},
--SNIP--occurred
When comparing this with the JSON from the single line section above, it is evident that this
enhances the human readability. Unfortunately, it causes a problem with the native parser in
Splunk. The hard returns cause Splunk to split the packet at the occurred field shown in the
screenshot below.
Figure 7: Multiline JSON is prematurely split in Splunk
This will surely break our dashboards if we don’t account for the change in format.
13 www.fireeye.com
Universal Parser
To solve this, we can define our own sourcetype and specify where Splunk will break on events.
But before we do this, let’s make sure we understand how line breaking works so we can
optimize the parsing in Splunk:
According to Splunk:
“Splunk Enterprise determines event boundaries in two steps:
1. Line breaking, which uses the LINE_BREAKER attribute's regular expression value to split the
incoming stream of bytes into separate lines. By default, the LINE_BREAKER is any sequence
of newlines and carriage returns (that is, ([\r\n]+)).
2. Line merging, which only occurs when the SHOULD_LINEMERGE attribute is set to "true"
(the default). This step uses all the other line merging settings (for example, BREAK_ONLY_
BEFORE, BREAK_ONLY_ BEFORE_DATE, MUST_BREAK_AFTER, etc.) to merge the
previously-separated lines into events.
If the second step does not run (because you set the SHOULD_LINEMERGE attribute to "false"),
then the events are simply the individual lines determined by LINE_BREAKER. The first step is
relatively efficient, while the second is relatively slow. If you are clever with the LINE_BREAKER
regex, you can often make Splunk get the desired result by using only the first step, and skipping
the second step. This is particularly valuable if a significant amount of your data consists of
multi-line events.”
Source: http://docs.splunk.com/Documentation/Splunk/6.0.3/Data/Indexmulti-lineevents
Bottom line: In order to be fast and efficient, we want to be clever with our LINE_BREAKER
regex so we can avoid relying on “SHOULD_LINEMERGE” capabilities.
14 www.fireeye.com
Fortunately, we have created a regular expression that will act as a universal FireEye JSON
parser. Perform the following steps to apply our universal parser:
Step 1) Create the following file if it does not exist:
$SPLUNK_HOME/etc/system/local/props.conf
Step 2) Add the following contents:
# Universal Handler for FireEye JSON notifications (pre and post FireEye OS 7.1)
[fe_json] SHOULD_LINEMERGE = false
LINE_BREAKER = ([\r\n]+)(^\{.*\}$)
The regex above states that one or more carriage returns and line feeds can exist followed by an
event that starts with ‘{‘ and ends with ‘}’ with anything in between.
Step 3) Restart splunkd:
$SPLUNK_HOME/bin/splunk restart splunkd
After splunkd is restarted, all FireEye events sent to Splunk with a sourcetype of fe_json will
be properly parsed as shown below:
Figure 8: After applying a custom sourcetype, both the pre and post 7.1 FireEye JSON notifications parse correctly
15 www.fireeye.com
Now that we have whole events, regardless of the FireEye OS version, let’s look at carving the
data. In order to replicate the FireEye dashboard using JSON, we need certain fields to map
properly.
The JSON fields map as follows:
FireEye Field
Type
ID
File Type
Malware
Severity
Time (UTC)
Source IP
Target IP
MD5
URL (malware callback, domain
match, malware object)
URL (web infection)
Location
Splunk Field
alert.name
alert.id
alert.explanation.malware-detected.malware.type
alert.explanation.malware-detected.malware.name
alert.severity
alert.occurred
alert.src.ip
alert.dst.ip
alert.explanation.malware-detected.malware.md5sum
alert.explanation.cnc-services.cnc-service{}.address
alert.explanation.cnc-services.cnc-service.address
Not Passed
The fields above will provide what is necessary to replicate the FireEye dashboard. However, in
our introductory article we extended our FireEye dashboard to include some other useful fields.
The other useful JSON fields map as follows:
FireEye Field
Action taken
Protocol
Source port
Destination port
FireEye alert URL
16 www.fireeye.com
Splunk Field
alert.action (may indicate blocked)
alert.explanation.protocol
alert.src.port
alert.dst.port
alert.alert-url (useful for linking to FE event)
Now that we know all of these fields and what they map to in Splunk, we can once again
replicate the FireEye dashboards using JSON (via HTTP POST) instead of using syslog as we did
in our introductory guide. The final dashboard using JSON will be provided at the end of the
article in the Appendix section. For a quick Splunk tutorial on carving incoming data, see our
introductory FireEye/Splunk paper for the following topics which will not be repeated in this
guide:
• How to Replicate a FireEye Dashboard
-- Simple Searches
-- Piping Search Results
-- Using Regular Expressions
-- Using Conditionals
• If Statement
• Case Statement
-- Sorting Searches
-- Renaming the Columns
-- Save As Dashboard Panel
• Time Frames
17 www.fireeye.com
Parsing Other Formats
We mentioned earlier that FireEye is flexible in its notification output formats because it
supports sending the following formats via HTTP POST:
Text – Normal
JSON – Normal
XML – Normal
Text – Concise
JSON – Concise
XML – Concise
Text – Extended
JSON – Extended
XML – Extended
After experimenting with the formats, it appears that extended XML may also be a robust
alternative format to send to Splunk (via HTTP POST) due to its verbosity and structure. We
will briefly explore this option in this paper, but we recommend sticking with the extended
JSON solution we have outlined. As we will learn further down, there are still some challenges
to overcome with XML. These points will not be covered in this paper; however, one possible
solution is present in the latest FireEye App for Splunk Enterprise.
Experimenting with XML
If you too want to experiment with XML, we have to first change the FireEye notification format
to XML. This is a pretty easy change in the FireEye device. This is done by going to “Settings”,
“Notifications”, and then clicking “HTTP”. FireEye provides the ability to change the default
format for all of the HTTP servers or the default can be overridden with a per server entry.
Here, we will configure a per server entry that will apply for this Splunk server only. We also
recommend changing the sourcetype to read fe_xml instead fe_json
New server URL: https://<SplunkAD.DR.ESS>:<PORT>/services/receivers/
simple?host=<FireEyeAddress>&s ource=wmps&sourcetype=fe_xml
18 www.fireeye.com
Remember to click the “Update” button when finished. Finally, fire off a test event so there is
XML data to look at in Splunk.
Figure 9: Changing the FireEye appliance to use XML for Splunk event notification
We can inspect an XML field with the following Splunk search: “sourcetype=fe_xml”
XML has the same issue that JSON experienced. FireEye OS 7.1 and later uses “pretty print” to
display the event notification over multiple lines. Compare the difference in the examples below.
19 www.fireeye.com
Single Line XML
A typical single line XML (pre FE OS 7.1) event appears similar to the following:
<?xml
version="1.0"
encoding="utf-8"?><alerts
appliance="fireeye- wmps.local" msg="extended" product="Web MPS"
version="7.0.2.156588" xmlns="http://www.fireeye.com/alert/2011/
AlertSchema"
xmlns:xsi="http:// www.w3.org/2001/
XMLSchema-instance" xsi:schemaLocation="http://www. fireeye.
com/alert/2011/AlertSchema
FireEyeAlert.xsd"><alert
id="691256" name="malware-object" severity="majr"><explanation
analysis="binary" protocol="tcp"><malware-detected><malware
name="FireEye-TestEvent- SIG"><downloaded-at>2014-04-01T11:50:59Z</
downloaded-at><md5sum>d41d8cd9 8f00b204e9800998ecf8427e</
md5sum><profile>winxp-sp2-rp</profile><executed- at>2014-0401T11:50:59Z</executed-at><application>explorer</ application></
malware></malware-detected><cnc-services><cnc-service port="200"
protocol="tcp"><address>FireEye-TestEvent.example. com</
address><channel>FireEye-TestEvent Channel 1</channel></cncservice><cnc-service port="201" protocol="tcp"><address>127.0.0.100</
address><channel>cncs
2
channel
fields</
channel></cnc-service></cnc- services><service>FireEye-TestEvent
EA Service</service></explanation><src vlan="0"><ip>169.250.0.1</
ip><host>NA-testing.fe-notify-examples.com</
host><port>10</port><mac>XX:XX:XX:XX:XX:XX</mac></
src><dst><ip>127.0.0.20</ ip><mac>XX:XX:XX:XX:XX:XX</mac><port>20</
port></dst><occurred>2014-04- 01T11:50:57Z</occurred><alerturl>https://fireeye-wmps.local/event_stream/ events_for_bot?ma_
id=691256</alert-url><action>notified</action></alert></ alerts>
20 www.fireeye.com
Multiline XML
A typical multiline XML (FE OS 7.1 and later) event looks like the following:
<?xml version="1.0" encoding="utf-8"?>
<alerts appliance="WebMPS.localdomain" msg="extended" product="Web
MPS" version="7.1.0.180577" xmlns="http://www.fireeye.com/alert/2013/
AlertSchema"
xmlns:xsi="http://www. w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.fireeye.com/ alert/2013/AlertSchema
FireEyeAlert.xsd">
<alert id="26" name="infection-match" severity="minr">
<explanation analysis="content" protocol="tcp">
<malware-detected>
<malware name="FireEye-TestEvent-SIG-IM" sid="30"
stype="bot-command"/>
</malware-detected>
</explanation>
<src vlan="0">
<ip>169.250.0.1</ip>
<host>IM-testing.fe-notify-examples.com</host>
<port>10</port>
--SNIP--
21 www.fireeye.com
Universal Parser
To remedy this issue, we have once again created a regular expression that will act as a universal
FireEye parser—but this time for XML events. Perform the following steps:
Step 1) Create the following file if it does not exist:
$SPLUNK_HOME/etc/system/local/props.conf
Step 2) Add the following contents (below the fe_json if desired):
# Universal Handler for FireEye JSON
FireEye OS 7.1)
notifications (pre and post
[fe_json] SHOULD_LINEMERGE = false
LINE_BREAKER = ([\r\n]+)(^\{.*\}$)
# Universal Handler for FireEye XML notifications (pre and post
FireEye OS 7.1)
[fe_xml]
SHOULD_LINEMERGE = false
LINE_BREAKER
=
([\r\n]+)(^\<\?xml.*\<\/alerts\>$)
Step 3) Restart splunkd:
$SPLUNK_HOME/bin/splunk restart splunkd
Send another test event and observe that we have whole events—regardless of the FireEye OS
version.
After clicking on the arrow to expand the event, notice that Splunk attempts to extract data into
fields, but is not able to extract all of the fields. There are a couple of options at this point, but in
this paper we will try to pipe our search through the xmlkv command.
22 www.fireeye.com
According to Splunk, the xmlkv command “extracts xml key-value pairs”. The description is as
follows:
“Finds key value pairs of the form <foo>bar</foo> where foo is the key and bar is the value
from the _raw key.”
Using the included xmlkv command, let’s see what fields Splunk is able to parse:
The XML fields map as follows:
FireEye Field
Type
ID
File Type
Malware
Severity
Time (UTC)
Source IP
Target IP
MD5
URL (malware callback, domain
match, malware object)
URL (web infection)
Location
Splunk Field
name
id
type
Not parsed with xmlkv (need regex)
severity
occurred
Not parsed with xmlkv (need regex)
ip
md5sum
address
Not parsed with xmlkv (need regex)
Not passed
The other useful XML fields map as follows:
FireEye Field
Action taken
Protocol
Source port
Destination port
FireEye alert URL
23 www.fireeye.com
Splunk Field
action (may indicate blocked)
Not parsed with xmlkv (need regex)
Not parsed with xmlkv (need regex)
port
alert-url (useful for linking to FE event)
Why are some of these fields not parsed via xmlkv when they were parsed in JSON? The data
is obviously present in the raw packet. We identified the issue below:
--SNIP-<src vlan="0">
<ip>169.250.0.1</ip>
<host>NA-testing.fe-notify-examples.com</host>
<port>10</port>
<mac>XX:XX:XX:XX:XX:XX</mac>
</src>
<dst>
<ip>127.0.0.20</ip>
<mac>XX:XX:XX:XX:XX:XX</mac>
<port>20</port>
</dst>
--SNIP—
Notice that in both sections, the IP is identified by the <ip> tag. The xmlkv command will only
recognize the last instance because it appears to overwrite all prior tags with the same name.
The same issue occurs with the <mac> and <port> tags.
The reason for this is due to a limitation in the xmlkv parser found here:
$SPLUNK_HOME/etc/apps/search/bin/xmlkv.py
The code snippet below overwrites previous keys with the latest value:
for kvpair in XML_KV_RE.findall(rawOut):
r[kvpair[0]] = kvpair[1]
Summary of Differences
It appears that FireEye sends comparable data with either format (JSON or XML). However,
the current add-on xml parser in Splunk does not handle repeated tags. FireEye’s XML requires
some custom parsing which will be covered in a later paper, but is currently used in the most
recent FireApp for Splunk Enterprise App.
Bottom line: Pick the format that makes the most sense for your organization.
24 www.fireeye.com
Creating Apps
Now that you have the data to start creating your dashboard, you may want to first separate it
into its own Splunk App. This can be achieved manually or by using the Splunk App Builder. The
easiest way to create an app is to follow the steps below:
Log into Splunk Web as an admin and navigate to Apps > Manage Apps.
1. Click Create app.
2. Fill in the following data:
-- Name: MyFireEyeApp
-- Folder Name: myfireeyeapp
-- Version: 1
-- Visible: Yes
-- Author: <Your name>
-- Template: barebones
By default, none of the supporting directories are created without first creating a dashboard in
the app. If you don’t already have a dashboard in mind that you will move to this app, you will
need to create a quick dummy dashboard so you can practice customizing your app.
To create a dummy (empty) dashboard, use the following steps:
• Click “Apps” -> Select our newly-created FireEye app
• Click the “Dashboards” link
• Click the “Create New” button
• Fill in the data
• Click the “Create Dashboard” button
25 www.fireeye.com
Moving a Dashboard
If you have already completed a dashboard (maybe using our prior guide), you can move it to the
app we just created. It is as easy as copy and paste.
1. Go to your current dashboard
2. Click “Edit” -> “Edit Source”
3. Highlight and copy all of the code in the text box
4. Go to your new FireEye App -> Dashboard
5. Create Dashboard
6. Fill in the data and click the “Create Dashboard” button
7. Enter the new dashboard
8. Click “Edit” -> “Edit Source”
9. Click in the code box and right click -> paste
10.Save the new dashboard
Customizing an App
Now that we have an app and a dashboard, it is time to customize. We will demonstrate this by
changing the colors of the navigation bars and icons of the app. This next part requires a little
under-the-hood work, but we will walk you through it. We need access to the Splunk server’s
underlying OS and directories. If you are not the administrator of the server, you may need their
assistance in creating or copying the required files.
App Navigation Colors
Notice that the colors of the FireEye app are still “Splunk green”, but this too is editable. For
example, look at the before and after screenshots below:
Before:
Figure 10: App color is Splunk green
26 www.fireeye.com
Figure 11: App navigation is Splunk green
After:
Figure 12: Custom FireEye appliance dark blue
Figure 13: Custom FireEye appliance blue
This customization is possible by editing the following file:
$SPLUNK_HOME/etc/apps/fireeye/local/data/ui/nav/default.xml
Default contents:
<nav search_view="search" color="#65A637">
<view name="search" default='true' />
<view name="data_models" />
<view name="reports" />
<view name="alerts" />
<view name="dashboards" />
</nav>
This file is currently controlling two aspects of the dashboard:
1. The default navigation links (Search, Pivot, Reports, Alerts, Dashboards)
2. The color of the navigation bars - Splunk green color is indicated above by: #65A637
We will change the color to match the dark blue in the FireEye 7.1 appliance. Using the
following hex code, we can get a close color match: #21232E
After color change:
<nav search_view="search" color="#21232E">
<view name="search" default='true' />
<view name="data_models" />
<view name="reports" />
<view name="alerts" />
<view name="dashboards" />
</nav>
Remember to restart splunkd when finished making changes:
$SPLUNK_HOME/bin/splunk restart splunkd
27 www.fireeye.com
App Icons
It is subtle at first, but some may notice that the Apps dropdown and Apps Launcher are missing
icons. Since we just created the app, Splunk has no default icons present. For example, look at
the before and after screenshots below:
Before:
Figure 14: Our newly created app is missing icons
Figure 15: App logo is just text
After:
Figure 16: Custom FireEye Icons
28 www.fireeye.com
Figure 17: Custom FireEye Log
For us to add app icons, they first need to be created, appropriately named, and added to a
specific directory for Splunk to properly populate the dashboard. The directory and filenames
are listed below:
Splunk 6.0 Directory and files:
Larger main app icon:
$SPLUNK_HOME/etc/apps/<app_name>/static/appIcon.png
$SPLUNK_HOME/etc/apps/<app_name>/ static/appIcon_2x.png
Smaller icon in the Apps dropdown:
$SPLUNK_HOME/etc/apps/<app_name>/static/appIconAlt.png
$SPLUNK_HOME/etc/apps/<app_name>/static/appIconAlt_2x.png
Application banner logo (right hand side of app):
$SPLUNK_HOME/etc/apps/<app_name>/static/appLogo.png
$SPLUNK_HOME/etc/apps/<app_name>/static/appLogo_2x.png
Splunk 5.0 Directory and files (useful for backward compatibility):
Larger main app icon:
$SPLUNK_HOME/etc/apps/<app_name>/appserver/static/appIcon.png
$SPLUNK_HOME/etc/apps/<app_name>/appserver/static/appIcon_2x.png
Smaller icon in the Apps dropdown:
$SPLUNK_HOME/etc/apps/<app_name>/appserver/static/appIconAlt.png
$SPLUNK_HOME/etc/apps/<app_name>/appserver/static/appIconAlt_2x.png
Application banner logo (right hand side of app):
$SPLUNK_HOME/etc/apps/<app_name>/appserver/static/appLogo.png
$SPLUNK_HOME/etc/apps/<app_name>/appserver/static/appLogo_2x.png
Pro-tips:
• Images are at least 165 pixels to provide a crisp icon, but resized by Splunk based on the
name
• All images should be transparent to account for mouseover color changes
• Hard refresh the screen after populating the directory with the icons. Most browsers support
a hard refresh by using Ctrl + F5
29 www.fireeye.com
Dashboard Details
Now that we have navigation colors and application icons, let’s put some finishing touches on
the appearance of the dashboards. We can customize just about any portion of the dashboard
using cascading style sheets (CSS)—even minor details such as the font size, 3D effect, and parts
of the dashboard we could not modify using other configuration files.
For example, look at the before and after screenshots below:
Before:
Figure 18: The standard dashboard colors
After:
Figure 19: Our customized dashboard
30 www.fireeye.com
This detailed customization can be done in three easy steps. First, create a custom cascading
style sheet (CSS). Then we will reference that from the simple XML in our dashboard. Finally, we
will restart the splunkweb service. Follow the steps below to complete this activity:
1) Create a new CSS file called custom.css with the content below in the following location:
$SPLUNK_HOME/etc/apps/<app name>/appserver/static/
If our app name from the above example was used then the path will be:
$SPLUNK_HOME/etc/apps/myfireeyeapp/appserver/static/
custom.css:
/* Set the background color of all of the nav bars to match the
FireEye dashboard background color */
.footer, .header, .app-bar, .nav, .nav-pills, .navbar-inner,
a.dropdown toggle{
background: #21232E !important;
}
/* Set the color of the hyperlink text in our dashboard to white for
readability. Add 3-D effect with shadows */
.app-bar .nav-pills > li > a, .nav-footer > li > a {
#color:#D12131 !important;
color:white !important;
text-shadow: -1px 0px black, 0px 1px black, 1px
0px black, 0px -1px black;
font-size:14px !important;
}
/* If the FireEye logo (appLogo.png or appLogoWhite.png) does not
exist the text will be the correct size and color */
div.app-name {
color:#D12131 !important;
text-shadow: -1px 0px black, 0px 1px black, 1px
0px black, 0px -1px black;
font-size:26px !important;
}
31 www.fireeye.com
2) Edit the dummy or copied dashboard source (Edit -> Edit source) and change:
<form> to:
<form stylesheet="custom.css">
- or <dashboard> to:
<dashboard stylesheet="custom.css">
3) From the command line of the Splunk server restart the splunkweb service:
$SPLUNK_HOME/bin/splunk restart splunkweb
32 www.fireeye.com
Sample FireEye Dashboards
Now that we have walked through the process of sending data to Splunk, creating an app, and
customizing the appearance, we will provide some dashboards that we have put together.
Note: All of these queries use sourcetype=fe_json; if the sourcetype name was modified, please
change the queries below as well.
To add these dashboard panels to the blank FireEye dashboard, perform the following actions:
• Copy and paste the search string into the Splunk search box
• Click the “Save As” button and select “Dashboard Panel”
• Select “Existing” Dashboard
• Select our FireEye dashboard and give the panel a title (ex: Alerts, Callback Activity, etc. )
• Click “Save”
NX (web MPS)
The most useful chart in the FireEye dashboard is used to look at the raw events. This
dashboard is replicated below.
Alerts -> Alerts:
Note: In the eval statement, all JSON fields must be referred to using single quotes (‘). This is
most likely needed because the period character "." is normally used for string appends.
sourcetype=fe_json | eval UrlHash=case ('alert.name'=="malwareobject",'alert.explanation.malware-detected.malware.md5sum', 'alert.
name'=="web-infection", 'alert.explanation.malware-detected.malware{}.
objurl', 'alert.name'=="malware-callback" OR 'alert.name'=="domainmatch",'alert.explanation.cnc-services.cnc-service.address')| sort
-occurred | table alert.name, alert.id, alert.explanation.malwaredetected. malware.name, alert.severity, alert.occurred, alert.
explanation.protocol, alert.src.ip, alert.src.port, alert.dst.ip,
alert.dst.port, UrlHash | rename alert.name AS Type, alert.id AS ID,
alert.explanation.malware-detected.malware.name AS Malware, alert.
severity AS Severity, alert. occurred AS Occurred, alert.explanation.
protocol AS Protocol, alert.src. ip AS "Source IP", alert.src.port AS
"Source Port", alert.dst.ip AS "Target IP", alert.dst.port AS "Target
Port", UrlHash AS "URL/Md5sum"
33 www.fireeye.com
Notice that the Malware name for a web-infection event is missing:
This is because the correct value was stored in an array:
The fix for this issue requires parsing via custom regex and will be covered in a more advanced
paper.
Alerts -> Callback Activity:
sourcetype=fe_json "alert.name"="malware-callback" | stats
count(alert. explanation.cnc-services.cnc-service.address) as
"Events", distinct_ count(alert.src.ip) as "Hosts", max(alert.
occurred) as "Last Seen"
by alert.explanation.cnc-services.cnc-service.address | table alert.
explanation.cnc-services.cnc-service.address, locations, Events,
Hosts, "Last Seen" | rename alert.explanation.cnc-services.cncservice.address as "C&C Server", locations as "Locations" | sort
–"Last Seen"
Time Frames:
Our first guide illustrated how to add a time range picker—this is worth mentioning here again.
Click the “Edit” drop down. Click “Edit Panels”. Click “Add Time Range Picker”. Select Last 24
Hours. Click the “Done” button.
Figure 21: Adding a time range picker to our dashboard
34 www.fireeye.com
Pro-tip: If for some reason, your time frame button is not working as expected (ours did not by
default), you have overridden the time picker in your search. Here is how to fix it:
Go to your dashboard. Click the “Edit” drop down. Click “Edit Panels”. Click the magnifying
glass drop down, and select “Edit Search String”. In the “Time Range Scope” section, select
the “Dashboard” button and click save. Now the “Time Range Picker” button will function as
expected.
Figure 22: Setting the Time Range Scope to use the dashboard instead of
the search string time frame
35 www.fireeye.com
Panels to Enhance Visibility
Now that you have a Splunk dashboard that replicates the FireEye Dashboard, let’s go further
by adding more panels that will enhance the network defender’s visibility into attacks. Splunk
has many visualization features that allow users to build charts and graphs for trending and
analytics.
NX (web MPS)
We can take some of the fields that we exposed in the FireEye dashboard above and create
pie charts to summarize key data points. This can help gauge if an organization is experiencing
an increase or lull in attacks, as well as identify trends in malware and Command and Control
(C2) ports. Each chart below is optional and may depend on the organization or security team’s
preferences.
Severity Pie Chart:
sourcetype=fe_json | chart count by alert.severity
Select pie chart
After typing in the search above, select the visualization tab, then pie chart. Click the “Save As”
button, select “Dashboard Panel”, click the “Existing” Button. Select the FireEye Dashboard and
provide a title of “Severity”. Select “View in Dashboard” to look at your new dashboard. Now,
let’s move the graph to the top by clicking “Edit” -> “Edit Panels”. Drag the pie chart to the top
of the screen. Click “Done” when finished. We will follow this same procedure to add the rest of
the charts.
Figure 23: Current dashboard
after adding severity pie chart.
36 www.fireeye.com
Malware Pie Chart:
sourcetype=fe_json | chart count by alert.explanation.malwaredetected. malware.name
Select pie chart
Top 20 Most Active Source IPs:
sourcetype=fe_json | top limit=20 alert.src.ip
Select pie chart
Top 20 Most Active Target IPs:
sourcetype=fe_json | top limit=20 alert.dst.ip
Select pie chart
Top 20 Most Active Destination Ports:
sourcetype=fe_json | top limit=20 alert.dst.port
Select pie chart
Most Active Sensors:
sourcetype=fe_json | chart count by appliance
Select pie chart
After arranging all of the charts, the dashboard should look similar to the following:
Figure 24: Current dashboard after adding all of the charts
37 www.fireeye.com
Adding Forms (Filters)
A Splunk form allows users to supply search terms within the dashboard to assist in carving
data. This user interaction can take place via text boxes, dropdown menus, radio buttons, or
search terms. We will illustrate how to add a wild card to one search below as an example, but
we will also provide a Simple XML Dashboard in the appendix that will apply a wildcard search
to the entire dashboard. Continue on to see how this works.
Adding forms can be broken down into two steps:
1. Add tokens to search strings
2. Add user input forms
38 www.fireeye.com
Adding Tokens to Search Strings
Tokens are defined by using dollar signs ‘$’ around variable names. Let’s use our Alerts
dashboard search as an example. Note the change in bold red font to compare the before and
after.
Before:
sourcetype=fe_json
| eval
UrlHash=case
('alert.
name'=="malware-object",'alert.explanation.malware-detected.malware.
md5sum', 'alert.name'=="web-infection", 'alert.explanation.malwaredetected.malware{}.objurl', 'alert.name'=="malware-callback" OR
'alert.name'=="domain-match",'alert.explanation.cnc-services.cncservice.address')| sort-occurred | table alert.name, alert.id, alert.
explanation.malware-detected.
malware.name, alert.severity, alert.occurred, alert.explanation.
protocol, alert.src.ip, alert.src.port, alert.dst.ip, alert.dst.
port, UrlHash | rename alert.name AS Type, alert.id AS ID, alert.
explanation.malware-detected.malware.name AS Malware, alert.severity
AS Severity, alert.occurred AS Occurred, alert.explanation.protocol
AS Protocol, alert.src.ip AS "Source IP", alert.src.port AS "Source
Port", alert.dst.ip AS "Target IP", alert.dst.port AS "Target Port",
UrlHash AS "URL/Md5sum
After:
sourcetype=fe_json $wild$ | eval
UrlHash=case
('alert.
name'=="malware- object",'alert.explanation.malware-detected.malware.
md5sum', 'alert.name'=="web-infection", 'alert.explanation.malwaredetected.malware{}.objurl', 'alert.name'=="malware-callback" OR
'alert.name'=="domain- match",'alert.explanation.cnc-services.cncservice.address')| sort-occurred | table alert.name, alert.id, alert.
explanation.malware-detected. malware.name, alert.severity, alert.
occurred, alert.explanation.protocol, alert.src.ip, alert.src.port,
alert.dst.ip, alert.dst.port, UrlHash | rename alert.name AS Type,
alert.id AS ID, alert.explanation.malware-detected.malware.name AS
Malware, alert.severity AS Severity, alert.occurred AS Occurred,
alert.explanation.protocol AS Protocol, alert.src.
ip AS "Source IP", alert.src.port AS "Source Port", alert.dst.ip AS
"Target IP", alert.dst.port AS "Target Port", UrlHash AS "URL/Md5sum
39 www.fireeye.com
Adding User Input Forms
If you had a time range picker on your previous dashboard, you should remove it now. We will
add it back in manually which will prevent some minor annoyances. We will add this wildcard
search field above the very first row which will place it at the top of our dashboard. As a
reminder, we can edit the XML by clicking on the “Edit” button and selecting “Edit Source”.
Before:
<form>
<label>FireEye</label>
<row>
<chart>
After:
<form>
<label>FireEye</label>
<!-- Add time range picker -->
<fieldset autoRun="True">
<input type="time" searchWhenChanged="true">
<default>
<earliestTime>-24h@h</earliestTime>
<latestTime>now</latestTime>
</default>
</input>
<!-- Add Wildcard Search (Form) -->
<input type="text" token="wild">
<label>Search</label>
<default>*</default>
<suffix/>
</input>
</fieldset>
<row>
40 www.fireeye.com
Figure 25: All of the combined pieces used to create the user input form
Pro-tip: Be sure to add the $wild$ token to all search strings for all panels on the dashboard
(charts, tables, graphs, etc).
To operate the search, just change the Search field at the top of the page and search for
whatever term is desired. Be sure to click the “Search” button when finished. To clear a previous
search, enter an asterisk in the search field and click the “Search” button again.
41 www.fireeye.com
Figure 26: Demonstrating the use of the wildcard search
For more information see the following Splunk doc:
http://docs.splunk.com/Documentation/Splunk/6.0.2/Viz/Buildandeditforms
42 www.fireeye.com
GeoIP Maps
Everyone loves a map with pretty dots on it. But how about a map with pie charts overlaid with
malware distribution? This is possible using an easy two-step process outlined below:
1. Generate a search with latitude and longitude coordinates
2. Editing the simple XML, change the <chart> or <table> tag to <map>
In our example below we will track where the attacks are originating, so we look at the
destination IP address. However, it is possible to change the IP address to whatever suits your
needs. Some may want to know which hosts are infected; thus they would map the source IP
instead. Keep in mind, though, that RFC 1918 addresses do not have geoIP data associated
with them.
iplocation
No Internet access is required to utilize Splunk’s iplocation command, which extracts location
information using 3rd party geoIP databases.
Syntax:
<search> | iplocation <field of interest>
JSON:
sourcetype=fe_json | iplocation alert.dst.ip
Source: http://docs.splunk.com/Documentation/Splunk/6.0.2/SearchReference/Iplocation
geostats
Now that we have the lat/long information from the iplocation command, we will feed that
data into the geostats command, which according to Splunk:
“Generate[s] statistics which are clustered into geographical bins to be rendered on a world
map.”
Source: http://docs.splunk.com/Documentation/Splunk/6.0.2/SearchReference/Geostats
Our search string will look like the following:
sourcetype=fe_json | iplocation alert.dst.ip | geostats
latfield=lat, longfield=lon count by alert.explanation.malwaredetected.malware.name
43 www.fireeye.com
After entering the data above in the search field, save it to the FireEye dashboard by selecting
“Save As -> Dashboard Panel”. Select existing, choose the FireEye dashboard and call this GeoIP.
When this new panel shows up on the dashboard, move it to the top by selecting “Edit -> Edit
panels” and dragging the panel to the top. Now, edit the source by clicking “Edit Source”. Edit
the simple XML and change the <chart> tag to <map>.
Figure 27: Changing the table tag to map
Once the tags are changed to map and the dashboard is saved, the GeoIP map will appear at the
top of the dashboard. Please note that FireEye “Test-fire” events use RFC-1918 addresses and
will not generate information on the map.
44 www.fireeye.com
Figure 28: A GeoIP map at the top of our dashboard.
If you are using CEF or CSV via syslog from our introductory paper, the CSV search string is
provided below:
CSV:
CSV:\0:\FireEye | iplocation dst | geostats latfield=lat, longfield=lon count by sname
45 www.fireeye.com
Figure 29: A GeoIP location map added to our dashboard maps the attacker IPs along with the threat statistics
Pro-tip: We have experienced instances in which the time range picker has caused the geoIP
to stop functioning. The best solution we found was to remove the time range picker, add the
geoIP, and then add in the time range picker last. In our final Simple XML dashboard that we
provide, we will have both geoIP and a functioning time range picker.
46 www.fireeye.com
Adding Drilldowns
Fortunately, when a user clicks any of the fields in our newly-created dashboard, by default
Splunk will pivot around the query that finds the event of interest. Unfortunately, the basic
default drilldown behavior is to show the raw data packet—which may not always be pretty.
The upside is that this behavior can be overridden by using custom drilldowns. One option is
to use <drilldown> tags. However, we will go a step beyond this by using JavaScript to control
extracted fields and CSS to control visibility of a detail pane.
Requirements
Unless we are able to embed our JavaScript and CSS into the Splunk Simple XML page, we will
need access to the Splunk server’s underlying OS. If you are not the administrator of the server,
you may need the Splunk administrator’s assistance in creating or copying the files. Either way,
we need to know where to put the files on the Splunk server so they can be referenced.
Supporting File Location:
Splunk dashboards can reference CSS and JavaScript files if they are placed in the following
directory:
$SPLUNK_HOME/etc/apps/<app_name>/appserver/static/
For example, our Splunk dashboard was created in the FireEye App directory, so its path will be:
$SPLUNK_HOME/etc/apps/myfireeyeapp/appserver/static/
We will provide example files in the section called: “Drilldown by Event ID”, but first check out
the following pro-tip.
Pro-tip: After creating new files in the static directory, remember to restart splunkweb:
$SPLUNK_HOME/bin/splunk restart splunkweb
Simple modifications of files that already exist will not require a splunkweb restart. However,
they will require a browser hard refresh to make sure a locally cached version of the JavaScript
or CSS file is not used. Most browsers support a hard refresh by using Ctrl + F5.
47 www.fireeye.com
How to Import Support Files:
According to Splunk: “Use the script and stylesheet attributes to <dashboard> or <form>
tags to import a JavaScript or CSS file from the default location for an app. You can also
reference script and CSS files from other apps.”
For example:
Import files from the same app
<dashboard script="myScript.js" stylesheet="myStyles.css">
. . .
</dashboard>
Source: http://docs.splunk.com/Documentation/Splunk/6.0.2/Viz/OverviewofSimplifiedXML
Drilldown by Event ID
To demonstrate how this works, we will use a small demo page showing our FireEye alerts. This
will require some Simple XML modification and two supporting files on the server.
Simple XML:
<form script="inpage_drilldown_form.js" stylesheet="custom.css">
<label>Drilldown demo</label>
<fieldset autoRun="True" submitButton="false">
<!-- Add Time range picker -->
<input type="time" searchWhenChanged="true">
<default>
<earliestTime>-24h@h</earliestTime>
<latestTime>now</latestTime>
</default>
</input>
<!-- Add Wildcard Search (Form) -->
<input type="text" token="wild">
<label>Search</label>
<default>*</default>
<suffix/>
</input>
<!-- Input to store the drilldown value. Hidden using
javascript when the dashboard is loaded. -->
<input type="text" token="ID" searchWhenChanged="true"/>
</fieldset>
<row>
48 www.fireeye.com
<table id="master">
<title>Alerts</title>
<searchString>sourcetype=fe_json
$wild$
| eval
UrlHash=case
('alert. name'=="malware-object",'alert.
explanation.malware-detected.malware. md5sum', 'alert.
name'=="web-infection", 'alert.explanation.malware- detected.
malware{}.objurl', 'alert.name'=="malware-callback" OR
'alert. name'=="domain-match",'alert.explanation.cncservices.cnc-service. address')| sort -occurred | table
alert.name, alert.id, alert.explanation. malware-detected.
malware.name, alert.severity, alert.occurred, alert.
explanation.protocol, alert.src.ip, alert.src.port, alert.
dst.ip, alert. dst.port, UrlHash | rename alert.name AS Type,
alert.id AS ID, alert. explanation.malware-detected.malware.
name AS Malware, alert.severity
AS Severity, alert.occurred AS Occurred, alert.explanation.
protocol AS
Protocol, alert.src.ip AS "Source IP", alert.src.port AS "Source
Port", alert.dst.ip AS "Target IP", alert.dst.port AS "Target
Port", UrlHash AS "URL/Md5sum"</searchString>
<earliestTime>-24h</earliestTime>
<latestTime>now</latestTime>
</table>
</row>
<row>
<table id="detail">
<title>Alert Detail: $ID$</title>
<searchTemplate>sourcetype=fe_json alert.id=$ID$ $wild$ |
table _raw, alert.alert-url</searchTemplate>
<earliestTime>-24h</earliestTime>
<latestTime>now</latestTime>
</table>
</row>
</form>
49 www.fireeye.com
Supporting files on the server:
inpage_drilldown_form.css
#field3 {
/* Hide all form fields
*/ display: none;
}
Since this is minor, we can add it to our previous custom.css:
/* Set the background color of all of the nav bars to match the
FireEye dashboard background color */
.footer, .header, .app-bar, .nav, .nav-pills, .navbar-inner,
a.dropdown- toggle {
background: #21232E !important;
}
/* Set the color of the hyperlink text in our
dashboard to white for readability.
Add 3-D effect with
shadows */
.app-bar .nav-pills > li > a, .nav-footer > li > a {
#color:#D12131 !important;
color:white !important;
text-shadow: -1px 0px black, 0px 1px black, 1px 0px black,
0px -1px black;
font-size:14px !important;
}
/* If the FireEye logo (appLogo.png or appLogoWhite.png) does
not exist the text will be the correct size and color
*/
div.app-name {
color:#D12131 !important;
text-shadow: -1px 0px black, 0px 1px black, 1px 0px black,
0px -1px black;
font-size:26px !important;
}
/* Hide the drilldown "Details" box when it is unpopulated */
#field3 {
/* Hide all form fields
*/ display: none;
}
50 www.fireeye.com
inpage_drilldown_form.js
require(['jquery','underscore','splunkjs/mvc','util/
console','splunkjs/mvc/ simplexml/ready!'], function($, _, mvc,
console){
// Get a reference to the dashboard
panels var
masterView
=
mvc.
Components.get('master'); var
detailView
=
mvc.Components.
get('detail');
var unsubmittedTokens
=
mvc.Components.
get('default'); var submittedTokens = mvc.
Components.get('submitted'); var urlTokens
=
mvc.Components.get('url');
if(!submittedTokens.has('ID'))
{
// if there's no value for the $sourcetype$ token yet,
hide the dashboard panel of the detail view
detailView.$el.parents('.dashboard-panel').hide();
}
submittedTokens.on('change:ID', function(){
// When the token changes...
if(!submittedTokens.get('ID'))
{
// ... hide the panel if the token is not defined
detailView.$el.parents('.dashboard-panel').hide();
} else {
// ... show the panel if the token has a value
detailView.$el.parents('.dashboard-panel').show();
}
});
masterView.on('click', function(e) {
e.preventDefault();
var newValue = e.data['row.ID'];
// Submit the value for the sourcetype field unsubmittedTokens.
set('form.ID', newValue); submittedTokens.set(unsubmittedTokens.
toJSON()); urlTokens.saveOnlyWithPrefix('form\\.',
unsubmittedTokens.toJSON(),
{
replaceState: false
});
});
});
51 www.fireeye.com
The behavior when first visiting the page shows no detail pane:
Figure 30: No events clicked yet, thus the detail pane is hidden from view
After the event is clicked, a detail pane can be seen below:
Figure 31: Detailed pane drilldown shown above
This event will be displayed until another event is clicked. The details pane can be hidden by
refreshing the page.
52 www.fireeye.com
Conclusion
Using a FireEye device, a free demo of Splunk, and Google, we were able to investigate the
different HTTP POST formats for replicating FireEye Dashboards in Splunk. In writing this guide,
we have discovered that there are many ways to tackle integrating these two devices because
FireEye provides robust event notification and Splunk is flexible when ingesting and presenting
these events. We are sharing this information in the hope that you will be inspired by seeing
even just a fraction of what is possible. Who knows, it may save you a little time as well. We
would love to hear your feedback, including sample FireEye dashboards and any pro-tips you
have for consuming and displaying data in Splunk.
53 www.fireeye.com
Troubleshooting
There are many methods that can be used to troubleshoot connection issues. Below is just one
example:
Using Curl
Using any Linux host, or Cygwin on Windows perform the following:
Step 1)
echo test > test.xml
Step 2)
curl -k -g --user <username>:<password> --data-binary @
test.xml "https://<splunkServer>:<port>/services/receivers/
simple?host=<SendingIP>&source= fe_test&sourcetype=fe_xml"
Ex:
curl -k
-g
--user fireeye:password
--data-binary @test.xml
"https://192.168.33.152:8089/services/receivers/simple?host=192.168.33
.152&source= fe_test&sourcetype=fe_xml"
Result:
You should see something similar to the following response from Splunk after issuing the
command above:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<results>
<result>
<field k="_index">
<value>
<text>default</text>
</value>
</field>
<field k="bytes">
<value>
<text>4</text>
</value>
</field>
<field k="host">
<value>
54 www.fireeye.com
<text>Source IP Address here</text>
</value>
</field>
<field k="source">
<value>
<text>fe_alert</text>
</value>
</field>
<field k="sourcetype">
<value>
<text>fe_xml</text>
</value>
</field>
</result>
</results>
</response>
Splunk Search:
After the data is successfully sent to Splunk, you should be able to search for it using the
following search term:
source=fe_test
You should see “test” as the message body because it was in the body of test.xml
55 www.fireeye.com
About the Author Tony Lee has more than ten years of
professional experience pursuing his passion in all areas of information
security. He is currently a Technical Director at Mandiant, a FireEye
Company, advancing many of the network penetration testing service
lines. His interests of late are kiosk hacking, post exploitation tactics, and
malware research. As an avid educator, Tony has instructed thousands of
students at many venues worldwide, including government, universities,
corporations, and conferences such as Black Hat. He takes every
opportunity to share knowledge as a contributing author to Hacking Exposed 7, frequent
blogger, and a lead instructor for a series of classes. He holds a Bachelor of Science degree in
computer engineering from Virginia Polytechnic Institute and State University and a Master of
Science degree in security informatics from The Johns Hopkins University.
Email: Tony.Lee -at- FireEye.com
Linked-in: http://www.linkedin.com/in/tonyleevt
Special Thanks
Dennis Hanzlik
Dan Dumond
Ian Ahl
Dave Pany
Karen Kukoda
Leianne Lamb
Brian Stoner
Gunpreet Singh
Kate Scott
About FireEye
FireEye has invented a purpose-built, virtual machine-based security platform that provides realtime threat protection to enterprises and governments worldwide against the next generation
of cyber attacks. These highly sophisticated cyber attacks easily circumvent traditional
signature-based defenses, such as next-generation firewalls, IPS, anti-virus, and gateways. The
FireEye Threat Prevention Platform provides real-time, dynamic threat protection without the
use of signatures to protect an organization across the primary threat vectors and across the
different stages of an attack life cycle. The core of the FireEye platform is a virtual execution
engine, complemented by dynamic threat intelligence, to identify and block cyber attacks in real
time. FireEye has over 2,500 customers across 65 countries, including over 150 of the Fortune
500.
FireEye, Inc. | 1440 McCarthy Blvd. Milpitas, CA 95035 | 408.321.6300 | 877.FIREEYE (347.3393) | [email protected] | www.fireeye.com
© 2014 FireEye, Inc. All rights reserved. FireEye is a registered trademark of
FireEye, Inc. All other brands, products, or service names are or may be trademarks
or service marks of their respective owners. SPT.CSS.EN-US.102014
Appendix A
Sample code to build a robust dashboard of maps, charts, forms, and detailed drilldown panels.
custom.css
/* Set the background color of all of the nav bars to match the
FireEye dashboard background color */
.footer, .header, .app-bar, .nav, .nav-pills, .navbar-inner,
a.dropdown- toggle {
background: #21232E !important;
}
/* Set the color of the hyperlink text in our dashboard to white for
readability. Add 3-D effect with shadows */
.app-bar .nav-pills > li > a, .nav-footer > li > a {
#color:#D12131 !important;
color:white !important;
text-shadow: -1px 0px black, 0px 1px black, 1px 0px black, 0px
-1px
black;
}
font-size:14px !important;
/* If the FireEye logo (appLogo.png or appLogoWhite.png) does not
exist the text will be the correct size and color */
div.app-name {
color:#D12131 !important;
text-shadow: -1px 0px black, 0px 1px black, 1px 0px black, 0px
-1px
black;
}
font-size:26px !important;
57 www.fireeye.com
/* Hide the drilldown "Details" box when it is unpopulated */
#field3 {
/* Hide all form fields */
display: none;
}
Simple XML:
<form script="inpage_drilldown_form.js" stylesheet="custom.css">
<label>FireEye JSON - With Drilldown and Filter</label>
<fieldset autoRun="True">
<input type="time" searchWhenChanged="true">
<default>
<earliestTime>-24h@h</earliestTime>
<latestTime>now</latestTime>
</default>
</input>
<!-- Add Wildcard Filter -->
<input type="text" token="wild">
<label>Search</label>
<default>*</default>
<suffix/>
</input>
<!-- Used for dropdown - Input field hidden using javascript. <div
id =
#field3 -->
<input type="text" token="ID" searchWhenChanged="true"/><!-Add time range picker -->
</fieldset>
<row>
<map>
<title>GeoIP Dest</title>
<searchString>sourcetype=fe_json $wild$ | iplocation alert.dst.ip
| geostats latfield=lat, longfield=lon count by alert.explanation.
malware- detected.malware.name</searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
</map>
</row>
<row>
<chart>
<title>Severity</title>
58 www.fireeye.com
<searchString>sourcetype=fe_json $wild$ | chart count by alert.
severity</searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">all</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.
labelStyle. overflowMode">ellipsisMiddle</
option>
<option name="charting.legend.placement">right</option>
</chart>
<chart>
<title>Malware</title>
<searchString>sourcetype=fe_json $wild$ | chart count by alert.
explanation.malware-detected.malware.name</searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">all</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.labelStyle.
overflowMode">ellipsisMiddle</option>
<option name="charting.legend.placement">right</option>
</chart>
<chart>
<title>Top 20 Source</title>
59 www.fireeye.com
<searchString>sourcetype=fe_json $wild$ | top limit=20 alert.
src.ip</ searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">all</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.labelStyle.
overflowMode">ellipsisMiddle</option>
<option name="charting.legend.placement">right</option>
</chart>
<chart>
<title>Top 20 Target</title>
<searchString>sourcetype=fe_json $wild$ | top limit=20 alert.
dst.ip</ searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">all</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.labelStyle.
overflowMode">ellipsisMiddle</option>
<option name="charting.legend.placement">right</option>
</chart>
<chart>
<title>Top 20 Dest Ports</title>
<searchString>sourcetype=fe_json $wild$ | top limit=20 alert.dst.
60 www.fireeye.com
port</searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">all</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.labelStyle.
overflowMode">ellipsisMiddle</option>
<option name="charting.legend.placement">right</option>
</chart>
<chart>
<title>Sensor</title>
<searchString>sourcetype=fe_json $wild$ | chart count by
appliance</ searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="charting.axisTitleX.visibility">visible</option>
<option name="charting.axisTitleY.visibility">visible</option>
<option name="charting.axisX.scale">linear</option>
<option name="charting.axisY.scale">linear</option>
<option name="charting.chart">pie</option>
<option name="charting.chart.nullValueMode">gaps</option>
<option name="charting.chart.sliceCollapsingThreshold">0.01</option>
<option name="charting.chart.stackMode">default</option>
<option name="charting.chart.style">shiny</option>
<option name="charting.drilldown">all</option>
<option name="charting.layout.splitSeries">0</option>
<option name="charting.legend.labelStyle.
overflowMode">ellipsisMiddle</option>
<option name="charting.legend.placement">right</option>
</chart>
</row>
<row>
<table id="master">
<title>Alerts</title>
61 www.fireeye.com
<searchString>sourcetype=fe_json
$wild$
| eval
UrlHash=case
('alert. name'=="malware-object",'alert.
explanation.malware-detected.malware. md5sum', 'alert.name'=="webinfection", 'alert.explanation.malware- detected.malware{}.
objurl', 'alert.name'=="malware-callback" OR 'alert. name'=="domainmatch",'alert.explanation.cnc-services.cnc-service. address')| sort
-occurred | table alert.name, alert.id, alert.explanation. malwaredetected.malware.name, alert.severity, alert.occurred, alert.src.
ip, alert.src.port, alert.dst.ip, alert.dst.port, UrlHash | rename
alert. name AS Type, alert.id AS ID, alert.explanation.malwaredetected.malware. name AS Malware, alert.severity AS Severity,
alert.occurred AS Occurred, alert.src.ip AS "Source IP", alert.src.
port AS "Source Port", alert.dst.ip
AS "Target IP", alert.dst.port AS "Target Port", UrlHash AS "URL/
Md5sum"</ searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="wrap">true</option>
<option name="rowNumbers">false</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">row</option>
<option name="count">10</option>
</table>
</row>
<row>
<table id="detail">
<title>Alert Detail: $ID$</title>
<searchString>sourcetype=fe_json alert.id=$ID$ $wild$ | table
_raw, alert.alert-url</searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="wrap">true</option>
<option name="rowNumbers">false</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">row</option>
<option name="count">10</option>
</table>
</row>
<row>
<table>
<title>Callbacks</title>
<searchString>sourcetype=fe_json "alert.name"="domain-match" $wild$
| stats
count(alert.explanation.cnc-services.cnc-service.address)
62 www.fireeye.com
as "Events", distinct_count(alert.src.ip) as "Hosts", max(alert.
occurred) as "Last Seen" by alert.explanation.cnc-services.cncservice.address | table alert.explanation.cnc-services.cnc-service.
address, alert.explanation.cnc- services.cnc-service.location,
Events, Hosts, "Last Seen" | rename alert. explanation.cnc-services.
cnc-service.address as "C&amp;C Server", alert. explanation.cncservices.cnc-service.location as "Locations" | sort –"Last Seen"</
searchString>
<earliestTime>$earliest$</earliestTime>
<latestTime>$latest$</latestTime>
<option name="wrap">true</option>
<option name="rowNumbers">false</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">row</option>
<option name="count">10</option>
</table>
</row>
</form>
63 www.fireeye.com