Skip to content

Commit

Permalink
Added Malware Hash Registry (MHR) pre processing
Browse files Browse the repository at this point in the history
  • Loading branch information
amadisson committed Oct 9, 2023
1 parent c31d990 commit af0268b
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 3 deletions.
2 changes: 1 addition & 1 deletion processing/cuckoo/processing/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2019-2023 Estonian Information System Authority.
# See the file 'LICENSE' for copying permission.

__version__ = "0.1.2"
__version__ = "0.1.3"
11 changes: 10 additions & 1 deletion processing/cuckoo/processing/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2019-2021 Estonian Information System Authority.
# Copyright (C) 2019-2023 Estonian Information System Authority.
# See the file 'LICENSE' for copying permission.

from cuckoo.common import config
Expand Down Expand Up @@ -74,6 +74,15 @@ def constraints(self, value):
"submitter": config.String(),
"rescan_time": config.Int(default_val=15, min_value=1),
},
"mhr.yaml": {
"enabled": config.Boolean(default_val=False),
"timeout": config.Int(default_val=60, min_value=0),
"url": config.HTTPUrl(default_val="https://hash.cymru.com/v2/"),
"user": config.String(allow_empty=True),
"password": config.String(allow_empty=True),
"min_suspicious": config.Int(default_val=10, min_value=1),
"min_malicious": config.Int(default_val=17, min_value=1),
},
"misp.yaml": {
"processing": {
"enabled": config.Boolean(default_val=False),
Expand Down
21 changes: 21 additions & 0 deletions processing/cuckoo/processing/data/conftemplates/mhr.yaml.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Enable or disable MHR usage during processing. Module performs hash and url lookups for submissions.
enabled: {{ enabled }}

# What percentage of AV engines should mark a sample as malicious for Cuckoo to
# mark it as suspicious? Take into account that false positives happen.
min_suspicious: {{ min_suspicious }}

# What percentage of AV engines should mark a sample as malicious for Cuckoo to
# mark it as malicious? Take into account that false positives happen.
min_malicious: {{ min_malicious }}

# How much time we can wait to establish MHR connection and get the report.
timeout: {{ timeout }}


# URL to your Malware Hash Registry (MHR) REST API
url: {{ url }}

# Registration is needed: https://hash.cymru.com/signup
user: {{ user }}
password: {{ password }}
115 changes: 115 additions & 0 deletions processing/cuckoo/processing/pre/mhr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Copyright (C) 2019-2023 Estonian Information System Authority.
# See the file 'LICENSE' for copying permission.
import logging
import time
from urllib.parse import urljoin
import requests
from requests.auth import HTTPBasicAuth
import json

from cuckoo.common.config import cfg

from ..abtracts import Processor
from ..signatures.signature import Scores, IOC


class MHRInfoGather(Processor):

CATEGORY = ["file"]
KEY = "mhr"

@classmethod
def enabled(cls):
return cfg("mhr", "enabled", subpkg="processing")

def init(self):
self.url = cfg(
"mhr", "url", subpkg="processing"
)
self.timeout = cfg(
"mhr", "timeout", subpkg="processing"
)
self.user = cfg(
"mhr", "user", subpkg="processing"
)
self.password = cfg(
"mhr", "password", subpkg="processing"
)
self.min_suspicious = cfg(
"mhr", "min_suspicious", subpkg="processing"
)
self.min_malicious = cfg(
"mhr", "min_malicious", subpkg="processing"
)

def _get_results(self, sha256):
results = self._request_json(urljoin(self.url, sha256))

if results:
return results
else:
return None

def _request_json(self, url, **kwargs):
"""Wrapper around doing a request and parsing its JSON output."""
try:
r = requests.get(url, auth=HTTPBasicAuth(self.user, self.password),
timeout=self.timeout, **kwargs)
return r.json() if r.status_code == 200 else {}
except (requests.ConnectionError, ValueError) as e:
self.ctx.log.error(
f"Unable to fetch MHR results: {e}"
)
return {}

def _handle_file_target(self):
info = None
try:
target = self.ctx.result.get("target")
info = self._get_results(target.sha256)

if not info:
return None
except Exception as e:
self.ctx.log.warning(
f"Error while making MHR request: {e}"
)
return info


def start(self):
info = None
antivirus_detection_rate = None
if self.ctx.analysis.category == "file":
info = self._handle_file_target()

if not info:
return {}


score = 0
if info["antivirus_detection_rate"]:
if info["antivirus_detection_rate"] >= self.min_malicious:
score = Scores.KNOWN_BAD
elif info["antivirus_detection_rate"] >= self.min_suspicious:
# Suspicious. Decide what scores to use Cuckoo-wide and document.
score = Scores.SUSPICIOUS
else:
return {}

if score:
iocs = [
IOC(antivirus="MHR", result=info["antivirus_detection_rate"])
]

self.ctx.signature_tracker.add_signature(
name="mhr",
score=score,
short_description="MHR sources report this target as "
"malicious",
description=f"{info['antivirus_detection_rate']} percentage of tested MHR antivirus engines"
f" detect this target as malicious",
iocs=iocs
)

return info
16 changes: 16 additions & 0 deletions web/cuckoo/web/templates/analysis/components/mhr.html.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% call ui_box(title="Malware Hash Registry (MHR)", has_padding=False) %}
<table class="table has-sticky-header has-striped-rows">
<thead>
<tr>
<th>Antivirus Detection Rate</th>
<th>Last Run</th>
</tr>
</thead>
<tbody>
<tr>
<td {{ pre.mhr.antivirus_detection_rate }}</td>
<td>{{ pre.mhr.last_run_date|formatisodatetime }}</td>
</tr>
</tbody>
</table>
{% endcall %}
9 changes: 9 additions & 0 deletions web/cuckoo/web/templates/analysis/index.html.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,15 @@
{% endif %}
{% endif %}

{# tab: static.mhr #}
{% if pre.mhr is defined %}
{% if pre.mhr.antivirus_detection_rate %}
<div role="region" id="mhr" hidden>
{% include "analysis/components/mhr.html.jinja2" %}
</div>
{% endif %}
{% endif %}

{# tab: pre.misp #}
{% if pre.misp %}
<div role="region" id="misp" hidden>
Expand Down
9 changes: 8 additions & 1 deletion web/cuckoo/web/templates/partial/analysis-index.html.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@
<li>
<a role="tab" href="#irma">IRMA</a>
</li>
{% endif %}
{% endif %}
{% endif %}
{% if pre.mhr is defined %}
{% if pre.mhr %}
<li>
<a role="tab" href="#mhr">MHR</a>
</li>
{% endif %}
{% endif %}
{% if pre.misp %}
<li>
Expand Down

0 comments on commit af0268b

Please sign in to comment.