Skip to content

Commit

Permalink
Merge branch 'master' into lint_python_update
Browse files Browse the repository at this point in the history
  • Loading branch information
Neo23x0 committed Apr 24, 2023
2 parents 8066d69 + fc3d4f3 commit ac92796
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 78 deletions.
180 changes: 107 additions & 73 deletions loki-upgrader.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
import argparse
import traceback
from sys import platform as _platform
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse
from os.path import exists

# Win32 Imports
if _platform == "win32":
Expand All @@ -37,6 +42,32 @@
elif _platform == "win32":
platform = "windows"

def needs_update(sig_url):
try:
o=urlparse(sig_url)
path=o.path.split('/')
branch=path[4].split('.')[0]
path.pop(len(path)-1)
path.pop(len(path)-1)
url = o.scheme+'://api.'+o.netloc+'/repos'+'/'.join(path)+'/commits/'+branch
response_info = urlopen(url)
j = json.load(response_info)
sha=j['sha']
cache='_'.join(path)+'.cache'
changed=False
if exists(cache):
with open(cache, "r") as file:
old_sha = file.read().rstrip()
if sha != old_sha:
changed=True
else:
with open(cache, "w") as file:
file.write(sha)
changed=True
return changed
except Exception as e:
return True


class LOKIUpdater(object):

Expand All @@ -58,79 +89,82 @@ def __init__(self, debug, logger, application_path):
def update_signatures(self, clean=False):
try:
for sig_url in self.UPDATE_URL_SIGS:
# Downloading current repository
try:
self.logger.log("INFO", "Upgrader", "Downloading %s ..." % sig_url)
response = urlopen(sig_url)
except Exception as e:
if self.debug:
traceback.print_exc()
self.logger.log("ERROR", "Upgrader", "Error downloading the signature database - "
"check your Internet connection")
sys.exit(1)

# Preparations
try:
sigDir = os.path.join(self.application_path, os.path.abspath('signature-base/'))
if clean:
self.logger.log("INFO", "Upgrader", "Cleaning directory '%s'" % sigDir)
shutil.rmtree(sigDir)
for outDir in ['', 'iocs', 'yara', 'misc']:
fullOutDir = os.path.join(sigDir, outDir)
if not os.path.exists(fullOutDir):
os.makedirs(fullOutDir)
except Exception as e:
if self.debug:
traceback.print_exc()
self.logger.log("ERROR", "Upgrader", "Error while creating the signature-base directories")
sys.exit(1)

# Read ZIP file
try:
zipUpdate = zipfile.ZipFile(io.BytesIO(response.read()))
for zipFilePath in zipUpdate.namelist():
sigName = os.path.basename(zipFilePath)
if zipFilePath.endswith("/"):
continue
# Skip incompatible rules
skip = False
for incompatible_rule in self.INCOMPATIBLE_RULES:
if sigName.endswith(incompatible_rule):
self.logger.log("NOTICE", "Upgrader", "Skipping incompatible rule %s" % sigName)
skip = True
if skip:
continue
# Extract the rules
self.logger.log("DEBUG", "Upgrader", "Extracting %s ..." % zipFilePath)
if "/iocs/" in zipFilePath and zipFilePath.endswith(".txt"):
targetFile = os.path.join(sigDir, "iocs", sigName)
elif "/yara/" in zipFilePath and zipFilePath.endswith(".yar"):
targetFile = os.path.join(sigDir, "yara", sigName)
elif "/misc/" in zipFilePath and zipFilePath.endswith(".txt"):
targetFile = os.path.join(sigDir, "misc", sigName)
elif zipFilePath.endswith(".yara"):
targetFile = os.path.join(sigDir, "yara", sigName)
else:
continue

# New file
if not os.path.exists(targetFile):
self.logger.log("INFO", "Upgrader", "New signature file: %s" % sigName)

# Extract file
source = zipUpdate.open(zipFilePath)
target = open(targetFile, "wb")
with source, target:
shutil.copyfileobj(source, target)
target.close()
source.close()

except Exception as e:
if self.debug:
traceback.print_exc()
self.logger.log("ERROR", "Upgrader", "Error while extracting the signature files from the download "
"package")
sys.exit(1)
if needs_update(sig_url) == True:
# Downloading current repository
try:
self.logger.log("INFO", "Upgrader", "Downloading %s ..." % sig_url)
response = urlopen(sig_url)
except Exception as e:
if self.debug:
traceback.print_exc()
self.logger.log("ERROR", "Upgrader", "Error downloading the signature database - "
"check your Internet connection")
sys.exit(1)

