Skip to content

Commit

Permalink
new: Easy submission from Lookyloo to Lookyloo
Browse files Browse the repository at this point in the history
  • Loading branch information
Rafiot committed Feb 18, 2025
1 parent 19205ea commit 72e66a5
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 15 deletions.
2 changes: 1 addition & 1 deletion bin/background_build_captures.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _build_missing_pickles(self) -> bool:
return False
if ((path / 'tree.pickle.gz').exists() or (path / 'tree.pickle').exists()):
# We already have a pickle file
self.logger.debug(f'{path} has a pickle.')
# self.logger.debug(f'{path} has a pickle.')
if (path / 'auto_report').exists():
# the pickle was built somewhere else, trigger report.
self.__auto_report(path)
Expand Down
18 changes: 9 additions & 9 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ defang = "^0.5.3"
vt-py = "^0.19.0"
pyeupi = "^1.3.0"
pysanejs = "^2.0.4"
pylookyloo = "^1.27.1"
pylookyloo = "^1.28.0"
dnspython = "^2.7.0"
pytaxonomies = "^2.0"
pymisp = {version = "^2.5.4", extras = ["url", "fileobjects"]}
Expand Down Expand Up @@ -105,7 +105,7 @@ types-python-dateutil = "^2.9.0.20241206"
types-beautifulsoup4 = "^4.12.0.20250204"
types-Pillow = "^10.2.0.20240822"
types-pytz = "^2025.1.0.20250204"
types-psutil = "^6.1.0.20241221"
types-psutil = "^7.0.0.20250218"

[build-system]
requires = ["poetry-core>=2.0"]
Expand Down
22 changes: 21 additions & 1 deletion website/web/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from flask_talisman import Talisman # type: ignore[import-untyped]
from lacuscore import CaptureStatus, CaptureSettingsError
from markupsafe import Markup
from pylookyloo import PyLookylooError, Lookyloo as PyLookyloo
from puremagic import from_string, PureError
from pymisp import MISPEvent, MISPServerError # type: ignore[attr-defined]
from werkzeug.security import check_password_hash
Expand Down Expand Up @@ -891,6 +892,24 @@ def web_misp_lookup_view(tree_uuid: str) -> str | WerkzeugResponse | Response:
misps_occurrences=misps_occurrences)


@app.route('/tree/<string:tree_uuid>/lookyloo_push', methods=['POST'])
def web_lookyloo_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response:
if remote_lookyloo_url := request.form.get('remote_lookyloo_url'):
to_push = lookyloo.get_capture(tree_uuid)
pylookyloo = PyLookyloo(remote_lookyloo_url)
try:
uuid = pylookyloo.upload_capture(full_capture=to_push, quiet=True)
remote_lookyloo_url = f'<a href="{pylookyloo.root_url}/tree/{uuid}" target="_blank">{uuid}</a>'
flash(Markup(f'Successfully pushed the capture: {remote_lookyloo_url}.'), 'success')
except PyLookylooError as e:
flash(f'Error while pushing capture: {e}', 'error')
except Exception as e:
flash(f'Unable to push capture: {e}', 'error')
else:
flash('Remote Lookyloo URL missing.', 'error')
return redirect(url_for('tree', tree_uuid=tree_uuid))


@app.route('/tree/<string:tree_uuid>/misp_push', methods=['GET', 'POST'])
def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response:
if not lookyloo.misps.available:
Expand Down Expand Up @@ -986,7 +1005,8 @@ def web_misp_push_view(tree_uuid: str) -> str | WerkzeugResponse | Response:
flash(f'Unable to create event(s): {new_events}', 'error')
else:
for e in new_events:
flash(f'MISP event {e.id} created on {misp.client.root_url}', 'success')
remote_misp_url = f'<a href="{misp.client.root_url}/events/view/{e.id}" target="_blank">{e.id}</a>'
flash(Markup(f'MISP event {remote_misp_url} created on {misp.client.root_url}'), 'success')
return redirect(url_for('tree', tree_uuid=tree_uuid))


Expand Down
4 changes: 3 additions & 1 deletion website/web/genericapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,9 @@ def post(self) -> dict[str, str | dict[str, list[str]]] | tuple[dict[str, str],
return {'error': ', '.join(messages['errors'])}, 400
return {'uuid': uuid, 'messages': messages}
else:
# Treat it as a direct export from Lacus
# Treat it as a direct export from Lacus, requires at a bare minimum a HAR
if 'har' not in parameters or not parameters.get('har'):
return {'error': 'Missing HAR file'}, 400
try:
uuid = str(uuid4())
# The following parameters are base64 encoded and need to be decoded first
Expand Down
2 changes: 1 addition & 1 deletion website/web/templates/capture.html
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@
</div>

<div class="row mb-3">
<label for="locale" class="col-sm-2 col-form-label">Browser <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language">locale</a> (Accept-Language):</label>
<label for="locale" class="col-sm-2 col-form-label">Browser <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language">locale</a>:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="locale" id="locale" placeholder="fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5">
<div class="alert alert-info" role="alert">
Expand Down
26 changes: 26 additions & 0 deletions website/web/templates/tree.html
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@
<a href="#mispPushModal" data-remote="{{ url_for('web_misp_push_view', tree_uuid=tree_uuid) }}"
data-bs-toggle="modal" data-bs-target="#mispPushModal" role="button">Prepare push to MISP</a>
{% endif %}
<a href="#lookylooPushModal" data-bs-toggle="modal" data-bs-target="#lookylooPushModal" role="button"
title="Push the capture to another Lookyloo Instance">Push to another Lookyloo</a>
</div>
</div>

Expand Down Expand Up @@ -941,6 +943,30 @@ <h4 class="modal-title" id="downloadModalLabel">
</div>
</div>

<div class="modal fade" id="lookylooPushModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="lookylooPushModalLabel">
Push the current capture to another Lookyloo instance
</h4>
<br>
<button type="button" class="btn btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<br>
<div class="modal-body">
<form role="form" action="{{ url_for('web_lookyloo_push_view', tree_uuid=tree_uuid) }}"
method=post enctype=multipart/form-data>
<label for="remote_lookyloo_url" class="col-sm-2 col-form-label">Submit capture to:</label>
<input type="text" class="form-control" name="remote_lookyloo_url" required>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>


<div class="modal fade" id="hashlookupModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
Expand Down

0 comments on commit 72e66a5

Please sign in to comment.