mirror of https://github.com/CIRCL/lookyloo
396 lines
15 KiB
HTML
396 lines
15 KiB
HTML
{% macro taxonomy_table(tree_uuid, categories_info, add_category) %}
|
|
<div class="table-responsive">
|
|
<table id="table" class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Description</th>
|
|
<th>Machinetag</th>
|
|
{% if add_category %}
|
|
<th>Click to add category</th>
|
|
{% else %}
|
|
<th>Click to remove category</th>
|
|
{% endif %}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% if categories_info is mapping %}
|
|
{% for mt, val in categories_info.items() %}
|
|
<tr>
|
|
<td><a href="https://www.misp-project.org/taxonomies.html#_{{ val[0].name }}">{{ val[0].name }}</a></td>
|
|
<td>
|
|
{% if val|length == 3 %}
|
|
{% if val[2].description %}
|
|
{{ val[2].description }}
|
|
{% elif val[2].expanded %}
|
|
{{ val[2].expanded }}
|
|
{%endif%}
|
|
{% elif val[1].description %}
|
|
{{ val[1].description }}
|
|
{% else %}
|
|
{{ val[1].predicate }}
|
|
{%endif%}
|
|
</td>
|
|
<td>{{ mt }}</td>
|
|
<td>
|
|
<button type="button" class="btn btn-primary {% if add_category %}categorize_capture{% else %}uncategorize_capture{% endif %}" value="{{ mt }}">
|
|
{% if add_category %}
|
|
Categorize capture.
|
|
{% else %}
|
|
Uncategorize capture.
|
|
{% endif %}
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% else %}
|
|
{% for mt in categories_info %}
|
|
<tr>
|
|
<td></td>
|
|
<td>
|
|
</td>
|
|
<td>{{ mt }}</td>
|
|
<td>
|
|
<button type="button" class="btn btn-primary {% if add_category %}categorize_capture{% else %}uncategorize_capture{% endif %}" value="{{ mt }}">
|
|
{% if add_category %}
|
|
Categorize capture.
|
|
{% else %}
|
|
Uncategorize capture.
|
|
{% endif %}
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<script nonce="{{ csp_nonce() }}">
|
|
$('.categorize_capture').on('click',function(e){
|
|
var button = $(this);
|
|
$.get("{{ url_for('categorize_capture', tree_uuid=tree_uuid) }}" + button.val())
|
|
$('#categoriesModal .modal-body').load("{{ url_for('categories_capture', tree_uuid=tree_uuid) }}")
|
|
});
|
|
$('.uncategorize_capture').on('click',function(e){
|
|
var button = $(this);
|
|
$.get("{{ url_for('uncategorize_capture', tree_uuid=tree_uuid) }}" + button.val())
|
|
$('#categoriesModal .modal-body').load("{{ url_for('categories_capture', tree_uuid=tree_uuid) }}")
|
|
});
|
|
</script>
|
|
{% endmacro %}
|
|
|
|
|
|
{% macro known_content_details(details) %}
|
|
<div>
|
|
{% if details is string %}
|
|
<b>{{ details }} </b>
|
|
{% else %}
|
|
This file is known as part of <b>{{ details[0] }}</b>
|
|
version <b>{{ details[1] }}</b>: <b>{{ details[2] }}</b>.
|
|
{% if details[3] > 1%}
|
|
It is also present in <b>{{ details[3] -1 }}</b> other libraries.
|
|
{%endif%}
|
|
{%endif%}
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{% macro context_form(tree_uuid, urlnode_uuid, hash, callback_str) %}
|
|
<button class="btn btn-primary collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#context_response_{{ urlnode_uuid }}" aria-expanded="false" aria-controls="collapseContextForm">
|
|
<span class="if-collapsed">Add context</span>
|
|
<span class="if-not-collapsed">Hide context form</span>
|
|
</button>
|
|
<div class="collapse" id="context_response_{{ urlnode_uuid }}">
|
|
<div class="card card-body">
|
|
<form role="form" action="{{ url_for('add_context', tree_uuid=tree_uuid, node_uuid=urlnode_uuid) }}" method=post enctype=multipart/form-data>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-10">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="legitimate" id="legitimate">
|
|
<label for="legitimate" class="form-check-label">Legitimate</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-10">
|
|
<label for="legitimate_domain" class="form-label">Domain serving the file when considered legitimate:</label>
|
|
<input type="text" class="form-control" name="legitimate_domain" id="legitimate_domain" placeholder="Domain name">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-10">
|
|
<label for="legitimate_description" class="form-label">Other context for this content (library name, owner, ...):</label>
|
|
<input type="text" class="form-control" name="legitimate_description" id="legitimate_description" placeholder="Description">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-10">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="malicious"></input>
|
|
<label for="malicious" class="form-check-label">Malicious</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-10">
|
|
<label for="malicious_type" class="form-label">Type of malicious content (phishing, malware, ...):</label>
|
|
<input type="text" class="form-control" name="malicious_type" id="malicious_type" placeholder="Type of malicious content">
|
|
</div>
|
|
</div>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-10">
|
|
<label for="malicious_target" class="form-label">Legitimate target of the malicious content (expecially for phishing):</label>
|
|
<input type="text" class="form-control" name="malicious_target" id="malicious_target" placeholder="Target">
|
|
</div>
|
|
</div>
|
|
<input type="hidden" id="hash_to_contextualize" name="hash_to_contextualize" value="{{ hash }}">
|
|
<input type="hidden" id="callback_str" name="callback_str" value="{{ callback_str }}">
|
|
<button type="submit" class="btn btn-primary" id="btn-looking">Submit context</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{% macro get_ressource_button(capture_uuid, urlnode_uuid, hash, text, can_preview=False) %}
|
|
<form method="post" action="{{ url_for('get_ressource', tree_uuid=capture_uuid, node_uuid=urlnode_uuid) }}">
|
|
<button class="btn btn-primary" name="ressource_hash" value="{{ hash }}"
|
|
{% if can_preview %}
|
|
data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-html="true"
|
|
title='<img class="ressource_preview" src="{{ url_for('get_ressource_preview', tree_uuid=capture_uuid, node_uuid=urlnode_uuid, h_ressource=hash) }}"/>'
|
|
{% endif %}
|
|
>{{ text }}</button>
|
|
</form>
|
|
{% endmacro %}
|
|
|
|
{% macro ressource_legitimacy_details(details, ressource_size) %}
|
|
{% if details and details[0] == False %}
|
|
<img src="/static/bomb.svg" title="Known malicious content in the response." width="21" height="21"/>
|
|
{%endif%}
|
|
<b>Body size</b> (in the HTTP response): {{ sizeof_fmt(ressource_size) }}
|
|
{% if details %}
|
|
{% if details[0] %}
|
|
- This file is known <b>legitimate</b> on the following domains: {{ ', '.join(details[1]) }}.
|
|
{% elif details[0] == False %}
|
|
</br>
|
|
<p>
|
|
The response sould be considered as
|
|
{% if details[1] is mapping and details[1].get('tag') %}
|
|
<b>{{ ', '.join(details[1]['tag']) }}</b>
|
|
{% else %}
|
|
<b>phishing</b>
|
|
{%endif%}
|
|
{% if details[1] is mapping and details[1].get('target') %}
|
|
and is targeting <b>the following domain(s)</b>: {{ ', '.join(details[1]['target']) }}
|
|
{% else %}
|
|
unless it is served by <b>the following domain(s)</b>: {{ ', '.join(details[1]) }}
|
|
{%endif%}
|
|
</p>
|
|
{%endif%}
|
|
{%endif%}
|
|
{% endmacro %}
|
|
|
|
{% macro indexed_hash(details, identifier_for_toggle) %}
|
|
{% set total_captures = details[0] %}
|
|
{% set other_captures = details[1] %}
|
|
{# Only show details if the hits are in an other capture #}
|
|
{% if total_captures > 1 %}
|
|
<p>
|
|
The same file was seen in <b>{{ total_captures - 1 }}</b> other captures.
|
|
</br>
|
|
<button class="btn btn-primary collapsed" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#captureslist_{{ identifier_for_toggle }}"
|
|
aria-expanded="false" aria-controls="collapseExample">
|
|
<span class="if-collapsed">Show other recent captures</span>
|
|
<span class="if-not-collapsed">Hide other recent captures</span>
|
|
</button>
|
|
</p>
|
|
{# Lists of other captures loading the same content... #}
|
|
<div class="collapse" id="captureslist_{{ identifier_for_toggle }}">
|
|
<div class="card card-body">
|
|
Note that only the most recent cached captures are displayed here, click on the link below to see more.
|
|
{% if other_captures['different_url']|length > 0 %}
|
|
{# ... on other URLs #}
|
|
<div>
|
|
<p>The following captures get the same file from a <b>different URL</b></p>
|
|
{{ other_captures_table(other_captures['different_url'], 20, identifier_for_toggle + '_same') }}
|
|
</div>
|
|
{% endif %}
|
|
</br>
|
|
{% if other_captures['same_url']|length > 0 %}
|
|
{# ... on the same URL #}
|
|
<div>
|
|
<p>The following captures get the same file from the <b>same URL</b></p>
|
|
{{ other_captures_table(other_captures['same_url'], 20, identifier_for_toggle + '_different') }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
{% macro other_captures_table(entries, max_entries, identifier) %}
|
|
<script type="text/javascript" nonce="{{ csp_nonce() }}">
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
new DataTable('#table_other_captures_{{identifier}}', {
|
|
"order": [[ 1, "desc" ]],
|
|
"paging": false,
|
|
"info": false,
|
|
"columns": [
|
|
{ "orderable": false},
|
|
{ "orderable": false},
|
|
{ "orderable": false}
|
|
],
|
|
"columnDefs": [{
|
|
"targets": 1,
|
|
"render": (data) => {
|
|
const date = new Date(data);
|
|
return date.getFullYear() + '-' + (date.getMonth() + 1).toString().padStart(2, "0") + '-' + date.getDate().toString().padStart(2, "0") + ' ' + date.toTimeString();
|
|
}
|
|
}]
|
|
} );
|
|
});
|
|
</script>
|
|
|
|
<div>
|
|
<table id="table_other_captures_{{identifier}}" class="table table-striped" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>Title</th>
|
|
<th>Timestamp</th>
|
|
<th>Domain</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for capture_uuid, urlnode_uuid, title, timestamp, hostname in entries[:max_entries] %}
|
|
<tr>
|
|
<td>
|
|
<button type="button" class="btn btn-link openNewTab" data-capture="{{capture_uuid}}" data-hostnode="{{urlnode_uuid}}">{{ title }}</button>
|
|
</td>
|
|
<td>{{ timestamp }}</td>
|
|
<td>{{ hostname }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{% macro indexed_cookies(header_text, button_text, cookies) %}
|
|
{% if cookies %}
|
|
<div>{{ header_text }}</div>
|
|
<ul>
|
|
{% for cookie, details in cookies.items() %}
|
|
{% set cookie_name_value = cookie.split('=', 1) %}
|
|
{% for detail in details %}
|
|
{% if detail|length == 1 %}
|
|
<li>
|
|
{{ detail[0] }}: <a href="{{ url_for('cookies_name_detail', cookie_name=cookie_name_value[0]) }}">
|
|
{{ cookie_name_value[0] }}</a>={{ shorten_string(cookie_name_value[1], 200) }}
|
|
</li>
|
|
{% else %}
|
|
<li>
|
|
{{ detail[0] }}: <a href="{{ url_for('cookies_name_detail', cookie_name=cookie_name_value[0]) }}">
|
|
{{ cookie_name_value[0] }}</a>={{ shorten_string(cookie_name_value[1], 200) }} -
|
|
</br>
|
|
{{ button_text }}
|
|
<button type="button" class="btn btn-primary locateInTree" data-hostnode="{{ detail[1] }}">Locate</button>
|
|
</li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endfor %}
|
|
</ul>
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
{% macro popup_icons_request(urlnode, tree_uuid) %}
|
|
<div>
|
|
{% if urlnode.request_cookie %}
|
|
{% set icon_info = get_icon("request_cookie") %}
|
|
<a href="{{ url_for('urlnode_request_cookies', tree_uuid=tree_uuid, node_uuid=urlnode.uuid) }}"
|
|
title="Download all the cookies in the request to the server">
|
|
<img src="{{ url_for('static', filename=icon_info['icon']) }}" alt="{{ icon_info['tooltip'] }}"
|
|
width="21" height="21"/>
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
|
|
{% macro pandora_submit(tree_uuid, node_uuid, ressource_hash) %}
|
|
<div class="col-sm-8">
|
|
<button type="button" class="btn btn-primary btn-sm submitPandoraButton"
|
|
title="open a new tab with the pandora report"
|
|
data-hostnode="{{ node_uuid }}"
|
|
data-hash="{{ ressource_hash }}"
|
|
data-pandorasubmit="{{ url_for('pandora_submit', tree_uuid=tree_uuid)}}">
|
|
Submit to Pandora
|
|
</button>
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
|
|
{% macro popup_icons_response(urlnode, tree_uuid) %}
|
|
<div>
|
|
{% if urlnode.response_cookie %}
|
|
{% set icon_info = get_icon("response_cookie") %}
|
|
<a href="{{ url_for('urlnode_response_cookies', tree_uuid=tree_uuid, node_uuid=urlnode.uuid) }}"
|
|
title="Download all the cookies in the response from the server">
|
|
<img src="{{ url_for('static', filename=icon_info['icon']) }}" alt="{{ icon_info['tooltip'] }}"
|
|
width="21" height="21"/>
|
|
</a>
|
|
{% endif %}
|
|
|
|
{% if urlnode.generic_type in ["js", "exe", "css", "font", "html", "json", "image", "video",
|
|
"unknown_mimetype", "text", "unset_mimetype", "octet-stream",
|
|
"livestream"] %}
|
|
{% set icon_info = get_icon(urlnode.generic_type) %}
|
|
<a href="{{ url_for('get_ressource', tree_uuid=tree_uuid, node_uuid=urlnode.uuid) }}">
|
|
<img src="{{ url_for('static', filename=icon_info['icon']) }}" alt="{{ icon_info['tooltip'] }}"
|
|
width="21" height="21"
|
|
{% if urlnode.generic_type == "image" %}
|
|
data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-html="true"
|
|
title='<img class="ressource_preview" src="{{ url_for('get_ressource_preview', tree_uuid=tree_uuid, node_uuid=urlnode.uuid) }}"/> </br>Click to download.'
|
|
{% else %}
|
|
data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-html="true"
|
|
title="{{icon_info['tooltip']}} <br/>Click to download."
|
|
{% endif %}
|
|
/>
|
|
</a>
|
|
{%endif%}
|
|
</div>
|
|
|
|
<div>
|
|
{% if urlnode["redirect"] %}
|
|
{% set icon_info = get_icon('redirect') %}
|
|
{% for child in urlnode.children if child.name == urlnode.redirect_url %}
|
|
<div title='{{ urlnode.redirect_url }}'>
|
|
<b>Redirect to</b>: {{ shorten_string(urlnode.redirect_url, 50) }}
|
|
<button type="button" class="btn btn-link locateInTree" data-hostnode="{{ child.hostnode_uuid }}" title="See the node the URL redirects to.">
|
|
<img src="{{ url_for('static', filename=icon_info['icon']) }}" alt="{{ icon_info['tooltip'] }}" width="21" height="21"/>
|
|
</button>
|
|
</div>
|
|
{% else %}
|
|
<img src="{{ url_for('static', filename=icon_info['icon']) }}"
|
|
alt="{{ icon_info['tooltip'] }}" title="{{ icon_info['tooltip'] }}"
|
|
width="21" height="21"/>
|
|
{% endfor %}
|
|
{%endif%}
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{% macro shorten_string(string, cut_length, with_title=False) %}
|
|
{% if with_title %}
|
|
<div title={{string}}>
|
|
{%endif%}
|
|
|
|
{% if string|length > cut_length %}
|
|
{{ string[:cut_length] }} [...]
|
|
{% else %}
|
|
{{ string }}
|
|
{%endif%}
|
|
|
|
{% if with_title %}
|
|
</div>
|
|
{%endif%}
|
|
|
|
{% endmacro %}
|