import splunklib.client as client
import splunklib.results as results
from time import sleep
from datetime import datetime, timedelta
import getpass
HOST = "localhost"
USERNAME = "admin"
PORT=8089
PASSWORD = getpass.getpass()
targetIndex = "sysmon" # The name of the index with the sysmon data...
targetSource = "SysmonEventID1.csv"
targetHost = "importCSV" # The name of the host with the data from the above index...
targetGuid = "{YOUR-GUID-HERE}"
eventTime = "2019-03-31T15:46:07"
targetTime = datetime.strptime(eventTime, "%Y-%m-%dT%H:%M:%S")
targetTime -= timedelta(minutes=1)
earliestTime = "%s/%s/%s:%s:%s:00" % (str(targetTime.month), str(targetTime.day), str(targetTime.year), str(targetTime.hour), str(targetTime.minute))
targetTime += timedelta(minutes=10)
latestTime = "%s/%s/%s:%s:%s:00" % (str(targetTime.month), str(targetTime.day), str(targetTime.year), str(targetTime.hour), str(targetTime.minute))
searchFragment = "index=%s host=%s earliest=%s latest=%s (ProcessGuid=%s OR ParentProcessGuid=%s) " % (
targetIndex, targetHost, earliestTime, latestTime, targetGuid, targetGuid)
# Define a Splunk Query Function (This gets called in recursion)...
def ExecuteSplunkQuery(splunkSearch):
searchQuery_normal = splunkSearch # This is the argument that gets passed to the function...
kwArgs_normalSearch = {"exec_mode": "normal", "count": 0} # Don't limit the returned results...
service = client.connect(
host=HOST,
port=PORT,
app="search",
username=USERNAME,
password=PASSWORD)
# Get the collection of search jobs and create new job...
jobs = service.jobs
job = jobs.create(searchQuery_normal, **kwArgs_normalSearch)
# We are executing a non-blocking search so we must wait and poll job to see when done...
while not job.is_done():
print("Waiting for job %s to complete...") % str(job)
sleep(2) # Wait 2 seconds and test again...
# Count search results. If zero, set no results flag...
resultCount = job["resultCount"] # This is a dictionary attribute of the job itself...
if (resultCount == "0"):
statusCode = 1
else:
statusCode = 0
# Get search results and return them as ResultsReader...
searchResults = results.ResultsReader(job.results(**kwArgs_normalSearch))
job.cancel()
return statusCode, searchResults
# First need to build function to create descendant queries from EventCode=1 sysmon events...
def BuildProcessDescendantSearch(guidList = []):
# Function argument is a list created from previous searches...
numGuids = len(guidList)
print "Found %i unique processGuid's. Finding descendants..." % numGuids
searchFragment = ""
for n in range(numGuids):
if (n == numGuids-1):
searchFragment += "ParentProcessGuid=%s" % guidList[n]
else:
searchFragment += "ParentProcessGuid=%s OR " % guidList[n]
return searchFragment
# This function will build the final query...
def BuildProcessQueryString(guidList = []):
numGuids = len(guidList)
searchFragment = ""
for n in range(numGuids):
if (n == numGuids - 1):
searchFragment += "ProcessGuid=%s" % guidList[n]
else:
searchFragment += "ProcessGuid=%s OR " % guidList[n]
return searchFragment
################
# Begin iteration search. The initial fragment was defined up top...
################
seedQuery = "search EventCode=1 %s | stats count BY ProcessGuid, ParentProcessGuid | fields - count" % searchFragment
statusFlag = 0 # This is set to 1 in the ExecuteSplunkQuery when no results are returned../
descendantCount = 0
parentProcessDictionary = {} # This dictionary will contain the unique Process/ParentProcess Guids
print "Executing seedQuery: %s" % seedQuery
statusFlag, resultsReader = ExecuteSplunkQuery(seedQuery)
# This is the iteration loop that builds the chain...
while (statusFlag != 1):
processGUIDList =[] # This will be a list process dictionaries
for result in resultsReader:
# Note dictionary structure {'ProcessGuid':'ParentProcessGuid'}
parentProcessDictionary[result.get('ProcessGuid', 'None')] = result.get('ParentProcessGuid', 'None')
processGUIDList.append(result.get('ProcessGuid', 'None'))
newSearchFragment = BuildProcessDescendantSearch(processGUIDList)
searchQuery = "search index=%s host=%s earliest=%s latest=%s (%s) | stats count BY ProcessGuid, ParentProcessGuid | fields - count" % (targetIndex, targetHost, earliestTime, latestTime, newSearchFragment)
print "New derived query: %s" % searchQuery
statusFlag, resultsReader = ExecuteSplunkQuery(searchQuery)
descendantCount += 1
print "Total descendant process generations found: %i" % descendantCount
# To construct final query, use keys from the processDictionary...
processList = parentProcessDictionary.keys()
finalSearchFragment = BuildProcessQueryString(processList)
finalQuery = "search index=%s host=%s earliest=%s latest=%s (%s) | table ParentProcessGuid, ParentCommandLine, EventDescription, ProcessGuid, CommandLine" % (targetIndex, targetHost, earliestTime, latestTime, finalSearchFragment)
print "Final sysmon chain query: %s" % finalQuery
statusFlag, resultsReader = ExecuteSplunkQuery(finalQuery)
for result in resultsReader:
print ">>>" + str(result)
... View more