Skip to content

Commit

Permalink
Merge branch 'master' into patch-2
Browse files Browse the repository at this point in the history
  • Loading branch information
Neo23x0 authored May 24, 2018
2 parents 9a45fda + 1b4714a commit 9cd7143
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 219 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ signature-base
tools/old-results
build
private-signatures
rules
rules.key
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Additional Checks:
3. SWF decompressed scan (new since version v0.8)
4. SAM dump check
5. DoublePulsar check - tries to detect DoublePulsar backdoor on port 445/tcp and 3389/tcp
6. [PE-Sieve](https://github.com/hasherezade/pe-sieve) process check
6. [PE-Sieve](https://hshrzd.wordpress.com/pe-sieve/) process check

The Windows binary is compiled with PyInstaller 2.1 and should run as x86 application on both x86 and x64 based systems.

Expand Down
15 changes: 13 additions & 2 deletions lib/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ def setNice(logger):
try:
pid = os.getpid()
p = psutil.Process(pid)
logger.log("INFO", "Setting LOKI process with PID: %s to priority IDLE" % pid)
logger.log("INFO", "Init", "Setting LOKI process with PID: %s to priority IDLE" % pid)
p.nice(psutil.IDLE_PRIORITY_CLASS)
return 1
except Exception, e:
if logger.debug:
traceback.print_exc()
logger.log("ERROR", "Error setting nice value of THOR process")
logger.log("ERROR", "Init", "Error setting nice value of THOR process")
return 0


Expand Down Expand Up @@ -310,3 +310,14 @@ def _kill_process_after_a_timeout(pid):
kill_check.clear()

return output, returnCode

def getHostname(os_platform):
"""
Generate and return a hostname
:return:
"""
# Computername
if os_platform == "linux" or os_platform == "osx":
return os.uname()[1]
else:
return os.environ['COMPUTERNAME']
43 changes: 43 additions & 0 deletions lib/levenshtein.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
# -*- coding: utf-8 -*-
#
# Levenshtein related functions

CHECK_FILES = ['svchost.exe', 'explorer.exe', 'iexplore.exe', 'lsass.exe', 'chrome.exe', 'csrss.exe', 'firefox.exe',
'winlogon.exe']

class LevCheck():

def __init__(self):
pass

def check(self, fileName):
"""
Check if file name is very similar to a file in the check list
:param fileName:
:return:
"""
for checkFile in CHECK_FILES:
if levenshtein(checkFile, fileName) == 1:
return checkFile
return None

def levenshtein(s, t):
if s == t: return 0
elif len(s) == 0: return len(t)
elif len(t) == 0: return len(s)
v0 = [None] * (len(t) + 1)
v1 = [None] * (len(t) + 1)
for i in range(len(v0)):
v0[i] = i
for i in range(len(s)):
v1[0] = i + 1
for j in range(len(t)):
cost = 0 if s[i] == t[j] else 1
v1[j + 1] = min(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost)
for j in range(len(v0)):
v0[j] = v1[j]

return v1[len(t)]

23 changes: 13 additions & 10 deletions lib/lokilogger.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import socket
from helpers import removeNonAsciiDrop

__version__ = '0.26.0'
__version__ = '0.28.0'

# Logger Class -----------------------------------------------------------------
class LokiLogger():
Expand All @@ -32,14 +32,15 @@ class LokiLogger():
linesep = "\n"

def __init__(self, no_log_file, log_file, hostname, remote_host, remote_port, csv, only_relevant, debug, platform, caller):
self.version = __version__
self.no_log_file = no_log_file
self.log_file = log_file
self.hostname = hostname
self.csv = csv
self.only_relevant = only_relevant
self.debug = debug
self.caller = caller
if platform == "windows":
if "windows" in platform.lower():
self.linesep = "\r\n"

# Colorization ----------------------------------------------------
Expand All @@ -58,7 +59,7 @@ def __init__(self, no_log_file, log_file, hostname, remote_host, remote_port, cs
self.remote_logger.addHandler(remote_syslog_handler)
self.remote_logging = True

def log(self, mes_type, message):
def log(self, mes_type, module, message):

# Remove all non-ASCII characters
# message = removeNonAsciiDrop(message)
Expand All @@ -81,7 +82,7 @@ def log(self, mes_type, message):

# to file
if not self.no_log_file:
self.log_to_file(message, mes_type)
self.log_to_file(message, mes_type, module)

# to stdout
try:
Expand All @@ -92,7 +93,7 @@ def log(self, mes_type, message):

# to syslog server
if self.remote_logging:
self.log_to_remotesys(message, mes_type)
self.log_to_remotesys(message, mes_type, module)

def log_to_stdout(self, message, mes_type):
# check tty encoding
Expand Down Expand Up @@ -171,23 +172,25 @@ def log_to_stdout(self, message, mes_type):
sys.exit(1)
print ("Cannot print to cmd line - formatting error")

def log_to_file(self, message, mes_type):
def log_to_file(self, message, mes_type, module):
try:
# Write to file
with codecs.open(self.log_file, "a", encoding='utf-8') as logfile:
if self.csv:
logfile.write(u"{0},{1},{2},{3}{4}".format(getSyslogTimestamp(), self.hostname, mes_type,message, self.linesep))
logfile.write(u"{0},{1},{2},{3},{4}{5}".format(
getSyslogTimestamp(), self.hostname, mes_type, module, message, self.linesep))
else:
logfile.write(u"%s %s LOKI: %s: %s%s" % (getSyslogTimestamp(), self.hostname, mes_type.title(), message, self.linesep))
logfile.write(u"%s %s LOKI: %s: MODULE: %s MESSAGE: %s%s" %
(getSyslogTimestamp(), self.hostname, mes_type.title(), module, message, self.linesep))
except Exception as e:
if self.debug:
traceback.print_exc()
sys.exit(1)
print("Cannot print line to log file {0}".format(self.log_file))

def log_to_remotesys(self, message, mes_type):
def log_to_remotesys(self, message, mes_type, module):
# Preparing the message
syslog_message = "LOKI: {0}: {1}".format(mes_type.title(), message)
syslog_message = "LOKI: {0}: MODULE: {1} MESSAGE: {2}".format(mes_type.title(), module, message)
try:
# Mapping LOKI's levels to the syslog levels
if mes_type == "NOTICE":
Expand Down
45 changes: 16 additions & 29 deletions lib/pesieve.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import os
import sys
import json
import traceback

from lib.lokilogger import *
Expand All @@ -27,10 +28,10 @@ def __init__(self, workingDir, is64bit, logger):

if self.isAvailable():
self.active = True
self.logger.log("NOTICE", "PE-Sieve successfully initialized BINARY: {0} "
self.logger.log("NOTICE", "PESieve", "PE-Sieve successfully initialized BINARY: {0} "
"SOURCE: https://github.com/hasherezade/pe-sieve".format(self.peSieve))
else:
self.logger.log("NOTICE", "Cannot find PE-Sieve in expected location {0} "
self.logger.log("NOTICE", "PESieve", "Cannot find PE-Sieve in expected location {0} "
"SOURCE: https://github.com/hasherezade/pe-sieve".format(self.peSieve))

def isAvailable(self):
Expand All @@ -39,7 +40,7 @@ def isAvailable(self):
:return:
"""
if not os.path.exists(self.peSieve):
self.logger.log("DEBUG", "PE-Sieve not found in location '{0}' - "
self.logger.log("DEBUG", "PESieve", "PE-Sieve not found in location '{0}' - "
"feature will not be active".format(self.peSieve))
return False
return True
Expand All @@ -51,34 +52,20 @@ def scan(self, pid):
:return hooked, replaces, suspicious: number of findings per type
"""
# Presets
hooked = 0
replaced = 0
suspicious = 0
results = {"hooked": 0, "replaced": 0, "detached": 0, "implanted": 0}
# Compose command
command = [self.peSieve, '/pid', str(pid), '/nodump', '/quiet']
command = [self.peSieve, '/pid', str(pid), '/ofilter', '2', '/quiet', '/json']
# Run PE-Sieve on given process
output, returnCode = runProcess(command)

# Process the output
lines = output.splitlines()
start_summary = False
for line in lines:
try:
# Debug output
results_raw = json.loads(output)
results = results_raw["scanned"]["modified"]
if self.logger.debug:
if "SUMMARY:" in line:
start_summary = True
if start_summary:
print(line)
# Extract the integer values
result_hooked = re.search(r'Hooked:[\s\t]+([0-9]+)', line)
if result_hooked:
hooked = int(result_hooked.group(1))
result_replaced = re.search(r'Replaced:[\s\t]+([0-9]+)', line)
if result_replaced:
replaced = int(result_replaced.group(1))
result_suspicious = re.search(r'Other suspicious:[\s\t]+([0-9]+)', line)
if result_suspicious:
suspicious = int(result_suspicious.group(1))
# Check output for process replacements
if "SUMMARY:" not in output:
self.logger.log("ERROR", "Something went wrong during PE-Sieve scan. Couldn't find the SUMMARY section in output.")
return hooked, replaced, suspicious
print results
except Exception as e:
traceback.print_exc()
self.logger.log("ERROR", "PESieve", "Something went wrong during PE-Sieve scan. "
"Couldn't parse the JSON output.")
return results
Loading

0 comments on commit 9cd7143

Please sign in to comment.