mirror of https://github.com/CIRCL/lookyloo
new: Add MISP lookup
parent
53ef253c94
commit
3071a1a7c9
|
@ -414,6 +414,20 @@ class Lookyloo():
|
|||
to_return['pi'][ct.root_hartree.har.root_url] = self.pi.get_url_lookup(ct.root_hartree.har.root_url)
|
||||
return to_return
|
||||
|
||||
def get_misp_occurrences(self, capture_uuid: str, /) -> Optional[Dict[str, Any]]:
|
||||
if not self.misp.available:
|
||||
return None
|
||||
try:
|
||||
ct = self.get_crawled_tree(capture_uuid)
|
||||
except LookylooException:
|
||||
self.logger.warning(f'Unable to get the modules responses unless the tree ({capture_uuid}) is cached.')
|
||||
return None
|
||||
nodes_to_lookup = ct.root_hartree.rendered_node.get_ancestors()
|
||||
events = {}
|
||||
for node in nodes_to_lookup:
|
||||
events[node.name] = self.misp.lookup(node, ct.root_hartree.get_host_node_by_uuid(node.hostnode_uuid))
|
||||
return events
|
||||
|
||||
def _set_capture_cache(self, capture_dir: Path, force: bool=False, redis_pipeline: Optional[Redis]=None) -> None:
|
||||
'''Populate the redis cache for a capture. Mostly used on the index page.'''
|
||||
if force or not self.redis.exists(str(capture_dir)):
|
||||
|
|
|
@ -19,7 +19,7 @@ from pysanejs import SaneJS
|
|||
from pyeupi import PyEUPI
|
||||
from pymisp import PyMISP, MISPEvent, MISPAttribute
|
||||
|
||||
from har2tree import CrawledTree, HostNode
|
||||
from har2tree import CrawledTree, HostNode, URLNode
|
||||
|
||||
|
||||
class MISP():
|
||||
|
@ -121,6 +121,20 @@ class MISP():
|
|||
return event
|
||||
return None
|
||||
|
||||
def lookup(self, node: URLNode, hostnode: HostNode) -> Union[List[str], Dict]:
|
||||
if self.available and self.enable_lookup:
|
||||
to_lookup = [node.name, node.hostname] + hostnode.resolved_ips
|
||||
if hasattr(hostnode, 'cnames'):
|
||||
to_lookup += hostnode.cnames
|
||||
if attributes := self.client.search(controller='attributes', value=to_lookup, pythonify=True):
|
||||
if isinstance(attributes, list):
|
||||
return list(set(attribute.event_id for attribute in attributes))
|
||||
else:
|
||||
return attributes
|
||||
return []
|
||||
else:
|
||||
return {'error': 'Module not available or lookup not enabled.'}
|
||||
|
||||
|
||||
class UniversalWhois():
|
||||
|
||||
|
|
|
@ -338,6 +338,17 @@ def stats(tree_uuid: str):
|
|||
return render_template('statistics.html', uuid=tree_uuid, stats=stats)
|
||||
|
||||
|
||||
@app.route('/tree/<string:tree_uuid>/misp_lookup', methods=['GET'])
|
||||
@flask_login.login_required
|
||||
def web_misp_lookup_view(tree_uuid: str):
|
||||
hits = lookyloo.get_misp_occurrences(tree_uuid)
|
||||
if hits:
|
||||
misp_root_url = lookyloo.misp.client.root_url
|
||||
else:
|
||||
misp_root_url = None
|
||||
return render_template('misp_lookup.html', uuid=tree_uuid, hits=hits, misp_root_url=misp_root_url)
|
||||
|
||||
|
||||
@app.route('/tree/<string:tree_uuid>/modules', methods=['GET'])
|
||||
def modules(tree_uuid: str):
|
||||
modules_responses = lookyloo.get_modules_responses(tree_uuid)
|
||||
|
@ -551,6 +562,7 @@ def tree(tree_uuid: str, node_uuid: Optional[str]=None):
|
|||
enable_categorization=enable_categorization,
|
||||
enable_bookmark=enable_bookmark,
|
||||
misp_push=lookyloo.misp.available and lookyloo.misp.enable_push,
|
||||
misp_lookup=lookyloo.misp.available and lookyloo.misp.enable_lookup,
|
||||
blur_screenshot=blur_screenshot, urlnode_uuid=hostnode_to_highlight,
|
||||
auto_trigger_modules=auto_trigger_modules,
|
||||
confirm_message=confirm_message if confirm_message else 'Tick to confirm.',
|
||||
|
|
|
@ -73,6 +73,13 @@
|
|||
});
|
||||
</script>
|
||||
<script>
|
||||
$('#mispLookupModal').on('show.bs.modal', function(e) {
|
||||
var button = $(e.relatedTarget);
|
||||
var modal = $(this);
|
||||
modal.find('.modal-body').load(button.data("remote"));
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$('#urlsInPageModal').on('show.bs.modal', function(e) {
|
||||
var button = $(e.relatedTarget);
|
||||
var modal = $(this);
|
||||
|
@ -229,6 +236,12 @@
|
|||
data-toggle="modal" data-target="#mispPushModal" role="button">Prepare push to MISP</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated and misp_lookup%}
|
||||
<li>
|
||||
<a href="#mispLookupModal" data-remote="{{ url_for('web_misp_lookup_view', tree_uuid=tree_uuid) }}"
|
||||
data-toggle="modal" data-target="#mispLookupModal" role="button">Search events on MISP</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if enable_bookmark %}
|
||||
<li>
|
||||
<a href="#/" role="button" onclick="UnbookmarkAllNodes();">Unbookmark all nodes</a>
|
||||
|
@ -392,6 +405,25 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="mispLookupModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="mispLookupModalLabel">MISP Lookup</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
... loading MISP Lookup view ...
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="screenshotModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
|
|
Loading…
Reference in New Issue