├── README.md ├── SA-Mitigation-Endpoint ├── bin │ └── mitigate_proc.py ├── default │ ├── commands.conf │ ├── inputs.conf │ ├── savedsearches.conf │ └── transforms.conf ├── logs │ └── proc_mitigator.log ├── lookups │ ├── proc_queue_template.csv │ ├── proc_queue_template.csv.default │ ├── process_queue.csv │ └── process_queue.csv.default └── metadata │ ├── default.meta │ └── default.meta.SplunkESSuite ├── SA-Mitigation ├── .DS_Store ├── README.md ├── bin │ ├── README.md │ ├── mitigator_endpoint.py │ └── mitigator_network.py ├── default │ ├── app.conf │ ├── commands.conf │ ├── correlationsearches.conf │ ├── data │ │ └── ui │ │ │ ├── nav │ │ │ └── default.xml │ │ │ └── views │ │ │ ├── mitigation_center.xml │ │ │ └── mitigation_tracker.xml │ ├── indexes.conf │ ├── inputs.conf │ ├── pan.conf │ ├── savedsearches.conf │ ├── searchbnf.conf │ └── transforms.conf ├── local │ └── app.conf ├── logs │ └── mitigator.log ├── lookups │ ├── mitigation.csv.default │ ├── mitigation_endpoint.csv │ ├── mitigation_endpoint.csv.default │ ├── mitigation_network.csv │ └── mitigation_network.csv.default └── metadata │ ├── default.meta │ └── default.meta.SplunkESSuite ├── images ├── SA-Mitigation-Endpoint-arch.png └── SA-Mitigation_search_arch.png ├── prezo ├── Auto Mitigation - Endpoint Example.mp4 └── confPrezo.pptx └── setup.xml.txt /README.md: -------------------------------------------------------------------------------- 1 | Splunk Mitigation Framework 2 | =========================== 3 | 4 | ## TODOs 5 | * setup.xml 6 | * documentation 7 | * error handling for the endpoint component 8 | 9 | ## Presentation Content 10 | [Slides](prezo/confPrezo.pptx) 11 | 12 | [Demo Video](https://www.youtube.com/watch?v=C4UIGNuoRdg) 13 | 14 | ## Installation 15 | Primariy package is the SA-Mitigation which contains a setup function with instructions on what to configure to get the framework setup. 16 | 17 | ### SA-Mitigation (Search Head Component) 18 | Contains all the search logic and the custom commands to take action. 19 | 20 | #### Search Architecture 21 | ![search\_arch](images/SA-Mitigation_search_arch.png) 22 | 23 | #### Installation Instructions 24 | coming soon... 25 | 26 | ### SA--Mitigator-Endpoint (Endpoint Component) 27 | 28 | #### Endpoing component architecture 29 | ![search\_arch](images/SA-Mitigation-Endpoint-arch.png) 30 | 31 | #### Installation Instructions 32 | comin soon... 33 | 34 | -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/bin/mitigate_proc.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.handlers 3 | import subprocess 4 | 5 | import splunk.Intersplunk as si 6 | from splunk.appserver.mrsparkle.lib.util import make_splunkhome_path 7 | 8 | ## Setup the logger 9 | def setup_logger(): 10 | """ 11 | Sets up a logger for the ProcMitigator. 12 | """ 13 | 14 | logger = logging.getLogger('proc_mitigator') 15 | # Prevent the log messages from being duplicated in the python.log 16 | # Authorization Failed 17 | logger.propagate = False 18 | logger.setLevel(logging.DEBUG) 19 | 20 | file_handler = logging.handlers.RotatingFileHandler( 21 | make_splunkhome_path(['etc', 'apps', 'SA-Mitigation-Endpoint', 22 | 'logs','proc_mitigator.log'])) 23 | 24 | formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') 25 | file_handler.setFormatter(formatter) 26 | 27 | logger.addHandler(file_handler) 28 | 29 | return logger 30 | 31 | logger = setup_logger() 32 | 33 | class ProcMitigator(object): 34 | """ 35 | Process Mitigator Class 36 | Used to Mitigate, kill, processes found in the Process Mitigation 37 | Queue (proc_mitigation_queue). 38 | """ 39 | 40 | ## Mitigate PID Command dictionary 41 | _proc_cmds = { 42 | "kill_pid": { 43 | 'win': ['taskkill', '/F', '/PID'], 44 | 'nix': ['kill', '-9'] 45 | }, 46 | "kill_proc_name": { 47 | 'win': ['taskkill', '/F' ,'/IM'], 48 | 'nix': ['killall', '-9'], 49 | }, 50 | "list_procs": { 51 | 'win': ['tasklist', '/V', '/FO', 'CSV'], 52 | 'nix': ['ps', '-A', '-o', 'pid'] 53 | } 54 | } 55 | 56 | def __init__(self, platform): 57 | """ 58 | ProcMitigator Constructor 59 | Used to initialize the Process Mitigator 60 | @param platform: The O/S platform of the system running the mitigator 61 | app. This MUST be one of [win, nix]. 62 | """ 63 | self._setPlatform(platform) 64 | if self._platform is not None: 65 | logger.info("ProcMitigator established for platform: " + 66 | self._platform) 67 | 68 | def _setPlatform(self, platform): 69 | """ 70 | Private method: _setPlatform 71 | Used to initialize the _platform field. 72 | @param platform: The O/S platform of the system running the mitigator 73 | app. This MUST be one of [win, nix]. 74 | """ 75 | if platform in ['win', 'nix']: 76 | self._platform = platform 77 | else: 78 | logger.error("Unknown Platform Used! - Specified Platform: " + 79 | str(self._platform)) 80 | self._platform = None 81 | 82 | def getPlatform(self): 83 | """ 84 | Public Method: getPlatform 85 | @return: self._platform 86 | """ 87 | return self._platform 88 | 89 | def _generateWinProcListing(self): 90 | """ 91 | Private Method: _generateWinProcList 92 | @return: A List of processes currently running on the system. Assumes 93 | the O/S platform is windows. 94 | """ 95 | p = subprocess.Popen(self._proc_cmds['list_procs']['win'], 96 | stdout=subprocess.PIPE) 97 | out, err = p.communicate() 98 | 99 | proc_list = [] 100 | out = out.split('\n') 101 | header = out[0] 102 | header = header[1:-1].split('","') 103 | out = out[1:] 104 | if not out[-1]: 105 | out = out[:-1] 106 | for line in out: 107 | attribs = line[1:-1].split('","') 108 | temp = {} 109 | for i in range(len(attribs)): 110 | temp[header[i]] = attribs[i] 111 | proc_list.append(temp) 112 | logger.info("Windows Process Listing Generated!") 113 | return proc_list 114 | 115 | 116 | def _generateNixProcListing(self): 117 | """ 118 | Private Method: _generateNixProcListing 119 | @return: A list of processes currently running on the system. Assumes 120 | the O/S platform is Nix based. 121 | """ 122 | p = subprocess.Popen(self._proc_cmds['list_procs']['nix'], 123 | stdout=subprocess.PIPE) 124 | out, err = p.communicate() 125 | 126 | proc_list = [] 127 | out = out.split('\n') 128 | header = out[0].strip() 129 | out = out[1:] 130 | if not out[-1]: 131 | out = out[:-1] 132 | for line in out: 133 | line = line.strip() 134 | proc_list.append({header: line}) 135 | logger.info("Nix Process Listing Generated!") 136 | return proc_list 137 | 138 | 139 | def locateProcess(self, proc_name=None, pid=None): 140 | """ 141 | Public Method: locateProcess 142 | @return: True if proc_name or pid were found in the process 143 | listing, False otherwise. 144 | """ 145 | located = False 146 | if self.getPlatform() == 'win': 147 | proc_list = self._generateWinProcListing() 148 | for proc in proc_list: 149 | if proc_name == proc['Image Name']: 150 | located = True 151 | break 152 | elif pid == proc['PID']: 153 | located = True 154 | break 155 | elif self.getPlatform() == 'nix': 156 | proc_list = self._generateNixProcListing() 157 | for proc in proc_list: 158 | if pid == proc['PID']: 159 | located = True 160 | break 161 | 162 | return located 163 | 164 | def killProcByID(self, the_pid): 165 | """ 166 | Public Method: killProcByID 167 | Used to issue a kill pid command to the system to for 168 | the_pid. 169 | 170 | @param the_pid: The PID of the process to be killed. 171 | @return [out, err] from the process communication. 172 | """ 173 | out = None 174 | err = None 175 | if self.locateProcess(pid=the_pid): 176 | p = subprocess.Popen(self._proc_cmds['kill_pid'][self.getPlatform()] + [str(the_pid)], 177 | stdout=subprocess.PIPE) 178 | out, err = p.communicate() 179 | else: 180 | logger.error("PID: " + str(the_pid) + " not found running on " + 181 | "the system!") 182 | return [out,err] 183 | 184 | def killProcByName(self, the_proc_name): 185 | """ 186 | Public Method: killProcByName 187 | Used to issue a kill process command to the system for 188 | the_proc_name 189 | 190 | @param the_proc_name: The Process Name of the process to be killed. 191 | @return [out, err] from the process communication. 192 | """ 193 | out = None 194 | err = None 195 | if self.locateProcess(proc_name=the_proc_name): 196 | p = subprocess.Popen(self._proc_cmds['kill_proc_name'][self.getPlatform()] + [str(the_proc_name)], 197 | stdout=subprocess.PIPE) 198 | out, err = p.communicate() 199 | else: 200 | logger.error("Process Name: " + str(the_proc_name) + " not found " + 201 | " running on the system!") 202 | 203 | return [out,err] 204 | 205 | if __name__ == '__main__': 206 | try: 207 | results = si.readResults() 208 | keywords, options = si.getKeywordsAndOptions() 209 | 210 | for entry in results: 211 | ## PID 212 | if "pid" in entry: 213 | pid = entry["pid"] 214 | else: 215 | pid = options.get('pid', None) 216 | 217 | ## Process Name 218 | if 'proc_name' in entry: 219 | proc_name = entry['proc_name'] 220 | else: 221 | proc_name = options.get('proc_name', None) 222 | 223 | ## Platform 224 | if 'platform' in entry: 225 | platform = entry['platform'] 226 | else: 227 | platform = options.get('platform', None) 228 | 229 | mitigator = ProcMitigator(str(platform)) 230 | 231 | if pid is not None: 232 | logger.info(str(mitigator.killProcByID(str(pid)))) 233 | elif proc_name is not None: 234 | logger.info(str(mitigator.killProcByName(str(proc_name)))) 235 | 236 | except Exception as e: 237 | logger.error("There was an issue establishing arguments for the " + 238 | "mitigateProc search command!") 239 | logger.exception(str(e)) 240 | -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/default/commands.conf: -------------------------------------------------------------------------------- 1 | ############## ############## 2 | # Version 0.09.11.2014 # 3 | # DO NOT EDIT THIS FILE! # 4 | # Please make all changes to files in $SPLUNK_HOME/etc/apps/SA-Mitigation/local# 5 | # To make changes, copy the section/stanza you want to change into ../local # 6 | # and edit there. # 7 | # # 8 | # Configuration for external search commands # 9 | # # 10 | ############## ############## 11 | 12 | [mitigateproc] 13 | filename = mitigate_proc.py 14 | supports_rawargs = true -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/default/inputs.conf: -------------------------------------------------------------------------------- 1 | [monitor://$SPLUNK_HOME/etc/apps/SA-Mitigation-Endpoint/logs/proc_mitigator.log] 2 | sourcetype=mitigation 3 | index = mitigation 4 | -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/default/savedsearches.conf: -------------------------------------------------------------------------------- 1 | ####################### 2 | ## Mitigation Searches 3 | ####################### 4 | 5 | #Enable this search if deplaying to Nix enviroment and disable the windows one below 6 | #[queue_manager_nix] 7 | #action.email.sendresults = 0 8 | #cron_schedule = */5 * * * * 9 | #disabled = False 10 | #dispatch.latest_time = +0s 11 | #enableSched = 1 12 | #is_visible = false 13 | #search = | inputlookup process_queue | head 1 | mitigateproc platform=nix | append [|inputlookup process_queue | join type=left pid [|inputlookup process_queue | head 1| eval temp=pid] | eval rm=if(pid==temp,1,0)] | where rm != 1 | fields time,pid | outputlookup process_queue 14 | 15 | #Enable this search if deploying in Win enviroment and disable the Nix one above 16 | [queue_manager_win] 17 | action.email.sendresults = 0 18 | cron_schedule = */5 * * * * 19 | disabled = False 20 | dispatch.latest_time = +0s 21 | enableSched = 1 22 | is_visible = false 23 | search = | inputlookup process_queue | head 1 | mitigateproc platform=win | append [|inputlookup process_queue | join type=left pid [|inputlookup process_queue | head 1| eval temp=pid] | eval rm=if(pid==temp,1,0)] | where rm != 1 | fields time,pid | outputlookup process_queue 24 | -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/default/transforms.conf: -------------------------------------------------------------------------------- 1 | [process_queue] 2 | filename = process_queue.csv 3 | case_sensitive_match = false 4 | 5 | [proc_queue_template] 6 | filename = proc_queue_template.csv 7 | case_sensitive_match = false -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/logs/proc_mitigator.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/Splunk-Mitigation-Framework/e973cdb9656a7d1abcef4b2b2e3c9b12b3710e39/SA-Mitigation-Endpoint/logs/proc_mitigator.log -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/lookups/proc_queue_template.csv: -------------------------------------------------------------------------------- 1 | pid,time 2 | DNF,DNF -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/lookups/proc_queue_template.csv.default: -------------------------------------------------------------------------------- 1 | pid,time 2 | -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/lookups/process_queue.csv: -------------------------------------------------------------------------------- 1 | pid,time 2 | -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/lookups/process_queue.csv.default: -------------------------------------------------------------------------------- 1 | time,pid -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/metadata/default.meta: -------------------------------------------------------------------------------- 1 | 2 | # Application-level permissions 3 | 4 | [] 5 | access = read : [ * ], write : [ admin, power ] 6 | 7 | ### EVENT TYPES 8 | 9 | [eventtypes] 10 | export = system 11 | 12 | 13 | ### PROPS 14 | 15 | [props] 16 | export = system 17 | 18 | 19 | ### TRANSFORMS 20 | 21 | [transforms] 22 | export = system 23 | 24 | 25 | ### LOOKUPS 26 | 27 | [lookups] 28 | export = system 29 | 30 | 31 | ### VIEWSTATES: even normal users should be able to create shared viewstates 32 | 33 | [viewstates] 34 | access = read : [ * ], write : [ * ] 35 | export = system 36 | -------------------------------------------------------------------------------- /SA-Mitigation-Endpoint/metadata/default.meta.SplunkESSuite: -------------------------------------------------------------------------------- 1 | 2 | ## SplunkEnterpriseSecuritySuite Application-level permissions 3 | [event_renderers] 4 | export = none 5 | 6 | ## per SOLNPCI-297 renaming 'ess_correlation_search_edit' -> 'correlation_search_edit' 7 | ## and setting exportation to local 8 | [views/correlation_search_edit] 9 | export = none 10 | 11 | ## The following export=none allows for general suppression definitions: 12 | ## 'ess_notable_supppression_new' -> 'notable_suppression_new' 13 | [views/notable_suppression_new] 14 | export = none 15 | 16 | ## Don't export the workflow actions since other apps will not have the notable editor and we don't 17 | ## want to redirect the users to an inaccessible view. 18 | ## Furthermore, we don't want to list the workflow actions twice if the customer has both ES and PCI 19 | [workflow_actions] 20 | export = none 21 | 22 | # Import the Domain Addons for ES. Note that these DA's will import the Supporting Addons. 23 | [] 24 | import = DA-ESS-AccessProtection,DA-ESS-EndpointProtection,DA-ESS-IdentityManagement,DA-ESS-NetworkProtection 25 | ## shared Application-level permissions 26 | [] 27 | access = read : [ * ], write : [ admin ] 28 | export = system 29 | 30 | [savedsearches] 31 | owner = admin 32 | 33 | [governance] 34 | access = read : [ * ], write : [ * ] 35 | 36 | ## Postprocess 37 | [postprocess] 38 | access = read : [ * ], write : [ * ] 39 | 40 | 41 | ## Exclude export of custom alert actions 42 | [alert_actions/email] 43 | export = none 44 | -------------------------------------------------------------------------------- /SA-Mitigation/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/Splunk-Mitigation-Framework/e973cdb9656a7d1abcef4b2b2e3c9b12b3710e39/SA-Mitigation/.DS_Store -------------------------------------------------------------------------------- /SA-Mitigation/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/Splunk-Mitigation-Framework/e973cdb9656a7d1abcef4b2b2e3c9b12b3710e39/SA-Mitigation/README.md -------------------------------------------------------------------------------- /SA-Mitigation/bin/README.md: -------------------------------------------------------------------------------- 1 | Attack Mitigation Scripts 2 | ========================= 3 | 4 | ### mitigator\_endpoint.py 5 | * Requires: Authentication for remote Splunk Agents instances under credential manager of ES under Realm `LWF`. 6 | 7 | This script makes a custom rest call to populate the `process_queue.csv` lookup in the remote splunk instances telling it what to block. 8 | 9 | ### mitigator\_network.py 10 | * Requires: Authentication for the remote Palo Alto firewalls under credential manager in ES with Realm `PAN`. 11 | 12 | This script is a modification of the pan block which uses credential manager, adds IPs to a designated group in a Palo Alto. 13 | 14 | 15 | -------------------------------------------------------------------------------- /SA-Mitigation/bin/mitigator_endpoint.py: -------------------------------------------------------------------------------- 1 | import urllib 2 | import urllib2 3 | import json 4 | import time 5 | import logging 6 | import logging.handlers 7 | 8 | import splunk.Intersplunk as si 9 | import splunk.rest 10 | from splunk.appserver.mrsparkle.lib.util import make_splunkhome_path 11 | 12 | def setup_logger(): 13 | """ 14 | Sets up a logger for the Mitigator search command to track issued 15 | mitigation tasks. 16 | """ 17 | logger = logging.getLogger('mitigator') 18 | # Prevent the log messgaes from being duplicated in the python.log 19 | # AuthorizationFailed 20 | logger.propagate = False 21 | logger.setLevel(logging.DEBUG) 22 | 23 | file_handler = logging.handlers.RotatingFileHandler( 24 | make_splunkhome_path(['etc', 'apps', 'SA-Mitigation', 'logs', 25 | 'mitigator.log']), 26 | maxBytes=25000000, backupCount=5) 27 | formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') 28 | file_handler.setFormatter(formatter) 29 | 30 | logger.addHandler(file_handler) 31 | 32 | return logger 33 | 34 | logger = setup_logger() 35 | 36 | class Mitigator(object): 37 | """ 38 | Mitigator Class 39 | This class is used for issuing mitigation tasks to remote forwarders 40 | containing the SA-LWF_Mitigater Splunk App. 41 | """ 42 | 43 | ## Forwarder Management Port 44 | _MGMT_PORT = ':8089' 45 | 46 | ## REST Endpoint for issuing Splunk Searches 47 | _SEARCH_ENDPOINT = '/servicesNS/nobody/search/search/jobs/export' 48 | 49 | ## REST Endpoint for authentication. Used to obtain a session key 50 | _AUTH_ENDPOINT = '/servicesNS/nobody/search/auth/login' 51 | 52 | def __init__(self, system, localSessionKey): 53 | """ 54 | Mitigator Constructor 55 | The constructor will attempt to obtain a session key for the remote 56 | instance. If this fails the Mitigator will be unable to issue a 57 | mitigation task to the remote forwarder. 58 | @param system: The system (hostname or ip) in which the mitigation task 59 | is being issued to. 60 | @param uname: Username for the remote Splunk instance 61 | @param passwd: Password for the remote Splunk instance 62 | """ 63 | self.queueSearch = ("| inputlookup proc_queue_template " + 64 | "| eval pid={0} | eval time={1} | fields time, " + 65 | "pid | outputlookup append=T max=1 process_queue") 66 | self._setHost(system) 67 | self._time = str(int(time.time())) 68 | self._setLocalSessionKey(localSessionKey) 69 | self.sessionKey = self._requestSessionKey() 70 | 71 | logger.info("Mitigator Established for System: " + self._host) 72 | 73 | 74 | def _setLocalSessionKey(self, local_session_key): 75 | """ 76 | Private Method: _setLocalSessionKey 77 | Used to set the local session key for the Splunk instance where 78 | SA-Mitigation resides. 79 | """ 80 | self._localSessionKey = str(local_session_key) 81 | 82 | def _setHost(self, the_system): 83 | """ 84 | Private Method: _setHost 85 | Method used to initialize the _host field. 86 | 87 | @param the_system: The system (hostname or ip) in which the mitigation task 88 | is being issued to. 89 | """ 90 | self._host = 'https://' + str(the_system) + self._MGMT_PORT 91 | 92 | def _getLWFCreds(self): 93 | """ 94 | """ 95 | uname = None 96 | passwd = None 97 | response, content = splunk.rest.simpleRequest('storage/passwords', 98 | getargs={'output_mode': 'json','count': '0'}, 99 | raiseAllErrors=True, 100 | sessionKey=self._localSessionKey) 101 | 102 | if response['status'] == "200": 103 | content = json.loads(content) 104 | for entry in content['entry']: 105 | if entry['content']['realm'] == "LWF": 106 | uname = entry['content']['username'] 107 | passwd = entry['content']['clear_password'] 108 | break 109 | 110 | #logger.info("Username: " + str(uname) + " Password: " + str(passwd)) 111 | logger.info("Loggin in as Username: " + str(uname) + " From LWF Realm in cred manager") 112 | else: 113 | logger.error("Received something other than an HTTP 200 response " + 114 | "when attempting to acquire the LWF creds from the " + 115 | " cred manager.") 116 | return uname, passwd 117 | 118 | def _requestSessionKey(self): 119 | """ 120 | Private Method: _requestSessionKey 121 | Method used to request a session key from the remote splunk 122 | instance. 123 | 124 | @return String representation of the session key for the remote splunk 125 | instance. 126 | """ 127 | try: 128 | uname, passwd = self._getLWFCreds() 129 | url = self._host + self._AUTH_ENDPOINT 130 | request = urllib2.Request(url, 131 | data = urllib.urlencode({'username': uname, 'password': passwd, 132 | 'output_mode': 'json'})) 133 | content = urllib2.urlopen(request).read() 134 | content = json.loads(content) 135 | return 'Splunk ' + content['sessionKey'] 136 | except Exception as e: 137 | logger.error("There was an issue requesting the session key for " + 138 | " host: " + self._host) 139 | logger.exception(str(e)) 140 | 141 | 142 | def getSessionKey(self): 143 | """ 144 | Public Method: getSessionKey 145 | @return The session key requested from the remote splunk instance. 146 | """ 147 | return self.sessionKey 148 | 149 | def sendMitigatePIDTask(self, pid): 150 | """ 151 | Public Method: sendMitigatePIDTask 152 | Used to issue PID mitigation tasks to the remote splunk instance. 153 | 154 | @param pid: The PID that is to be mitigated by the remote Splunk 155 | instance 156 | """ 157 | try: 158 | url = self._host + self._SEARCH_ENDPOINT 159 | request = urllib2.Request(url, 160 | data = urllib.urlencode({'search': self.queueSearch.format(str(pid), self._time), 161 | 'output_mode': 'json'}), 162 | headers = {'Authorization': self.getSessionKey()}) 163 | 164 | content = urllib2.urlopen(request) 165 | logger.info("Mitigate PID task sent to host: " + self._host + 166 | " for PID: " + str(pid) + ", at Time: " + self._time) 167 | except Exception as e: 168 | logger.error("There was an issue sending a PID Mitigation Task " + 169 | "for host: " + self._host + ", time: " + self._time + 170 | ", PID: " + str(pid)) 171 | logger.exception(str(e)) 172 | 173 | if __name__ == '__main__': 174 | 175 | try: 176 | results, dummyresults, settings = si.getOrganizedResults() 177 | keywords, options = si.getKeywordsAndOptions() 178 | 179 | for entry in results: 180 | ## System info 181 | if "system" in entry: 182 | system = entry["system"] 183 | else: 184 | system = options.get('system', None) 185 | 186 | ## PID Info 187 | if "pid" in entry: 188 | pid = entry["pid"] 189 | else: 190 | pid = options.get('pid', None) 191 | 192 | mit = Mitigator(system, settings['sessionKey']) 193 | mit.sendMitigatePIDTask(pid) 194 | print 'sent PID ' + pid + ' to be mitigated at ' + system 195 | 196 | except Exception as e: 197 | logger.error("There was an issue establishing arguments for the " + 198 | "mitigator search command!") 199 | logger.exception(str(e)) 200 | -------------------------------------------------------------------------------- /SA-Mitigation/bin/mitigator_network.py: -------------------------------------------------------------------------------- 1 | ########################################## 2 | # This is a modifed version of the panChange.py script from the Palo Alto App 3 | # This script is meant to be use with Splunk Enterprise Security. 4 | # Author: jose@splunk.com 5 | # Description: This is a modifed version of the panChange.py script from the Palo Alto App 6 | # This script is meant to be use with Splunk Enterprise Security. 7 | # Udpates: 8 | # * crendetials now stored encrypted using credential manager with ES 9 | # * configuration file moved to default/pan.conf 10 | ########################################## 11 | # Original Documentation Below 12 | ########################################### 13 | # Version 0.1 14 | # Extremely Experimental 15 | # author: monzy@splunk.com 16 | # About this script: 17 | # Given an IP address, adds or removes the IP from an address group 18 | # The script assumes that you have firewall policy setup that blocks 19 | # traffic for a given group, e.g. a badActors group. 20 | # It is important to recognize that this script does NOT modify a firewall rule. 21 | # It only adds/removes address objects. 22 | # So if a rule operates on an Address Group, this scripts add/remove will impact 23 | # that rule/policy. 24 | ############################################ 25 | # How to Use this script 26 | # in the example below, we are blocking all ip's returned by the search 27 | # example1: index=pan_logs 1.1.1.1 | stats dc(dst_ip) by dst_ip | panblock action="add" group="badboys" 28 | # Adds the IP 1.1.1.1 29 | # example2: index=pan_logs wine | stats dc(dst_hostname) by dst_hostname | panblock action="rem" group="badboys" device="sales-fw" 30 | # Removes all dst_hostnames returned by the search from the sales firewall from the badboys group 31 | ########################################### 32 | # Known issues: 33 | # Very limited error checking 34 | # Errors may not reported in the Splunk UI 35 | # Changes do not get implemented on Panorama (i am happy to work with someone to add this feature) 36 | ########################################### 37 | # DEFAULTS 38 | ACTION = 'add' 39 | # This is a default actor. 40 | ACTOR = '1.1.1.1' 41 | # if you DO want to go through a proxy, e.g., HTTP_PROXY={squid:'2.2.2.2'} 42 | HTTP_PROXY = {} 43 | 44 | ######################################################### 45 | # Do NOT modify anything below this line unless you are 46 | # certain of the ramifications of the changes 47 | ######################################################### 48 | 49 | import splunk.Intersplunk # so you can interact with Splunk 50 | import splunk.entity as entity # for splunk config info 51 | import urllib2 # make http requests to PAN firewall 52 | import sys # for system params and sys.exit() 53 | import re # regular expressions checks in PAN messages 54 | import splunk.mining.dcutils as dcu 55 | import ConfigParser # to parse out the pa.conf file 56 | from splunk.appserver.mrsparkle.lib.util import make_splunkhome_path # to grab the default splunk path 57 | import splunk.rest 58 | import json 59 | 60 | logger = dcu.getLogger() 61 | # set path of config 62 | panconf = make_splunkhome_path(["etc","apps","SA-Mitigation","default","pan.conf"]) 63 | # read config file 64 | config = ConfigParser.RawConfigParser() 65 | config.read(panconf) 66 | 67 | #Assign PA IP 68 | PAN = config.get('PAN','IP') 69 | 70 | #Assign BADACTORS group name 71 | BADACTORS = config.get('PAN','GROUP') 72 | 73 | ## Major props to Ledion. copying his function, verbatim and then adding comments and traceback and logging 74 | ## http://blogs.splunk.com/2011/03/15/storing-encrypted-credentials/ 75 | ## access the credentials in /servicesNS/nobody//admin/passwords 76 | 77 | def getCredentials(sessionKey): 78 | '''Given a splunk sesionKey returns a clear text user name and password from a splunk password container''' 79 | USERNAME ='' 80 | PASSWORD ='' 81 | #make a rest call to get passwords from credential manager 82 | response,content = splunk.rest.simpleRequest('storage/passwords', sessionKey=sessionKey, getargs={'output_mode':'json'}, postargs=None, method='GET', raiseAllErrors=False, proxyMode=False, rawResult=False, timeout=None, jsonargs=None) 83 | #format output as json 84 | content = json.loads(content) 85 | 86 | #look for the realm of PAN and resturn the credentials 87 | for items in content['entry']: 88 | if items['content']['realm'] == 'PAN': 89 | USERNAME = item['content']['username'] 90 | PASSWORD = item['content']['clear_password'] 91 | return USERNAME,PASSWORD 92 | ## Major props to Ledion. copying his function, verbatim and then adding comments and traceback and logging 93 | 94 | def createOpener(): 95 | '''Create a generic opener for http. This is particularly helpful when there is a proxy server in line''' 96 | # Thanks to: http://www.decalage.info/en/python/urllib2noproxy 97 | proxy_handler = urllib2.ProxyHandler(HTTP_PROXY) 98 | opener = urllib2.build_opener(proxy_handler) 99 | urllib2.install_opener(opener) 100 | return opener 101 | 102 | def getKey(PAN, PANUSER, PANPASS): 103 | ''' Logs into the PAN firewall and obtains a PAN session key''' 104 | # create an opener object 105 | opener = createOpener() 106 | try: 107 | # the url for the PAN 108 | panReq = urllib2.Request('https://'+PAN+'/api/?type=keygen&user='+PANUSER+'&password='+PANPASS) 109 | # make the request 110 | req = opener.open(panReq) 111 | except: 112 | sys.exit(-1) 113 | # the result of the URL request 114 | result = req.read() 115 | # get the status of the result 116 | try: 117 | sm = re.search(r"success",result).group(0) 118 | if sm == 'success' : 119 | status = 'success' 120 | except: 121 | sys.exit(-1) 122 | # parse the key from the result 123 | key = result.split("")[0].split("")[1] 124 | return key 125 | 126 | def checkAddr(address): 127 | '''Check if an address is a FQDN or IP with some netmask. Return the appropriate uri for PAN api''' 128 | # element is everything after the element= field in the PAN api 129 | # re pattern for IP address 130 | ippat = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' 131 | # re pattern for fully qualified domain name (could be stricter) 132 | fqdnpat = '\w+[.-]' 133 | # is element an IP address 134 | if re.match(ippat, address) != None : 135 | ipuri = ''+address+'/32' 136 | return ipuri 137 | if re.match(fqdnpat, address) != None : 138 | fqdnuri = ''+address+'' 139 | return fqdnuri 140 | 141 | def panorama(): 142 | ''' Interact with PANorama''' 143 | #Set dynamic address object (with LinkID) at Panorama level, commit 144 | #https://pm-panorama/api/?type=config&action=set&xpath=/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='splunktastic']/address/entry[@name='test-add']&element=test1&key=LUFRPT14MW5xOEo1R09KVlBZNnpnemh0VHRBOWl6TGM9bXcwM3JHUGVhRlNiY0dCR0srNERUQT09 145 | #https://pm-panorama/api/?type=commit&action=all&cmd=splunktastic&key=LUFRPT14MW5xOEo1R09KVlBZNnpnemh0VHRBOWl6TGM9bXcwM3JHUGVhRlNiY0dCR0srNERUQT09 146 | #Map IPs to correct UserID 147 | #https://pm-panorama/api/?type=user-id&action=set&cmd=1.0update&key=LUFRPT14MW5xOEo1R09KVlBZNnpnemh0VHRBOWl6TGM9bXcwM3JHUGVhRlNiY0dCR0srNERUQT09&target=0006C107916 148 | return 0 149 | 150 | def addActor(PAN, key, VSYS, ACTOR, BADACTORS): 151 | '''Creates an address object then add the object to an Address group''' 152 | # create an opener object 153 | opener = createOpener() 154 | # create the address object 155 | panReq = urllib2.Request('https://'+PAN+'//api/?type=config&action=set&key='+key+'&xpath=/config/devices/entry/vsys/entry[@name='+"'"+VSYS+"'"+']/address/entry[@name='+"'"+ACTOR+"'"+']&element='+checkAddr(ACTOR)) 156 | req = opener.open(panReq) 157 | # add the address object to the BADACTORS group 158 | panReq = urllib2.Request('https://'+PAN+'//api/?type=config&action=set&key='+key+'&xpath=/config/devices/entry/vsys/entry[@name='+"'"+VSYS+"'"+']/address-group/entry[@name='+"'"+BADACTORS+"'"+']&element='+ACTOR+'') 159 | req = opener.open(panReq) 160 | return 0 161 | 162 | def remActor(PAN, key, VSYS, ACTOR, BADACTORS): 163 | '''Remove an address object from the address-group then remove the addres object ''' 164 | # create an opener object 165 | opener = createOpener() 166 | # first we remove him from the badactors group 167 | #panReq = urllib2.Request('https://'+PAN+'/api/?type=config&action=delete&key='+key+'&xpath=/config/devices/entry/vsys/entry[@name='+"'"+VSYS+"'"+']/address-group/entry[@name='+"'"+BADACTORS+"'"+']&element='+ACTOR+'') 168 | #req = opener.open(panReq) 169 | # then we remove him all together 170 | #panReq = urllib2.Request('https://'+PAN+'/api/?type=config&action=delete&key='+key+'&xpath=/config/devices/entry/vsys/entry[@name='+"'"+VSYS+"'"+']/address/entry[@name='+"'"+ACTOR+"'"+']') 171 | #req = opener.open(panReq) 172 | panReq = urllib2.Request('https://'+PAN+'/api/?type=config&action=delete&key='+key+'&xpath=/config/devices/entry/vsys/entry[@name='+"'"+VSYS+"'"+']/address-group/entry[@name='+"'"+BADACTORS+"'"+']/member[text()='+"'"+ACTOR+"'"+']') 173 | req = opener.open(panReq) 174 | panReq = urllib2.Request('https://'+PAN+'/api/?type=config&action=delete&key='+key+'&xpath=/config/devices/entry/vsys/entry[@name='+"'"+VSYS+"'"+']/address/entry[@name='+"'"+ACTOR+"'"+']') 175 | req = opener.open(panReq) 176 | return 0 177 | 178 | def commitConfig(PAN, key): 179 | '''Save the changes made to the address objects''' 180 | # create an opener object 181 | opener = createOpener() 182 | panReq = urllib2.Request('https://'+PAN+'//api/?type=commit&cmd=&key='+key) 183 | req = opener.open(panReq) 184 | return 0 185 | 186 | def block(result): 187 | key = getKey(PAN, PANUSER, PANPASS) 188 | if ACTION == 'add': 189 | addActor(PAN, key, VSYS, str(result[result.keys()[0]]), BADACTORS) 190 | elif ACTION == 'rem': 191 | remActor(PAN, key, VSYS, str(result[result.keys()[0]]), BADACTORS) 192 | else: 193 | return ['bad action', key] 194 | return ["action submitted", key] 195 | 196 | args, kwargs = splunk.Intersplunk.getKeywordsAndOptions() 197 | #parse the kwargs for ACTION, VSYS, PAN 198 | if kwargs.has_key('action'): 199 | ACTION = kwargs['action'] 200 | if kwargs.has_key('device'): 201 | PAN = kwargs['device'] 202 | if kwargs.has_key('vsys'): 203 | VSYS = kwargs['vsys'] 204 | if kwargs.has_key('group'): 205 | BADACTORS = kwargs['group'] 206 | 207 | # an empty dictionary. it will be used to hold system values 208 | settings = dict() 209 | # results contains the data from the search results and settings contains the sessionKey that we can use to talk to splunk 210 | results,unused,settings = splunk.Intersplunk.getOrganizedResults() 211 | # get the sessionKey 212 | sessionKey = settings['sessionKey'] 213 | # get the user and password using the sessionKey 214 | PANUSER, PANPASS = getCredentials(sessionKey) 215 | 216 | try: 217 | for result in results: 218 | if (result.has_key('src_ip')\ 219 | or result.has_key('dst_ip') \ 220 | or result.has_key('ip') \ 221 | or result.has_key('hostname') \ 222 | or result.has_key('dst_hostname') \ 223 | or result.has_key('dest_host') \ 224 | or result.has_key('domain') \ 225 | or result.has_key('clientip') ): 226 | blockresult = block(result) 227 | result["status"] = blockresult[0] 228 | key = blockresult[1] 229 | # for test purposes 230 | elif (len(result) == 2) and result.has_key('test'): 231 | result["status"] = ["this is the sessionKey. not printing the password :p " + sessionKey] 232 | else: 233 | result["status"] = 'empty or invalid field vlue' 234 | 235 | #after all the addresses have been processed, commit the config 236 | commitConfig(PAN, key) 237 | except Exception, e: 238 | import traceback 239 | stack = traceback.format_exc() 240 | if isgetinfo: 241 | splunk.Intersplunk.parseError(str(e)) 242 | 243 | results = splunk.Intersplunk.generateErrorResults(str(e)) 244 | logger.warn(stack) 245 | 246 | # output results 247 | splunk.Intersplunk.outputResults(results) 248 | -------------------------------------------------------------------------------- /SA-Mitigation/default/app.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Splunk app configuration file 3 | # 4 | 5 | [install] 6 | is_configured = 0 7 | 8 | [ui] 9 | is_visible = 0 10 | label = SA-Mitigation 11 | 12 | [launcher] 13 | author = Jose Hernandez, Monzy Merza, Brian Luger 14 | description = Fight attacks in ES framework 15 | version = 1.0 16 | 17 | [credential:LWF:admin:] 18 | password = $1$+/Ox7ASEXpT2WsM= 19 | 20 | [credential:PAN:panservice:] 21 | password = $1$pvDs6R3GQ/c= 22 | -------------------------------------------------------------------------------- /SA-Mitigation/default/commands.conf: -------------------------------------------------------------------------------- 1 | ############################ 2 | # Version 0.09.11.2014 3 | # DO NOT EDIT THIS FILE! 4 | # Please make all changes to files in $SPLUNK_HOME/etc/apps/SA-Mitigation/local 5 | # To make changes, copy the section/stanza you want to change into ../local and edit there. 6 | # Configuration for external search commands 7 | ############################ 8 | 9 | [blockendpoint] 10 | filename = mitigator_endpoint.py 11 | supports_rawargs = true 12 | passauth = true 13 | 14 | [blocknetwork] 15 | filename = mitigator_network.py 16 | supports_rawargs = true 17 | passauth = true 18 | -------------------------------------------------------------------------------- /SA-Mitigation/default/correlationsearches.conf: -------------------------------------------------------------------------------- 1 | [Network - Mitigation High Confidence IDS - Rule] 2 | default_status = 2 3 | description = A high confidence IDS alert to $src$ example for the Mitigation framework 4 | rule_description = Notable that triggers mitigation on a high confidence IDS alert to $src$ 5 | rule_name = High Confidence IDS 6 | rule_title = Mitigation - High Confidence IDS Alert on $src$ 7 | search = {} 8 | security_domain = network 9 | severity = critical 10 | 11 | 12 | [Endpoint - Mitigation High Confidence Registry - Rule] 13 | default_status = 2 14 | description = Mitigation on a registry key under currentversion/run with created from a application with .vbs as a file extension with pid $pid$ on $host$ 15 | rule_description = Notable that triggers mitigation on a registry key under currentversion/run with created from a application with .vbs as a file extension with pid $pid$ on $host$ 16 | rule_name = High Confidence Registry 17 | rule_title = Mitigation - High Confidence Registry Alert with pid $pid$ on $host$ 18 | search = {} 19 | security_domain = endpoint 20 | severity = critical 21 | -------------------------------------------------------------------------------- /SA-Mitigation/default/data/ui/nav/default.xml: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /SA-Mitigation/default/data/ui/views/mitigation_center.xml: -------------------------------------------------------------------------------- 1 |
2 | 3 | High level view of what is going on with auto mitigaton 4 |
5 | 6 | 7 | All 8 | Endpoint 9 | Network 10 | * 11 | 12 | 13 |
20 | 21 | 22 | 23 | Host in Mitigation 24 | index=mitigation_* $type$ | stats dc(orig_host) 25 | $mitigation_time.earliest$ 26 | $mitigation_time.latest$ 27 | 28 | 29 | 30 | 31 | 32 | 33 | Top 5 Host 34 | index=mitigation_summary $type$ | top orig_host limit=5 | rename orig_host as Host | table Host 35 | $mitigation_time.earliest$ 36 | $mitigation_time.latest$ 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
70 |
71 | 72 | 73 | Recent Processes Killed by Host 74 | index=mitigation_* $type$ pid=* |stats count by pid,orig_host | rename orig_host as Host | sort - count | table Host,pid,count | head 10 75 | $mitigation_time.earliest$ 76 | $mitigation_time.latest$ 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
101 |
102 |
103 | 104 | 105 | 106 | Mitigation By SourceType 107 | index=mitigation_* NOT orig_sourcetype="stash" * | stats count by orig_sourcetype 108 | $mitigation_time.earliest$ 109 | $mitigation_time.latest$ 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Mitigation Details 133 | index=mitigation $type$ 134 | $mitigation_time.earliest$ 135 | $mitigation_time.latest$ 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | ["host","source","sourcetype"] 146 | 147 | 148 | 149 | 150 | 151 | 152 | Mitigation Errors by Host 153 | index=mitigation_* tag=error $type$ | stats count by orig_host 154 | $mitigation_time.earliest$ 155 | $mitigation_time.latest$ 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 |
-------------------------------------------------------------------------------- /SA-Mitigation/default/data/ui/views/mitigation_tracker.xml: -------------------------------------------------------------------------------- 1 |
2 | 3 | Detailed view of what is going on with auto mitigaton for a specific host 4 |
5 | 6 | 7 | 8 | 0 9 | 10 | 11 | 12 | 13 | 14 | All 15 | Endpoint 16 | Network 17 | * 18 | 19 | 20 | 21 | All 22 | index=mitigation_summary | stats count by id 23 | * 24 | 25 | 26 | 27 | * 28 | 29 |
30 | 31 | 32 | 33 | Mitigation Activity 34 | index=mitigation_* $type$ $id$ $host$ | timechart count 35 | $mitigation_time.earliest$ 36 | $mitigation_time.latest$ 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | Malicious RegKeys 65 | index=mitigation_* $type$ $id$ $host$ | stats count by key_path | rename key_path as RegKey | sort - count | table RegKey, count 66 | $mitigation_time.earliest$ 67 | $mitigation_time.latest$ 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
94 | 95 | 96 | Malicious Scripts 97 | index=mitigation_* | stats count by data,pid | sort - count 98 | $mitigation_time.earliest$ 99 | $mitigation_time.latest$ 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 |
124 |
125 | 126 | 127 | Malicious Process 128 | index=mitigation_* $id$ $host$ | stats count by process_image 129 | $mitigation_time.earliest$ 130 | $mitigation_time.latest$ 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 |
155 |
156 |
157 | 158 | 159 | 160 | Mitigation Map 161 | index=mitigation $type$ $id$ $host$ | iplocation src | geostats latfield=src_lat longfield=src_long count 162 | $mitigation_time.earliest$ 163 | $mitigation_time.latest$ 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | ["host","source","sourcetype"] 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | Mitigation Details 190 | index=mitigation_summary 191 | $mitigation_time.earliest$ 192 | $mitigation_time.latest$ 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | ["host","source","sourcetype"] 204 | 205 | 206 | 207 |
208 | -------------------------------------------------------------------------------- /SA-Mitigation/default/indexes.conf: -------------------------------------------------------------------------------- 1 | [mitigation] 2 | homePath = $SPLUNK_DB/mitigationdb/db 3 | coldPath = $SPLUNK_DB/mitigationdb/colddb 4 | thawedPath = $SPLUNK_DB/mitigationdb/thaweddb 5 | tstatsHomePath = volume:_splunk_summaries/mitigationdb/datamodel_summary 6 | maxMemMB = 20 7 | maxConcurrentOptimizes = 6 8 | maxHotIdleSecs = 86400 9 | maxHotBuckets = 10 10 | maxDataSize = auto_high_volume 11 | 12 | [mitigation_summary] 13 | homePath = $SPLUNK_DB/mitigation_summarydb/db 14 | coldPath = $SPLUNK_DB/mitigation_summarydb/colddb 15 | thawedPath = $SPLUNK_DB/mitigation_summarydb/thaweddb 16 | -------------------------------------------------------------------------------- /SA-Mitigation/default/inputs.conf: -------------------------------------------------------------------------------- 1 | [monitor://$SPLUNK_HOME/etc/apps/SA-Mitigation/logs/mitigator.log] 2 | sourcetype=mitigation 3 | index = mitigation 4 | -------------------------------------------------------------------------------- /SA-Mitigation/default/pan.conf: -------------------------------------------------------------------------------- 1 | #sets configuration parameters for Palo Alto 2 | # Currently does not support multiple vsys and or groing through proxies 3 | 4 | [PAN] # please do not change this might break things 5 | IP = '192.168.4.100' # ip address of palo alto 6 | GROUP = 'badActors' # name of group to drop blocked ips in 7 | 8 | -------------------------------------------------------------------------------- /SA-Mitigation/default/savedsearches.conf: -------------------------------------------------------------------------------- 1 | [Network - Mitigation High Confidence IDS - Rule] 2 | action.email.reportServerEnabled = 0 3 | action.keyindicator.invert = 0 4 | action.summary_index = 1 5 | action.summary_index._name = notable 6 | action.summary_index.ttl = 1p 7 | alert.suppress = 1 8 | alert.suppress.fields = src 9 | alert.suppress.period = 86300 10 | alert.track = 0 11 | counttype = number of events 12 | cron_schedule = */1 * * * * 13 | dispatch.earliest_time = -24h 14 | dispatch.latest_time = +0s 15 | enableSched = 1 16 | quantity = 0 17 | realtime_schedule = 0 18 | relation = greater than 19 | search = | tstats `summariesonly` count from datamodel=Intrusion_Detection where earliest=-24h@h latest=+0s (IDS_Attacks.severity=critical OR IDS_Attacks.severity=high IDS_Attacks.src!=0.0.0.0 IDS_Attacks.src!="00:*") by IDS_Attacks.src,IDS_Attacks.dest,sourcetype,host| rename IDS_Attacks.src AS src | regex src="^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" | rename IDS_Attacks.dest AS dest | rename sourcetype as orig_sourcetype | rename host as orig_host | table orig_sourcetype,orig_host,dest,src,count | sort - count 20 | 21 | [Endpoint - Mitigation High Confidence Registry - Rule] 22 | action.email.reportServerEnabled = 0 23 | action.keyindicator.invert = 0 24 | action.summary_index = 1 25 | action.summary_index._name = notable 26 | action.summary_index.ttl = 1p 27 | alert.suppress = 1 28 | alert.suppress.fields = host,pid,process_name 29 | alert.suppress.period = 86300 30 | alert.track = 0 31 | counttype = number of events 32 | cron_schedule = */1 * * * * 33 | dispatch.earliest_time = -48h 34 | dispatch.latest_time = +0s 35 | enableSched = 1 36 | quantity = 0 37 | realtime_schedule = 0 38 | relation = greater than 39 | search = sourcetype="winregistry" key_path="*\\windows\\currentversion\\run*" data="*.vbs" | rename sourcetype as orig_sourcetype | rename host as orig_host | table orig_sourcetype,orig_host,dest,status,pid,process_image,key_path,data 40 | 41 | [Master Mitigation - Network] 42 | cron_schedule = */1 * * * * 43 | description = Search that find all network items to mitigation and puts the block in place. Also keeps track of what is being mitigated in mitigation_network lookup 44 | dispatch.earliest_time = -1h 45 | dispatch.latest_time = now 46 | display.events.fields = ["host","source","sourcetype","tag","src_country","src","dest","Notable_Events_Meta.rule_id"] 47 | display.general.type = statistics 48 | display.visualizations.show = 0 49 | enableSched = 1 50 | search = index=notable source="Network - Mitigation*" | eval id=splunk_server."@@".index."@@".md5(_time._raw) | rename dest as system | table id,orig_sourcetype,orig_host,src,system | collect index=mitigation addtime=true marker="type=network,status=submitted,action=block" | blocknetwork action=block device=10.0.0.1 vsys=vsys1 group=BADACTORS 51 | #old search 52 | #search = index=notable source="Network - Mitigation*" | eval status="submitted" | eval action="block" | eval type="network" | rename Notable_Events_Meta.rule_id as id| table id,orig_sourcetype,orig_host,src,dest,action,status,pid,type | collect index=mitigation_summary addtime=true | blocknetwork action=block device=10.0.0.1 vsys=vsys1 group=BADACTORS 53 | 54 | [Master Mitigation - Endpoint] 55 | cron_schedule = */1 * * * * 56 | description = Search that find all network items to mitigation and puts the block in place. Also keeps track of what is being mitigated in mitigation_network lookup 57 | dispatch.earliest_time = -1h 58 | dispatch.latest_time = now 59 | display.events.fields = ["host","source","sourcetype","tag","src_country","src","dest","Notable_Events_Meta.rule_id", "pid"] 60 | display.general.type = statistics 61 | display.visualizations.show = 0 62 | enableSched = 1 63 | search = index=notable source="Endpoint - Mitigation*" | eval id=splunk_server."@@".index."@@".md5(_time._raw) | rename dest as system | table id,orig_sourcetype,orig_host,src,system,pid,process_image,key_path,data | collect index=mitigation_summary addtime=true marker="type=endpoint,status=submitted,action=block" | blockendpoint pid=pid system=system 64 | #old search we were using 65 | #search = index=notable source="Endpoint - Mitigation*" | eval status="submitted" | eval action="block" | eval type="endpoint" | rename Notable_Events_Meta.rule_id as id| rename dest as system | blockendpoint pid=pid system=system | table id,orig_sourcetype,orig_host,src,dest,action,status,pid,process_image,key_path,type,data | collect index=mitigation addtime=true 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /SA-Mitigation/default/searchbnf.conf: -------------------------------------------------------------------------------- 1 | ################## 2 | # mitigator 3 | ################## 4 | [blockendpoint-command] 5 | syntax = blockendpoint (pid=)* (system=)* 6 | shortdesc = Kills a process on a remote machine 7 | description = Must specify a hostname and PID 8 | usage = public 9 | example1 = blockendpoint pid=1234 system=10.0.0.1 10 | comment1 = blocks process 1234 on remote host 10.0.0.1 11 | related = blocknetwork 12 | tags = mitigate block endpoint 13 | 14 | [blocknetwork-command] 15 | syntax = blocknetwork (action=)* (device=)* (vsys=)* (group=)* 16 | shortdesc = Sends an IP address to Palo Alto to be placed under a block group. 17 | description = Must specify the device IP (device), the vsys (vsys), the action (action), and finally which block group to put the IP address in (group). 18 | usage = public 19 | example1 = blocknetwork action=block device=10.0.0.1 vsys=vsys1 group=BADACTORS 20 | comment1 = blocks any IP address passed to this command by placing them in group BADACTORs. Group needs to be configured in the Palo Alto FW as blocking. 21 | related = blockendpoint, panblock 22 | tags = mitigate block network 23 | 24 | -------------------------------------------------------------------------------- /SA-Mitigation/default/transforms.conf: -------------------------------------------------------------------------------- 1 | [mitigation_network] 2 | filename = mitigation_network.csv 3 | case_sensitive_match = false 4 | -------------------------------------------------------------------------------- /SA-Mitigation/local/app.conf: -------------------------------------------------------------------------------- 1 | [credential:LWF:admin:] 2 | password = $1$+/Ox7ASEXpT2WsM= 3 | -------------------------------------------------------------------------------- /SA-Mitigation/lookups/mitigation.csv.default: -------------------------------------------------------------------------------- 1 | #Intentionally left empty make modular input of this to calculate the other 2 mitigation_*.csv lookups 2 | #id = ID of notable event 3 | #ioc = indicator which will be mitigated this lookup table is then broken up per indicator (ip/runkeys/etc.) 4 | #status = failed or successful - if it was mitigated or not 5 | id,ioc,status 6 | -------------------------------------------------------------------------------- /SA-Mitigation/lookups/mitigation_endpoint.csv: -------------------------------------------------------------------------------- 1 | #id = ID of notable event 2 | #regkey = registry key to mitigate on 3 | #status = failed or successful - if it was mitigated or not 4 | id,regkey,status 5 | -------------------------------------------------------------------------------- /SA-Mitigation/lookups/mitigation_endpoint.csv.default: -------------------------------------------------------------------------------- 1 | #id = ID of notable event 2 | #regkey = registry key to mitigate on 3 | #status = failed or successful - if it was mitigated or not 4 | id,regkey,status 5 | -------------------------------------------------------------------------------- /SA-Mitigation/lookups/mitigation_network.csv: -------------------------------------------------------------------------------- 1 | id,src,status,time 2 | "maquina.local@@notable@@4bc9cf3558ca18f9536f524097b6f09a","96.44.226.43",submitted,1410322200 3 | "maquina.local@@notable@@aea852f8a38071662f64456f06bf8e50","95.106.229.220",submitted,1410322200 4 | "maquina.local@@notable@@3a81fd1d3d0ac6d8583f3a75496597b5","90.86.109.191",submitted,1410322200 5 | "maquina.local@@notable@@ce87540c1a6e514ad1b1960e102d2a40","90.77.58.235",submitted,1410322200 6 | "maquina.local@@notable@@52f363c4316b9b1b3dd326b82c331ca1","69.74.142.131",submitted,1410322200 7 | "maquina.local@@notable@@5df20e3752d491dd9558271426e20d4f","67.228.139.118",submitted,1410322200 8 | "maquina.local@@notable@@4fed7066699f6834d91f02de6bf0feeb","59.60.235.251",submitted,1410322200 9 | "maquina.local@@notable@@a81206481c6a61592e36132b0665f49b","57.206.75.55",submitted,1410322200 10 | "maquina.local@@notable@@dc8891bde3d7cc162551e70b7e8934fb","55.155.183.174",submitted,1410322200 11 | "maquina.local@@notable@@7db2a3a4abf99e469aa945a21f6cd48b","47.149.190.108",submitted,1410322200 12 | "maquina.local@@notable@@865538efb5a32cb5ba49e7d36a2e5b72","47.107.105.110",submitted,1410322200 13 | "maquina.local@@notable@@b249b906d2680a5f1154bb9746b6915b","44.236.254.45",submitted,1410322200 14 | "maquina.local@@notable@@20a5b10e16c2bae423566804eb1974f3","43.155.21.76",submitted,1410322200 15 | "maquina.local@@notable@@e6060e0f44d8735ae10751365b07b828","255.86.116.223",submitted,1410322200 16 | "maquina.local@@notable@@99bac8e98d322f7a82b6aace0048b44a","247.220.184.112",submitted,1410322200 17 | "maquina.local@@notable@@f0455bc6dac3016e1735d6ef993a65a6","234.220.221.111",submitted,1410322200 18 | "maquina.local@@notable@@5ae444ce643f5fffdae2cee6523aaff3","233.205.111.93",submitted,1410322200 19 | "maquina.local@@notable@@44e54ce5d5719d012b61b7febae9947d","225.212.85.229",submitted,1410322200 20 | "maquina.local@@notable@@7ae8aed528ab0fdce53678bb9a5485ca","218.108.43.117",submitted,1410322200 21 | "maquina.local@@notable@@793a6eb6da6b78810dcc2c1bf4acfb46","213.185.100.178",submitted,1410322200 22 | "maquina.local@@notable@@d43f42c9bcb585495a7fb786dbb9aa38","211.247.75.203",submitted,1410322200 23 | "maquina.local@@notable@@a51f83fb993ba81e5ca8575c217f6744","211.169.204.162",submitted,1410322200 24 | "maquina.local@@notable@@bf0d79d0751d5d920982a207b4d44dff","207.122.211.168",submitted,1410322200 25 | "maquina.local@@notable@@c8cd7f5235625cfa48f27ff6c02e1b25","205.187.245.187",submitted,1410322200 26 | "maquina.local@@notable@@25a36a8ec97047892f080584cc4f10f3","202.87.243.241",submitted,1410322200 27 | "maquina.local@@notable@@b64e5132dc1dc7efb3c7cf20c1562790","202.79.207.134",submitted,1410322200 28 | "maquina.local@@notable@@d3ec185f57c276452f46bc402a95a6a6","192.168.96.67",submitted,1410322200 29 | "maquina.local@@notable@@599d36d655bdc06ae357c37787efde44","192.168.31.247",submitted,1410322200 30 | "maquina.local@@notable@@01ec916d6d796758b95c5f377407c844","189.207.214.112",submitted,1410322200 31 | "maquina.local@@notable@@7bb02bd88e566b0cd5e62bcf189962d4","184.101.203.90",submitted,1410322200 32 | "maquina.local@@notable@@4adec38f97fdee8d9ca95b6217f0578f","17.241.150.106",submitted,1410322200 33 | "maquina.local@@notable@@ad14bb69f58a4d0dc95812ab6f954f0e","17.18.19.6",submitted,1410322200 34 | "maquina.local@@notable@@9a2d33c128eed894928d254f48e0c38d","17.18.19.5",submitted,1410322200 35 | "maquina.local@@notable@@c6205e27d0e8a52cdd4124bbae80caab","17.18.19.21",submitted,1410322200 36 | "maquina.local@@notable@@6f3ea972da6a7b5cdfa7172b3952e04c","17.18.19.20",submitted,1410322200 37 | "maquina.local@@notable@@2704e828dddbabe8ce5ae5ef56187de2","168.162.223.148",submitted,1410322200 38 | "maquina.local@@notable@@e5a91dc4e40aa6291ada4c7a9123b57e","160.221.80.74",submitted,1410322200 39 | "maquina.local@@notable@@8e7560b43eb2fa00826d91850e07e9a1","158.138.219.125",submitted,1410322200 40 | "maquina.local@@notable@@2b842eab14e5f1c82fbfdde9194cb55c","148.167.77.93",submitted,1410322200 41 | "maquina.local@@notable@@4cf62f7e930d69cc3d7e540cbb8a713f","129.17.73.122",submitted,1410322200 42 | "maquina.local@@notable@@a96afb11132b62bc0e0d9067c7edb8e7","124.254.205.166",submitted,1410322200 43 | "maquina.local@@notable@@25cdb06d0f297afe472c7bd4eef44861","123.111.73.166",submitted,1410322200 44 | "maquina.local@@notable@@fec28328e6798918ccb62c3aef170c50","123.111.153.227",submitted,1410322200 45 | "maquina.local@@notable@@1b9325add9b3ce67e87805508d2b57e9","117.178.100.5",submitted,1410322200 46 | "maquina.local@@notable@@0e7cfe2ddf2fd3fd24942afe535436e1","111.77.83.117",submitted,1410322200 47 | "maquina.local@@notable@@05e712835e9d72351541b779ae7224a2","101.118.78.175",submitted,1410322200 48 | -------------------------------------------------------------------------------- /SA-Mitigation/lookups/mitigation_network.csv.default: -------------------------------------------------------------------------------- 1 | #id = ID of notable event 2 | #ip = network ip to block traffic from 3 | #status = failed or successful - if it was mitigated or not 4 | #time = time it was mitigated 5 | id,ip,status,time 6 | -------------------------------------------------------------------------------- /SA-Mitigation/metadata/default.meta: -------------------------------------------------------------------------------- 1 | 2 | # Application-level permissions 3 | 4 | [] 5 | access = read : [ * ], write : [ admin, power ] 6 | 7 | ### EVENT TYPES 8 | 9 | [eventtypes] 10 | export = system 11 | 12 | 13 | ### PROPS 14 | 15 | [props] 16 | export = system 17 | 18 | 19 | ### TRANSFORMS 20 | 21 | [transforms] 22 | export = system 23 | 24 | 25 | ### LOOKUPS 26 | 27 | [lookups] 28 | export = system 29 | 30 | 31 | ### VIEWSTATES: even normal users should be able to create shared viewstates 32 | 33 | [viewstates] 34 | access = read : [ * ], write : [ * ] 35 | export = system 36 | -------------------------------------------------------------------------------- /SA-Mitigation/metadata/default.meta.SplunkESSuite: -------------------------------------------------------------------------------- 1 | 2 | ## SplunkEnterpriseSecuritySuite Application-level permissions 3 | [event_renderers] 4 | export = none 5 | 6 | ## per SOLNPCI-297 renaming 'ess_correlation_search_edit' -> 'correlation_search_edit' 7 | ## and setting exportation to local 8 | [views/correlation_search_edit] 9 | export = none 10 | 11 | ## The following export=none allows for general suppression definitions: 12 | ## 'ess_notable_supppression_new' -> 'notable_suppression_new' 13 | [views/notable_suppression_new] 14 | export = none 15 | 16 | ## Don't export the workflow actions since other apps will not have the notable editor and we don't 17 | ## want to redirect the users to an inaccessible view. 18 | ## Furthermore, we don't want to list the workflow actions twice if the customer has both ES and PCI 19 | [workflow_actions] 20 | export = none 21 | 22 | # Import the Domain Addons for ES. Note that these DA's will import the Supporting Addons. 23 | [] 24 | import = DA-ESS-AccessProtection,DA-ESS-EndpointProtection,DA-ESS-IdentityManagement,DA-ESS-NetworkProtection,SA-Mitigator 25 | ## shared Application-level permissions 26 | [] 27 | access = read : [ * ], write : [ admin ] 28 | export = system 29 | 30 | [savedsearches] 31 | owner = admin 32 | 33 | [governance] 34 | access = read : [ * ], write : [ * ] 35 | 36 | ## Postprocess 37 | [postprocess] 38 | access = read : [ * ], write : [ * ] 39 | 40 | 41 | ## Exclude export of custom alert actions 42 | [alert_actions/email] 43 | export = none 44 | -------------------------------------------------------------------------------- /images/SA-Mitigation-Endpoint-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/Splunk-Mitigation-Framework/e973cdb9656a7d1abcef4b2b2e3c9b12b3710e39/images/SA-Mitigation-Endpoint-arch.png -------------------------------------------------------------------------------- /images/SA-Mitigation_search_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/Splunk-Mitigation-Framework/e973cdb9656a7d1abcef4b2b2e3c9b12b3710e39/images/SA-Mitigation_search_arch.png -------------------------------------------------------------------------------- /prezo/Auto Mitigation - Endpoint Example.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/Splunk-Mitigation-Framework/e973cdb9656a7d1abcef4b2b2e3c9b12b3710e39/prezo/Auto Mitigation - Endpoint Example.mp4 -------------------------------------------------------------------------------- /prezo/confPrezo.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josehelps/Splunk-Mitigation-Framework/e973cdb9656a7d1abcef4b2b2e3c9b12b3710e39/prezo/confPrezo.pptx -------------------------------------------------------------------------------- /setup.xml.txt: -------------------------------------------------------------------------------- 1 | 2 | remind user to setup index under role 3 | remind user to configure searches 4 | include SA-Mitigation as part of ES pieces 5 | remind user to make sure host can resolve when sending command 6 | recreate the dashboard views in ES 7 | --------------------------------------------------------------------------------