Compare commits

..

2 Commits

Author SHA1 Message Date
Adrian Maraj 4c2620df4c fixing so that modules can be none 2024-04-16 15:35:16 +02:00
Adrian Maraj c5c1a8adf0 fixes to make mypy happy 2024-04-16 15:29:12 +02:00
5 changed files with 61 additions and 28 deletions

View File

@ -18,7 +18,6 @@ from lookyloo.default import AbstractManager, get_config
from lookyloo.helpers import get_captures_dir
from lookyloo.modules import FOX
from website.web import modules
logging.config.dictConfig(get_config('logging'))
@ -113,8 +112,8 @@ class AsyncCapture(AbstractManager):
settings = json.loads(to_capture['auto_report'])
elif isinstance(to_capture['auto_report'], dict):
settings = to_capture['auto_report']
response_3rd_party = modules(uuid, True)
self.lookyloo.send_mail(uuid,response_3rd_party, email=settings.get('email', ''),
self.lookyloo.send_mail(uuid, email=settings.get('email', ''),
comment=settings.get('comment'))
lazy_cleanup = self.lookyloo.redis.pipeline()

View File

@ -1,5 +1,3 @@
{report}
Dear {recipient},
Please have a look at this capture on lookyloo:
@ -9,6 +7,8 @@ Initial URL: {initial_url}
{redirects}
{modules}
{misp}
{comment}

View File

@ -813,7 +813,58 @@ class Lookyloo():
result.append(self.takedown_details(rendered_hostnode))
return result
def send_mail(self, capture_uuid: str, /, modules: str, email: str='', comment: str | None=None) -> bool | dict[str, Any]:
def modules_filtered(self, capture_uuid: str, /) -> str | None:
response = self.get_modules_responses(capture_uuid)
if not response:
return None
modules = set()
if 'vt' in response:
vt = response.pop('vt')
for url, report in vt.items():
if not report:
continue
for vendor, result in report['attributes']['last_analysis_results'].items():
if result['category'] == 'malicious':
modules.add(vendor)
if 'pi' in response:
pi = response.pop('pi')
for url, full_report in pi.items():
if not full_report:
continue
modules.add('Phishing Initiative')
if 'phishtank' in response:
pt = response.pop('phishtank')
for url, full_report in pt['urls'].items():
if not full_report:
continue
modules.add('Phishtank')
if 'urlhaus' in response:
uh = response.pop('urlhaus')
for url, results in uh['urls'].items():
if results:
modules.add('URLhaus')
if 'urlscan' in response and response.get('urlscan'):
urlscan = response.pop('urlscan')
if 'error' not in urlscan['submission']:
if urlscan['submission'] and urlscan['submission'].get('result'):
if urlscan['result']:
if (urlscan['result'].get('verdicts')
and urlscan['result']['verdicts'].get('overall')):
if urlscan['result']['verdicts']['overall'].get('malicious'):
modules.add('urlscan')
else:
# unable to run the query, probably an invalid key
pass
if len(modules) == 0:
return f"Capture does not seem to be malicious"
return f"Malicious capture according to {len(modules)} module(s) {modules}"
def send_mail(self, capture_uuid: str, /, email: str='', comment: str | None=None) -> bool | dict[str, Any]:
'''Send an email notification regarding a specific capture'''
if not get_config('generic', 'enable_mail_notification'):
return {"error": "Unable to send mail: mail notification disabled"}
@ -857,6 +908,7 @@ class Lookyloo():
if diff.days < 1: # MISP event should not be older than 24hours
misp += f"\n{ts.isoformat()} : {misp_url}events/{event_id}"
break # some events have more than just one timestamp, we just take the first one
modules = self.modules_filtered(capture_uuid)
msg = EmailMessage()
msg['From'] = email_config['from']
if email:
@ -866,13 +918,13 @@ class Lookyloo():
body = get_email_template()
body = body.format(
recipient=msg['To'].addresses[0].display_name,
modules=modules if modules else '',
domain=self.public_domain,
uuid=capture_uuid,
initial_url=initial_url,
redirects=redirects,
comment=comment if comment else '',
misp=f"MISP occurrences from the last 24h: {misp}" if misp else '',
report= modules if modules else '',
sender=msg['From'].addresses[0].display_name,
)
msg.set_content(body)

View File

@ -817,7 +817,7 @@ def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response | No
@app.route('/tree/<string:tree_uuid>/modules', methods=['GET'])
def modules(tree_uuid: str, mail: bool = False) -> str | WerkzeugResponse | Response:
def modules(tree_uuid: str) -> str | WerkzeugResponse | Response:
modules_responses = lookyloo.get_modules_responses(tree_uuid)
if not modules_responses:
return redirect(url_for('tree', tree_uuid=tree_uuid))
@ -894,21 +894,6 @@ def modules(tree_uuid: str, mail: bool = False) -> str | WerkzeugResponse | Resp
else:
# unable to run the query, probably an invalid key
pass
if mail:
short_results = {"vt": vt_short_result, "pi": pi_short_result, "urlscan": urlscan_to_display, "phishtank": phishtank_short_result, "urlhaus": urlhaus_short_result}
# iterate through the results because if they are empty, there is no hit within the 3rd party modules
for module in short_results:
if short_results[module]: # some might have more values which have to be checked if they are empty
for data in short_results[module]:
if short_results[module][data]: # if true we can consider that there is a hit and the capture might be malicious
return str("**************************************************\n"
" Malicious capture according to 3rd party modules \n"
"**************************************************")
return str('********************************************\n'
' Capture doesn\'t seem to be malicious\n'
'********************************************')
return render_template('modules.html', uuid=tree_uuid, vt=vt_short_result,
pi=pi_short_result, urlscan=urlscan_to_display,
phishtank=phishtank_short_result,
@ -1121,8 +1106,7 @@ def send_mail(tree_uuid: str) -> WerkzeugResponse:
# skip clearly incorrect emails
email = ''
comment: str = request.form['comment'] if request.form.get('comment') else ''
response_3rd_party = modules(tree_uuid, True)
lookyloo.send_mail(tree_uuid, response_3rd_party, email, comment)
lookyloo.send_mail(tree_uuid, email, comment)
flash("Email notification sent", 'success')
return redirect(url_for('tree', tree_uuid=tree_uuid))

View File

@ -389,9 +389,7 @@ class CaptureReport(Resource): # type: ignore[misc]
@api.param('comment', 'Description of the URL, will be given to the analyst.') # type: ignore[misc]
def post(self, capture_uuid: str) -> bool | dict[str, Any]:
parameters: dict[str, Any] = request.get_json(force=True)
from . import modules
report = modules(capture_uuid, True)
return lookyloo.send_mail(capture_uuid, report, parameters.get('email', ''), parameters.get('comment'))
return lookyloo.send_mail(capture_uuid, parameters.get('email', ''), parameters.get('comment'))
auto_report_model = api.model('AutoReportModel', {