# Preparations
try:
sigDir = os.path.join(self.application_path, os.path.abspath('signature-base/'))
if clean:
self.logger.log("INFO", "Upgrader", "Cleaning directory '%s'" % sigDir)
shutil.rmtree(sigDir)
for outDir in ['', 'iocs', 'yara', 'misc']:
fullOutDir = os.path.join(sigDir, outDir)
if not os.path.exists(fullOutDir):
os.makedirs(fullOutDir)
except Exception as e:
if self.debug:
traceback.print_exc()
self.logger.log("ERROR", "Upgrader", "Error while creating the signature-base directories")
sys.exit(1)

# Read ZIP file
try:
zipUpdate = zipfile.ZipFile(io.BytesIO(response.read()))
for zipFilePath in zipUpdate.namelist():
sigName = os.path.basename(zipFilePath)
if zipFilePath.endswith("/"):
continue
# Skip incompatible rules
skip = False
for incompatible_rule in self.INCOMPATIBLE_RULES:
if sigName.endswith(incompatible_rule):
self.logger.log("NOTICE", "Upgrader", "Skipping incompatible rule %s" % sigName)
skip = True
if skip:
continue
# Extract the rules
self.logger.log("DEBUG", "Upgrader", "Extracting %s ..." % zipFilePath)
if "/iocs/" in zipFilePath and zipFilePath.endswith(".txt"):
targetFile = os.path.join(sigDir, "iocs", sigName)
elif "/yara/" in zipFilePath and zipFilePath.endswith(".yar"):
targetFile = os.path.join(sigDir, "yara", sigName)
elif "/misc/" in zipFilePath and zipFilePath.endswith(".txt"):
targetFile = os.path.join(sigDir, "misc", sigName)
elif zipFilePath.endswith(".yara"):
targetFile = os.path.join(sigDir, "yara", sigName)
else:
continue

# New file
if not os.path.exists(targetFile):
self.logger.log("INFO", "Upgrader", "New signature file: %s" % sigName)

# Extract file
source = zipUpdate.open(zipFilePath)
target = open(targetFile, "wb")
with source, target:
shutil.copyfileobj(source, target)
target.close()
source.close()

except Exception as e:
if self.debug:
traceback.print_exc()
self.logger.log("ERROR", "Upgrader", "Error while extracting the signature files from the download "
"package")
sys.exit(1)
else:
self.logger.log("INFO", "Upgrader", "%s is up to date." % sig_url)

except Exception as e:
if self.debug:
Expand Down
22 changes: 17 additions & 5 deletions loki.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class Loki(object):
hashes_md5 = {}
hashes_sha1 = {}
hashes_sha256 = {}
hashes_scores = {}
false_hashes = {}
c2_server = {}

Expand Down Expand Up @@ -389,26 +390,30 @@ def scan_path(self, path):
continue

# Malware Hash
matchScore = 100
if ioc_contains(self.hashes_md5_list, md5_num):
matchType = "MD5"
matchDesc = self.hashes_md5[md5_num]
matchHash = md5
matchScore = self.hashes_scores[md5_num]
if ioc_contains(self.hashes_sha1_list, sha1_num):
matchType = "SHA1"
matchDesc = self.hashes_sha1[sha1_num]
matchHash = sha1
matchScore = self.hashes_scores[sha1_num]
if ioc_contains(self.hashes_sha256_list, sha256_num):
matchType = "SHA256"
matchDesc = self.hashes_sha256[sha256_num]
matchHash = sha256
matchScore = self.hashes_scores[sha256_num]

# Hash string
hashString = "MD5: %s SHA1: %s SHA256: %s" % ( md5, sha1, sha256 )

if matchType:
reasons.append("Malware Hash TYPE: %s HASH: %s SUBSCORE: 100 DESC: %s" % (
matchType, matchHash, matchDesc))
total_score += 100
reasons.append("Malware Hash TYPE: %s HASH: %s SUBSCORE: %d DESC: %s" % (
matchType, matchHash, matchScore, matchDesc))
total_score += matchScore

# Script Anomalies Check
if args.scriptanalysis:
Expand Down Expand Up @@ -1202,12 +1207,19 @@ def initialize_hash_iocs(self, ioc_directory, false_positive=False):
if re.search(r'^#', line) or re.search(r'^[\s]*$', line):
continue
row = line.split(';')
hash = row[0].lower()
comment = row[1].rstrip(" ").rstrip("\n")
# Handle 2 and 3 column IOCs
if len(row) == 2:
hash = row[0].lower()
comment = row[1].rstrip(" ").rstrip("\n")
elif len(low) == 3:
hash = row[0].lower()
score = int(row[1])
comment = row[2].rstrip(" ").rstrip("\n")
# Empty File Hash
if hash in HASH_WHITELIST:
continue
# Else - check which type it is
self.hashes_scores[int(hash, 16)] = score
if len(hash) == 32:
self.hashes_md5[int(hash, 16)] = comment
if len(hash) == 40:
Expand Down

0 comments on commit ac92796

Please sign in to comment.