Skip to content

Commit

Permalink
New Version of Sigma2SplunkAlert
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick Bareiss authored and Patrick Bareiss committed Aug 11, 2019
1 parent f8fcba7 commit 48f3fd0
Show file tree
Hide file tree
Showing 36 changed files with 2,693 additions and 5 deletions.
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ The Sigma Hunting App for Splunk provides the following features:
- Store triggered detection rules in a dedicated index
- Enrichment of triggered detection rules with data from the [Mitre ATT&CK Matrix](https://attack.mitre.org/matrices/enterprise/)
- Providing powerfull dashboards for investigation: security posture, host investigator, APT investigator, lateral movement investigator
- Whitelist App to adapt the detection rules to your enviroment

### Update of Sigma Detection Rules
The Sigma detection rules can be updated from the Sigma Hunting App:
Expand Down Expand Up @@ -40,10 +39,6 @@ The APT investigator tries to identify, which threat actor is attacking you by u
The Lateral Movement Investigator uses the information of triggered alerts in combination with firewall data in order to find lateral movement. It identifies, if the same detection rule was triggered for two host and there was a network connection between them:
![](https://github.com/P4T12ICK/Sigma-Hunting-App/blob/master/pictures/sigma_hunting_app_lateral_movement_investigator.png)

### Sigma Hunting Whitelist App for Splunk
The Sigma Hunting Whitelist App contains the whitelist for your detection rules. That helps the SOC Analysts to tune the detection rules and define exceptions/whitelists:
![](https://github.com/P4T12ICK/Sigma-Hunting-App/blob/master/pictures/sigma_hunting_whitelist_app.png)


## Installation
Installation steps are described in detail in the [wiki](https://github.com/P4T12ICK/Sigma-Hunting-App/wiki/Installation-Sigma-Hunting-App).
Expand Down
Binary file removed Sigma_Hunting_APP/sigma_hunting_app.spl
Binary file not shown.
Binary file not shown.
4 changes: 4 additions & 0 deletions sigma_hunting_app/README/settings.conf.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[settings]
repository = <value>
folder = <value>
# This is the remote Sigma repository for your detection rules.
1 change: 1 addition & 0 deletions sigma_hunting_app/Sigma2SplunkAlert
Submodule Sigma2SplunkAlert added at 1fbfe6
21 changes: 21 additions & 0 deletions sigma_hunting_app/appserver/static/run_action.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require([
"jquery",
"splunkjs/mvc/searchmanager",
"splunkjs/mvc/simplexml/ready!"
], function(
$,
SearchManager
) {
var mysearch = new SearchManager({
id: "mysearch",
autostart: "false",
search: "| update"
});
$(".button1").on("click", function (){
var ok = confirm("Are you sure?");
if (ok){
mysearch.startSearch();
alert('Please restart Splunk or run debug/refresh to make changes effective! But wait 10min before doing it to ensure the script was finished.');
}
});
});
1 change: 1 addition & 0 deletions sigma_hunting_app/bin/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is where you put any scripts you want to add to this app.
68 changes: 68 additions & 0 deletions sigma_hunting_app/bin/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import splunk.admin as admin
import splunk.entity as en

class ConfigApp(admin.MConfigHandler):
'''
Set up supported arguments
'''
def setup(self):
if self.requestedAction == admin.ACTION_EDIT:
for arg in ['repository', 'folder']:
self.supportedArgs.addOptArg(arg)

'''
Read the initial values of the parameters from the custom file
myappsetup.conf, and write them to the setup page.
If the app has never been set up,
uses .../app_name/default/myappsetup.conf.
If app has been set up, looks at
.../local/myappsetup.conf first, then looks at
.../default/myappsetup.conf only if there is no value for a field in
.../local/myappsetup.conf
For boolean fields, may need to switch the true/false setting.
For text fields, if the conf file says None, set to the empty string.
'''

def handleList(self, confInfo):
confDict = self.readConf("settings")
if None != confDict:
for stanza, settings in confDict.items():
for key, val in settings.items():
if key in ['repository'] and val in [None, '']:
val = ''
if key in ['folder'] and val in [None, '']:
val = ''
confInfo[stanza].append(key, val)

'''
After user clicks Save on setup page, take updated parameters,
normalize them, and save them somewhere
'''
def handleEdit(self, confInfo):
name = self.callerArgs.id
args = self.callerArgs

if self.callerArgs.data['repository'][0] in [None, '']:
self.callerArgs.data['repository'][0] = ''

if self.callerArgs.data['folder'][0] in [None, '']:
self.callerArgs.data['folder'][0] = ''


'''
Since we are using a conf file to store parameters,
write them to the [setupentity] stanza
in app_name/local/myappsetup.conf
'''

self.writeConf('settings', 'settings', self.callerArgs.data)

# initialize the handler
admin.init(ConfigApp, admin.CONTEXT_NONE)



47 changes: 47 additions & 0 deletions sigma_hunting_app/bin/update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/sh
unset PYTHONPATH
unset LD_LIBRARY_PATH

if [ -z $SPLUNK_HOME ]; then
splunk_path='/opt/splunk'
else
splunk_path=$SPLUNK_HOME
fi


# look for config /local/settings.conf otherwise /default/settings.conf
repository=''
folder=''
FILE=$splunk_path/etc/apps/sigma_hunting_app/local/settings.conf

repository=$(cat $splunk_path/etc/apps/sigma_hunting_app/default/settings.conf | grep repository | cut -d ' ' -f3)
folder=$(cat $splunk_path/etc/apps/sigma_hunting_app/default/settings.conf | grep folder | cut -d ' ' -f3)

if [ -f $FILE ]; then
check_repository=$(cat $splunk_path/etc/apps/sigma_hunting_app/local/settings.conf | grep repository | cut -d ' ' -f3)
if ! [ -z $check_repository ]; then
repository=$check_repository
fi

check_folder=$(cat $splunk_path/etc/apps/sigma_hunting_app/local/settings.conf | grep folder | cut -d ' ' -f3)
if ! [ -z $check_folder ]; then
folder=$check_folder
fi
fi

cd $splunk_path/etc/apps/sigma_hunting_app/Sigma2SplunkAlert
rm -rf rules/*
cd rules
git clone $repository > /dev/null 2>&1
cd ..



if ! [ "${folder:-1}" == "/" ]; then
folder=$folder/
fi

./sigma2splunkalert --config config/config.yml --sigma-config sigma_config/splunk-all.yml rules/$folder > savedsearches.conf
cp savedsearches.conf ../default/savedsearches.conf


17 changes: 17 additions & 0 deletions sigma_hunting_app/default/app.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# Splunk app configuration file
#

[install]
is_configured = 0
install_source_checksum = cb75009a6e5f04c167c1ff03b59a2dc6cb4b0f51

[ui]
is_visible = 1
label = Sigma Hunting

[launcher]
author = Patrick Bareiss
description = A Sigma Hunting app consiting of different hunting searchs and detection rules.
version = 1.1.0

4 changes: 4 additions & 0 deletions sigma_hunting_app/default/commands.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[update]
chunked = true
filename = update.sh

8 changes: 8 additions & 0 deletions sigma_hunting_app/default/data/ui/nav/default.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<nav search_view="search">
<view name="security_posture" default='true' />
<view name="host_investigator" />
<view name="apt_investigator" />
<view name="lateral_movement_investigator" />
<view name="update" />
<view name="search" />
</nav>
1 change: 1 addition & 0 deletions sigma_hunting_app/default/data/ui/views/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add all the views that your app needs in this directory
73 changes: 73 additions & 0 deletions sigma_hunting_app/default/data/ui/views/apt_investigator.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<form>
<label>APT Investigator</label>
<fieldset submitButton="false">
<input type="time" token="time_picker">
<label>Time Range Picker</label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
</fieldset>
<row>
<panel>
<title>Countries of APT Groups by Triggered Alerts</title>
<map>
<title>Triggered Alerts -&gt; Mitre ATT&amp;CK Technique -&gt; potential APT Groups -&gt; Countries</title>
<search>
<query>`threat-hunting-index` | stats dc(name) AS "Distinct Count" by threat_actors | sort - "Distinct Count" | lookup mitre_enrichment_apt_country threat_actors AS threat_actors | search country=* | stats sum("Distinct Count") AS "Distinct Count" by country | sort - "Distinct Count" | geom geo_countries featureIdField="country"</query>
<earliest>$time_picker.earliest$</earliest>
<latest>$time_picker.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="drilldown">none</option>
<option name="mapping.choroplethLayer.colorBins">9</option>
<option name="mapping.choroplethLayer.colorMode">auto</option>
<option name="mapping.choroplethLayer.maximumColor">0x006D9C</option>
<option name="mapping.choroplethLayer.minimumColor">0x62b3b2</option>
<option name="mapping.choroplethLayer.neutralPoint">0</option>
<option name="mapping.choroplethLayer.shapeOpacity">0.75</option>
<option name="mapping.choroplethLayer.showBorder">1</option>
<option name="mapping.data.maxClusters">100</option>
<option name="mapping.legend.placement">bottomright</option>
<option name="mapping.map.center">(50,0)</option>
<option name="mapping.map.panning">1</option>
<option name="mapping.map.scrollZoom">0</option>
<option name="mapping.map.zoom">2</option>
<option name="mapping.markerLayer.markerMaxSize">50</option>
<option name="mapping.markerLayer.markerMinSize">10</option>
<option name="mapping.markerLayer.markerOpacity">0.8</option>
<option name="mapping.showTiles">1</option>
<option name="mapping.tileLayer.maxZoom">7</option>
<option name="mapping.tileLayer.minZoom">0</option>
<option name="mapping.tileLayer.tileOpacity">1</option>
<option name="mapping.type">choropleth</option>
<option name="refresh.display">progressbar</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</map>
</panel>
</row>
<row>
<panel>
<title>Distinct Count of Triggered Rules by APT Group</title>
<table>
<search>
<query>`threat-hunting-index` | stats values(attack_technique) AS "Attack Techniques" values(attack_tactics) AS "Attack Tactics" values(name) AS Rules dc(name) AS "Distinct Count" by threat_actors | lookup mitre_enrichment_apt_country threat_actors AS threat_actors | sort - "Distinct Count" | rename country AS Country | table threat_actors "Attack Techniques" "Attack Tactics" Rules Country "Distinct Count"</query>
<earliest>$time_picker.earliest$</earliest>
<latest>$time_picker.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">10</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">none</option>
<option name="percentagesRow">false</option>
<option name="refresh.display">progressbar</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
</table>
</panel>
</row>
</form>
71 changes: 71 additions & 0 deletions sigma_hunting_app/default/data/ui/views/host_investigator.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<form>
<label>Host Investigator</label>
<fieldset submitButton="false">
<input type="time" token="token_time">
<label>Time Range Picker</label>
<default>
<earliest>-24h@h</earliest>
<latest>now</latest>
</default>
</input>
<input type="text" token="token_host" searchWhenChanged="true">
<label>Host</label>
<prefix>orig_host="</prefix>
<suffix>"</suffix>
<default>*</default>
<initialValue>*</initialValue>
</input>
</fieldset>
<row>
<panel>
<title>Host Investigation by Timeline</title>
<viz type="timeline_app.timeline">
<search>
<query>`threat-hunting-index` $token_host$ | eval attack_tactics = mvindex(attack_tactics, 0) | eval sort_value=case(attack_tactics=="initial-access",1,attack_tactics=="execution",2,attack_tactics=="persistence",3,attack_tactics=="privilege-escalation",4,attack_tactics=="defense-evasion",5,attack_tactics=="credential-access",6,attack_tactics=="discovery",7,attack_tactics=="lateral-movement",8,attack_tactics=="collection",9,attack_tactics=="command-and-control",10,attack_tactics=="exfiltration",11,attack_tactics=="impact",12) | sort sort_value | table _time attack_tactics attack_technique</query>
<earliest>$token_time.earliest$</earliest>
<latest>$token_time.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<option name="timeline_app.timeline.axisTimeFormat">SECONDS</option>
<option name="timeline_app.timeline.colorMode">categorical</option>
<option name="timeline_app.timeline.maxColor">#DA5C5C</option>
<option name="timeline_app.timeline.minColor">#FFE8E8</option>
<option name="timeline_app.timeline.numOfBins">6</option>
<option name="timeline_app.timeline.tooltipTimeFormat">SECONDS</option>
<option name="timeline_app.timeline.useColors">1</option>
<option name="trellis.enabled">0</option>
<option name="trellis.scales.shared">1</option>
<option name="trellis.size">medium</option>
</viz>
</panel>
</row>
<row>
<panel>
<title>Triggered Rules by Host</title>
<table>
<search>
<query>`threat-hunting-index` $token_host$ | fillnull value=null level | stats count by orig_host, attack_ID, name, attack_technique, level | eval sort_chain=case(level=="critical",1,level=="high",2,level=="medium",3,level=="low",4) | sort sort_chain | fields - sort_chain</query>
<earliest>$token_time.earliest$</earliest>
<latest>$token_time.latest$</latest>
<sampleRatio>1</sampleRatio>
</search>
<option name="count">20</option>
<option name="dataOverlayMode">none</option>
<option name="drilldown">cell</option>
<option name="percentagesRow">false</option>
<option name="refresh.display">progressbar</option>
<option name="rowNumbers">false</option>
<option name="totalsRow">false</option>
<option name="wrap">true</option>
<format type="color" field="level">
<colorPalette type="map">{"critical":#DC4E41,"high":#F1813F,"medium":#F8BE34}</colorPalette>
</format>
<drilldown>
<link target="_blank">search?q=%60threat-hunting-index%60%20orig_host=$row.orig_host$&amp;earliest=$token_time.earliest$&amp;latest=$token_time.latest$</link>
</drilldown>
</table>
</panel>
</row>
</form>
Loading

0 comments on commit 48f3fd0

Please sign in to comment.