Skip to content

Commit

Permalink
backport of sysmon, + aux conf propagate to vm partially
Browse files Browse the repository at this point in the history
backport of Fernando's cuckoosandbox/cuckoo#2518

(cherry picked from commit ad183ba)
  • Loading branch information
doomedraven authored and me committed Oct 24, 2018
1 parent 4e97162 commit 3730252
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
56 changes: 56 additions & 0 deletions analyzer/windows/modules/auxiliary/curtain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import os
import time
import logging
from threading import Thread

from lib.common.abstracts import Auxiliary
from lib.common.results import upload_to_host

log = logging.getLogger(__name__)

__author__ = "Jeff White [karttoon] @noottrak"
__email__ = "jwhite@paloaltonetworks.com"
__version__ = "1.0.3"
__date__ = "21FEB2018"

class Curtain(Thread, Auxiliary):

def __init__(self, options={}, config=None):
Thread.__init__(self)
Auxiliary.__init__(self, options, config)
self.do_run = options.get("curtain", {}).get("enabled", False)
self.enabled = options.get("curtain", {}).get("enabled", False)

def collectLogs(self):
try:
os.system("C:\\Windows\\System32\\wevtutil.exe query-events microsoft-windows-powershell/operational /rd:true /e:root /format:xml /uni:true > C:\\curtain.log")
except Exception as e:
log.error("Curtain - Error collecting PowerShell events - %s " % e)

time.sleep(5)

if os.path.exists("C:\\curtain.log"):
upload_to_host("C:\\curtain.log", "curtain/%s.curtain.log" % time.time(), False)
else:
log.error("Curtain log file not found!")

def clearLogs(self):
try:
os.system("C:\\Windows\\System32\\wevtutil.exe clear-log microsoft-windows-powershell/operational")
except Exception as e:
log.error("Curtain - Error clearing PowerShell events - %s" % e)

def run(self):
if self.enabled:
self.clearLogs()
while self.do_run:
self.collectLogs()
time.sleep(15)
return True
return False

def stop(self):
if self.enabled:
self.collectLogs()
return True
return False
60 changes: 60 additions & 0 deletions analyzer/windows/modules/auxiliary/sysmon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import logging
import os
import time
import threading

from lib.common.abstracts import Auxiliary
from lib.common.results import upload_to_host

log = logging.getLogger(__name__)

__author__ = "@FernandoDoming"
__version__ = "1.0.0"

class Sysmon(threading.Thread, Auxiliary):

def __init__(self, options={}, analyzer=None):
threading.Thread.__init__(self)
Auxiliary.__init__(self, options, analyzer)
self.do_run = options.get("sysmon", {}).get("enabled", False)
self.enabled = options.get("sysmon", {}).get("enabled", False)

def clear_log(self):
try:
os.system("C:\\Windows\\System32\\wevtutil.exe clear-log microsoft-windows-sysmon/operational")
except Exception as e:
log.error("Error clearing Sysmon events - %s" % e)


def collect_logs(self):
try:
os.system("C:\\Windows\\System32\\wevtutil.exe query-events "\
"microsoft-windows-sysmon/operational /format:xml /e:Events > C:\\sysmon.xml")
except Exception as e:
log.error("Could not create sysmon log file - %s" % e)

# Give it some time to create the file
time.sleep(5)

if os.path.exists("C:\\sysmon.xml"):
upload_to_host("C:\\sysmon.xml", "sysmon/%s.sysmon.xml" % time.time())
else:
log.error("Sysmon log file not found in guest machine")


def run(self):
if self.enabled:
self.clear_log()
while self.do_run:
self.collect_logs()
time.sleep(15)

return True
return False

def stop(self):
if self.enabled:
self.do_run = False
self.collect_logs()
return True
return False
5 changes: 5 additions & 0 deletions lib/cuckoo/core/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def __init__(self, task, error_queue):
self.task = task
self.errors = error_queue
self.cfg = Config()
self.aux_cfg = Config("auxiliary")
self.storage = ""
self.binary = ""
self.machine = None
Expand Down Expand Up @@ -221,6 +222,10 @@ def build_options(self):
except:
pass

# options from auxiliar.conf
options["curtain"] = self.aux_cfg.curtain.enabled
options["sysmon"] = self.aux_cfg.sysmon.enabled

return options

def launch_analysis(self):
Expand Down
67 changes: 67 additions & 0 deletions modules/processing/sysmon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import logging, os, re
import xml.etree.ElementTree as ET
import xmltodict

from lib.cuckoo.common.abstracts import Processing
from lib.cuckoo.common.exceptions import CuckooProcessingError

log = logging.getLogger(__name__)

__author__ = "@FernandoDoming"
__version__ = "1.0.0"

class Sysmon(Processing):

def remove_noise(self, data):
filtered_proc_creations_re = [
r"C:\\Windows\\System32\\wevtutil\.exe\s+clear-log\s+microsoft-windows-(sysmon|powershell)\/operational",
r"bin\\is32bit.exe",
r"bin\\inject-(?:x86|x64).exe",
r"C:\\Windows\\System32\\wevtutil.exe\s+query-events microsoft-windows-powershell\/operational\s+\/rd:true\s+\/e:root\s+\/format:xml\s+\/uni:true",
r"C:\\Windows\\System32\\wevtutil.exe\s+query-events\s+microsoft-windows-sysmon\/operational\s+\/format:xml",
]

filtered = []
for event in data:
is_filtered = False
if event["System"]["EventID"] == "1":
for p in filtered_proc_creations_re:
cmdline = event["EventData"]["Data"][9]["#text"]
if re.search(p, cmdline):
log.info("Supressed %s because it is noisy" % cmdline)
is_filtered = True

if not is_filtered:
filtered.append(event)

return filtered

def run(self):
self.key = "sysmon"

# Determine oldest sysmon log and remove the rest
lastlog = os.listdir("%s/sysmon/" % self.analysis_path)
lastlog.sort()
lastlog = lastlog[-1]
# Leave only the most recent file
for f in os.listdir("%s/sysmon/" % self.analysis_path):
if f != lastlog:
try:
os.remove("%s/sysmon/%s" % (self.analysis_path, f))
except:
log.error("Failed to remove sysmon file log %s" % f)

os.rename(
"%s/sysmon/%s" % (self.analysis_path, lastlog),
"%s/sysmon/sysmon.xml" % self.analysis_path
)

data = None
try:
xml = open("%s/sysmon/sysmon.xml" % self.analysis_path).read()
xml = xml.decode("latin1").encode("utf8")
data = xmltodict.parse(xml)["Events"]["Event"]
except Exception as e:
raise CuckooProcessingError("Failed parsing sysmon.xml: %s" % e.message)

return self.remove_noise(data)

0 comments on commit 3730252

Please sign in to comment.