mirror of https://github.com/CIRCL/lookyloo
new: Initial listing of all resources loaded on the capture
parent
2d764e73ff
commit
83c6c308c5
|
@ -570,6 +570,18 @@ class Lookyloo():
|
|||
break
|
||||
return details, body_content
|
||||
|
||||
def get_all_body_hashes(self, capture_uuid: str, /) -> Dict[str, Dict[str, Union[URLNode, int]]]:
|
||||
ct = self.get_crawled_tree(capture_uuid)
|
||||
to_return: Dict[str, Dict[str, Union[URLNode, int]]] = defaultdict()
|
||||
for node in ct.root_hartree.url_tree.traverse():
|
||||
if node.empty_response or node.body_hash in to_return:
|
||||
# If we have the same hash more than once, skip
|
||||
continue
|
||||
total_captures, details = self.indexing.get_body_hash_captures(node.body_hash, limit=-1)
|
||||
# Note for future: mayeb get url, capture title, something better than just the hash to show to the user
|
||||
to_return[node.body_hash] = {'node': node, 'total_captures': total_captures}
|
||||
return to_return
|
||||
|
||||
def get_latest_url_capture(self, url: str, /) -> Optional[CaptureCache]:
|
||||
'''Get the most recent capture with this URL'''
|
||||
captures = self.sorted_capture_cache(self.indexing.get_captures_url(url))
|
||||
|
|
|
@ -403,7 +403,7 @@ tornado = ["tornado (>=0.2)"]
|
|||
|
||||
[[package]]
|
||||
name = "har2tree"
|
||||
version = "1.13.2"
|
||||
version = "1.13.3"
|
||||
description = "HTTP Archive (HAR) to ETE Toolkit generator"
|
||||
category = "main"
|
||||
optional = false
|
||||
|
@ -421,7 +421,7 @@ six = ">=1.16.0,<2.0.0"
|
|||
w3lib = ">=1.22.0,<2.0.0"
|
||||
|
||||
[package.extras]
|
||||
docs = ["Sphinx (>=5.0.2,<6.0.0)"]
|
||||
docs = ["Sphinx (>=5.1.1,<6.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "hiredis"
|
||||
|
@ -544,7 +544,7 @@ i18n = ["Babel (>=2.7)"]
|
|||
|
||||
[[package]]
|
||||
name = "jsonschema"
|
||||
version = "4.8.0"
|
||||
version = "4.9.0"
|
||||
description = "An implementation of JSON Schema validation for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
|
@ -553,6 +553,7 @@ python-versions = ">=3.7"
|
|||
[package.dependencies]
|
||||
attrs = ">=17.4.0"
|
||||
importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""}
|
||||
pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""}
|
||||
pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2"
|
||||
|
||||
[package.extras]
|
||||
|
@ -713,6 +714,14 @@ python-versions = ">=3.7"
|
|||
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"]
|
||||
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
|
||||
|
||||
[[package]]
|
||||
name = "pkgutil-resolve-name"
|
||||
version = "1.3.10"
|
||||
description = "Resolve a name to an object."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "playwright"
|
||||
version = "1.24.0"
|
||||
|
@ -1192,7 +1201,7 @@ python-versions = "*"
|
|||
|
||||
[[package]]
|
||||
name = "types-redis"
|
||||
version = "4.3.11"
|
||||
version = "4.3.13"
|
||||
description = "Typing stubs for redis"
|
||||
category = "dev"
|
||||
optional = false
|
||||
|
@ -1200,7 +1209,7 @@ python-versions = "*"
|
|||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.28.5"
|
||||
version = "2.28.6"
|
||||
description = "Typing stubs for requests"
|
||||
category = "dev"
|
||||
optional = false
|
||||
|
@ -1219,7 +1228,7 @@ python-versions = "*"
|
|||
|
||||
[[package]]
|
||||
name = "types-urllib3"
|
||||
version = "1.26.17"
|
||||
version = "1.26.20"
|
||||
description = "Typing stubs for urllib3"
|
||||
category = "dev"
|
||||
optional = false
|
||||
|
@ -1391,7 +1400,7 @@ misp = ["python-magic", "pydeep2"]
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = ">=3.8,<3.11"
|
||||
content-hash = "73b3a7e37ff853a7edf8632744c175dc933552cfcb7b6fcd9c4bd5ebc1194801"
|
||||
content-hash = "44380fea67a49952b9e376628a50dcbe383929de3c6e174ce8b1c1b7c59f2525"
|
||||
|
||||
[metadata.files]
|
||||
aiohttp = [
|
||||
|
@ -1753,8 +1762,8 @@ gunicorn = [
|
|||
{file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"},
|
||||
]
|
||||
har2tree = [
|
||||
{file = "har2tree-1.13.2-py3-none-any.whl", hash = "sha256:e96db03800fe67b352c0c564c3f58ac6ce2e261fe64d15ec7f4e0b81c3a8edaa"},
|
||||
{file = "har2tree-1.13.2.tar.gz", hash = "sha256:c05c0952ae5c9af7d9d01c7362aa23c4060e8a48b8d6daa1f44ce70a1a8cfff3"},
|
||||
{file = "har2tree-1.13.3-py3-none-any.whl", hash = "sha256:1cb921d3dfd9048244edcfc1aa01e5f0884248bf0cc39aafa18165eaed393db9"},
|
||||
{file = "har2tree-1.13.3.tar.gz", hash = "sha256:7481696e9c4f2907d4df391027e4c4ee01b03f4a588a726dc1904035c0d959af"},
|
||||
]
|
||||
hiredis = [
|
||||
{file = "hiredis-2.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b4c8b0bc5841e578d5fb32a16e0c305359b987b850a06964bd5a62739d688048"},
|
||||
|
@ -1828,8 +1837,8 @@ jinja2 = [
|
|||
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
|
||||
]
|
||||
jsonschema = [
|
||||
{file = "jsonschema-4.8.0-py3-none-any.whl", hash = "sha256:58bb77251318cef5e1179e33dd6e7a008a3c6c638487ab4d943c2f370cc31a1a"},
|
||||
{file = "jsonschema-4.8.0.tar.gz", hash = "sha256:c1d410e379b210ba903bee6adf3fce6d5204cea4c2b622d63f914d2dbfef0993"},
|
||||
{file = "jsonschema-4.9.0-py3-none-any.whl", hash = "sha256:5d0be0cd1b670438b71c3d3145b2abba1f9d197e3e91adc4c4bae4c0e114e252"},
|
||||
{file = "jsonschema-4.9.0.tar.gz", hash = "sha256:df10e65c8f3687a48e93d0d348ce0ce5f897b5a28e9bbcbbe8f7c7eaf019e850"},
|
||||
]
|
||||
lief = [
|
||||
{file = "lief-0.12.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:4fbbc9d520de87ac22210c62d22a9b088e5460f9a028741311e6f68ef8877ddd"},
|
||||
|
@ -2147,6 +2156,10 @@ pillow = [
|
|||
{file = "Pillow-9.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927"},
|
||||
{file = "Pillow-9.2.0.tar.gz", hash = "sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04"},
|
||||
]
|
||||
pkgutil-resolve-name = [
|
||||
{file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"},
|
||||
{file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"},
|
||||
]
|
||||
playwright = [
|
||||
{file = "playwright-1.24.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:942c938a8fc8d5daa01cf4e2ca7dfd4cad9216e3e0af88992c083dd324f9210e"},
|
||||
{file = "playwright-1.24.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fbc74dd91c0c00d282d340b6d08d22010279cbe84052afe0f0854dc1e3a51315"},
|
||||
|
@ -2425,20 +2438,20 @@ types-python-dateutil = [
|
|||
{file = "types_python_dateutil-2.8.19-py3-none-any.whl", hash = "sha256:6284df1e4783d8fc6e587f0317a81333856b872a6669a282f8a325342bce7fa8"},
|
||||
]
|
||||
types-redis = [
|
||||
{file = "types-redis-4.3.11.tar.gz", hash = "sha256:83e5633f216c729fb39c5d3f71dd3b0080c651f75b5d4128733878512409c744"},
|
||||
{file = "types_redis-4.3.11-py3-none-any.whl", hash = "sha256:ba4612407a758353aa4fe5e1e4b804126e1160dbd6797840223958b1b5dda34d"},
|
||||
{file = "types-redis-4.3.13.tar.gz", hash = "sha256:b8334a96a2f431521bfa72205b343129acdc5a646ffcfb304d80a1cd0deff548"},
|
||||
{file = "types_redis-4.3.13-py3-none-any.whl", hash = "sha256:cc2209ecfab2ad6df1e3eec730c06f9b2dec77f4164eb86e04dad455a651b394"},
|
||||
]
|
||||
types-requests = [
|
||||
{file = "types-requests-2.28.5.tar.gz", hash = "sha256:ac618bfefcb3742eaf97c961e13e9e5a226e545eda4a3dbe293b898d40933ad1"},
|
||||
{file = "types_requests-2.28.5-py3-none-any.whl", hash = "sha256:98ab647ae88b5e2c41d6d20cfcb5117da1bea561110000b6fdeeea07b3e89877"},
|
||||
{file = "types-requests-2.28.6.tar.gz", hash = "sha256:cf3383bbd79394bf051a0a9202d6831fa962f186f923c178f7c059e3424bd00e"},
|
||||
{file = "types_requests-2.28.6-py3-none-any.whl", hash = "sha256:d8d7607419cd4b41a7b9497e15e8c0bad78d50df43c48ad25bc526a11518c3a9"},
|
||||
]
|
||||
types-setuptools = [
|
||||
{file = "types-setuptools-63.2.2.tar.gz", hash = "sha256:a9aa0c01d5f3443cd544026d5ffc97b95ddadf731dab13419c393d43fd8617c0"},
|
||||
{file = "types_setuptools-63.2.2-py3-none-any.whl", hash = "sha256:a370df7a1e0dc856af9d998234f6e2ab04f30f25b8e1410f6db65910979f6252"},
|
||||
]
|
||||
types-urllib3 = [
|
||||
{file = "types-urllib3-1.26.17.tar.gz", hash = "sha256:73fd274524c3fc7cd8cd9ceb0cb67ed99b45f9cb2831013e46d50c1451044800"},
|
||||
{file = "types_urllib3-1.26.17-py3-none-any.whl", hash = "sha256:0d027fcd27dbb3cb532453b4d977e05bc1e13aefd70519866af211b3003d895d"},
|
||||
{file = "types-urllib3-1.26.20.tar.gz", hash = "sha256:1fb6e2af519a7216a19dd6be8cd2ee787b402a754ccb4a13ca1c0e5b202aea5a"},
|
||||
{file = "types_urllib3-1.26.20-py3-none-any.whl", hash = "sha256:6249b6223226cb2012db3b4ff6945c9cb0e12ece9b24f5e29787c4f05028a979"},
|
||||
]
|
||||
types-werkzeug = [
|
||||
{file = "types-Werkzeug-1.0.9.tar.gz", hash = "sha256:5cc269604c400133d452a40cee6397655f878fc460e03fde291b9e3a5eaa518c"},
|
||||
|
|
|
@ -63,7 +63,7 @@ pyhashlookup = "^1.2.0"
|
|||
lief = "^0.12.1"
|
||||
ua-parser = "^0.15.0"
|
||||
Flask-Login = "^0.6.2"
|
||||
har2tree = "^1.13.2"
|
||||
har2tree = "^1.13.3"
|
||||
playwrightcapture = "^1.13.4"
|
||||
passivetotal = "^2.5.9"
|
||||
werkzeug = "2.1.2"
|
||||
|
@ -74,8 +74,8 @@ misp = ['python-magic', 'pydeep2']
|
|||
[tool.poetry.dev-dependencies]
|
||||
mypy = "^0.971"
|
||||
ipython = "^8.4.0"
|
||||
types-redis = "^4.3.11"
|
||||
types-requests = "^2.28.5"
|
||||
types-redis = "^4.3.13"
|
||||
types-requests = "^2.28.6"
|
||||
types-Flask = "^1.1.6"
|
||||
types-pkg-resources = "^0.1.3"
|
||||
types-Deprecated = "^1.2.9"
|
||||
|
|
|
@ -8,7 +8,7 @@ import os
|
|||
import time
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
from io import BytesIO, StringIO
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
from typing import Any, Dict, List, Optional, Union, TypedDict
|
||||
from urllib.parse import quote_plus, unquote_plus, urlparse
|
||||
|
||||
import flask_login # type: ignore
|
||||
|
@ -160,6 +160,38 @@ def get_sri(directory: str, filename: str) -> str:
|
|||
app.jinja_env.globals.update(get_sri=get_sri)
|
||||
|
||||
|
||||
class Icon(TypedDict):
|
||||
icon: str
|
||||
tooltip: str
|
||||
|
||||
|
||||
def get_icon(icon_id: str) -> Optional[Icon]:
|
||||
available_icons: Dict[str, Icon] = {
|
||||
'js': {'icon': "javascript.png", 'tooltip': 'The content of the response is a javascript'},
|
||||
'exe': {'icon': "exe.png", 'tooltip': 'The content of the response is an executable'},
|
||||
'css': {'icon': "css.png", 'tooltip': 'The content of the response is a CSS'},
|
||||
'font': {'icon': "font.png", 'tooltip': 'The content of the response is a font'},
|
||||
'html': {'icon': "html.png", 'tooltip': 'The content of the response is a HTML document'},
|
||||
'json': {'icon': "json.png", 'tooltip': 'The content of the response is a Json'},
|
||||
'text': {'icon': "json.png", 'tooltip': 'The content of the response is a text'}, # FIXME: Need new icon
|
||||
'iframe': {'icon': "ifr.png", 'tooltip': 'This content is loaded from an Iframe'},
|
||||
'image': {'icon': "img.png", 'tooltip': 'The content of the response is an image'},
|
||||
'unset_mimetype': {'icon': "wtf.png", 'tooltip': 'The type of content of the response is not set'},
|
||||
'octet-stream': {'icon': "wtf.png", 'tooltip': 'The type of content of the response is a binary blob'},
|
||||
'unknown_mimetype': {'icon': "wtf.png", 'tooltip': 'The type of content of the response is of an unknown type'},
|
||||
'video': {'icon': "video.png", 'tooltip': 'The content of the response is a video'},
|
||||
'livestream': {'icon': "video.png", 'tooltip': 'The content of the response is a livestream'},
|
||||
'response_cookie': {'icon': "cookie_received.png", 'tooltip': 'There are cookies in the response'},
|
||||
'request_cookie': {'icon': "cookie_read.png", 'tooltip': 'There are cookies in the request'},
|
||||
'redirect': {'icon': "redirect.png", 'tooltip': 'The request is redirected'},
|
||||
'redirect_to_nothing': {'icon': "cookie_in_url.png", 'tooltip': 'The request is redirected to an URL we do not have in the capture'}
|
||||
}
|
||||
return available_icons.get(icon_id)
|
||||
|
||||
|
||||
app.jinja_env.globals.update(get_icon=get_icon)
|
||||
|
||||
|
||||
# ##### Generic/configuration methods #####
|
||||
|
||||
@app.after_request
|
||||
|
@ -201,30 +233,6 @@ def urls_hostnode(tree_uuid: str, node_uuid: str):
|
|||
|
||||
@app.route('/tree/<string:tree_uuid>/host/<string:node_uuid>', methods=['GET'])
|
||||
def hostnode_popup(tree_uuid: str, node_uuid: str):
|
||||
keys_response = {
|
||||
'js': {'icon': "javascript.png", 'tooltip': 'The content of the response is a javascript'},
|
||||
'exe': {'icon': "exe.png", 'tooltip': 'The content of the response is an executable'},
|
||||
'css': {'icon': "css.png", 'tooltip': 'The content of the response is a CSS'},
|
||||
'font': {'icon': "font.png", 'tooltip': 'The content of the response is a font'},
|
||||
'html': {'icon': "html.png", 'tooltip': 'The content of the response is a HTML document'},
|
||||
'json': {'icon': "json.png", 'tooltip': 'The content of the response is a Json'},
|
||||
'text': {'icon': "json.png", 'tooltip': 'The content of the response is a text'}, # FIXME: Need new icon
|
||||
'iframe': {'icon': "ifr.png", 'tooltip': 'This content is loaded from an Iframe'},
|
||||
'image': {'icon': "img.png", 'tooltip': 'The content of the response is an image'},
|
||||
'unset_mimetype': {'icon': "wtf.png", 'tooltip': 'The type of content of the response is not set'},
|
||||
'octet-stream': {'icon': "wtf.png", 'tooltip': 'The type of content of the response is a binary blob'},
|
||||
'unknown_mimetype': {'icon': "wtf.png", 'tooltip': 'The type of content of the response is of an unknown type'},
|
||||
'video': {'icon': "video.png", 'tooltip': 'The content of the response is a video'},
|
||||
'livestream': {'icon': "video.png", 'tooltip': 'The content of the response is a livestream'},
|
||||
'response_cookie': {'icon': "cookie_received.png", 'tooltip': 'There are cookies in the response'},
|
||||
# redirect has to be last
|
||||
'redirect': {'icon': "redirect.png", 'tooltip': 'The request is redirected'},
|
||||
'redirect_to_nothing': {'icon': "cookie_in_url.png", 'tooltip': 'The request is redirected to an URL we do not have in the capture'}
|
||||
}
|
||||
keys_request = {
|
||||
'request_cookie': {'icon': "cookie_read.png", 'tooltip': 'There are cookies in the request'}
|
||||
}
|
||||
|
||||
try:
|
||||
hostnode, urls = lookyloo.get_hostnode_investigator(tree_uuid, node_uuid)
|
||||
except IndexError:
|
||||
|
@ -235,8 +243,6 @@ def hostnode_popup(tree_uuid: str, node_uuid: str):
|
|||
hostnode_uuid=node_uuid,
|
||||
hostnode=hostnode,
|
||||
urls=urls,
|
||||
keys_response=keys_response,
|
||||
keys_request=keys_request,
|
||||
enable_context_by_users=enable_context_by_users,
|
||||
uwhois_available=lookyloo.uwhois.available)
|
||||
|
||||
|
@ -683,6 +689,12 @@ def mark_as_legitimate(tree_uuid: str):
|
|||
return jsonify({'message': 'Legitimate entry added.'})
|
||||
|
||||
|
||||
@app.route('/tree/<string:tree_uuid>/body_hashes', methods=['GET'])
|
||||
def tree_body_hashes(tree_uuid: str):
|
||||
body_hashes = lookyloo.get_all_body_hashes(tree_uuid)
|
||||
return render_template('tree_body_hashes.html', tree_uuid=tree_uuid, body_hashes=body_hashes)
|
||||
|
||||
|
||||
# ##### helpers #####
|
||||
|
||||
def index_generic(show_hidden: bool=False, show_error: bool=True, category: Optional[str]=None):
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
"exe.png": "pWwo9nBLtEss/UJ173zHa6/RpySUyz/XMdNhWc6aRIvwwHMO6a+fLmu2K6TbvO3Jbg4VYL2Af4yhHPyhH3ZeTw==",
|
||||
"favicon.ico": "KOmrfwRbOQqhhwSeBkNpMRAxSVMmmLg+2kRMg9iSv7OWjE9spJc7x4MKB4AE/hi0knaV7UBVctAU6XZ7AC72ZA==",
|
||||
"font.png": "RwoQkj9dT9SLUL2F7cAA16Nat9t2hDb58eQlHF9ThUar829p0INUXG+5XuDaFOC8SsmCZK5vw2f+YAQ6mLC1Qw==",
|
||||
"generic.css": "6pYUMp7DzXI/O531PJ2PIB0/ce0TdIWEOEC4RfpcbMK2SRgKkZfGn12aixsTJEzAkF8Ao0/Bz405v3Bl0f7RUQ==",
|
||||
"generic.css": "Sh/BcxFMLYYaLdCluVt9efGvJ9CF5d+YJ7lkL2M24PRGu8VZHI9lJiUlFObIocjQgwss3Ve2U5cUAE5WiAdpQQ==",
|
||||
"generic.js": "UmFl4fHmB/UjMdUuYdFy9BfzQlJTyeImNHCFyBO4SdLxBCwCGxkF3NQvel1PKqW8JTnoPlPpq/n9d+vCfPeegA==",
|
||||
"html.png": "T7pZrb8MMDsA/JV/51hu+TOglTqlxySuEVY0rpDjTuAEyhzk2v+W4kYrj7vX+Tp3n2d2lvVD08PwhCG62Yfbzg==",
|
||||
"ifr.png": "rI5YJypmz1QcULRf9UaOYSqV4tPUSxUdLAycoYzCwywt4Pw4eWzBg9SUr769VyIimoiIyJR+aNuoIA4p5WO2fQ==",
|
||||
|
|
|
@ -59,7 +59,6 @@ table td p {
|
|||
font-smooth: auto;
|
||||
color: white;
|
||||
background: black;
|
||||
z-index: 1;
|
||||
border: 2px solid;
|
||||
border-color: white;
|
||||
padding-top: 2px;
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
{% from "macros.html" import ressource_legitimacy_details %}
|
||||
{% from "macros.html" import indexed_hash %}
|
||||
{% from "macros.html" import indexed_cookies %}
|
||||
{% from "macros.html" import popup_icons %}
|
||||
{% from "macros.html" import popup_icons_request %}
|
||||
{% from "macros.html" import popup_icons_response %}
|
||||
{% from "macros.html" import shorten_string %}
|
||||
{% from "macros.html" import other_captures_table %}
|
||||
{% from "macros.html" import get_ressource_button %}
|
||||
|
@ -142,7 +143,7 @@
|
|||
|
||||
<li class="list-group-item">
|
||||
<p class="h4">Request</p>
|
||||
{{ popup_icons(keys_request, url['url_object'], tree_uuid) }}
|
||||
{{ popup_icons_request(url['url_object'], tree_uuid) }}
|
||||
|
||||
{% if url['url_object'].posted_data %}
|
||||
<a href="{{ url_for('urlnode_post_request', tree_uuid=tree_uuid, node_uuid=url['url_object'].uuid) }}">
|
||||
|
@ -179,7 +180,7 @@
|
|||
<span>Load time: {{ url['url_object'].time.total_seconds() }}s</span>
|
||||
</small>
|
||||
</p>
|
||||
{{ popup_icons(keys_response, url['url_object'], tree_uuid) }}
|
||||
{{ popup_icons_response(url['url_object'], tree_uuid) }}
|
||||
|
||||
{% if url['url_object'].rendered_html %}
|
||||
<a href="{{ url_for('urlnode_rendered_content', tree_uuid=tree_uuid, node_uuid=url['url_object'].uuid) }}">
|
||||
|
|
|
@ -258,55 +258,62 @@
|
|||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro popup_icons(lookup_dict, urlnode, tree_uuid) %}
|
||||
{% macro popup_icons_request(urlnode, tree_uuid) %}
|
||||
<div>
|
||||
{% for key, icon_info in lookup_dict.items() %}
|
||||
{% if urlnode[key] %}
|
||||
{% if key == "request_cookie" %}
|
||||
{% 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"/>
|
||||
<img src="{{ url_for('static', filename=icon_info['icon']) }}" alt="{{ icon_info['tooltip'] }}"
|
||||
width="21" height="21"/>
|
||||
</a>
|
||||
{% elif key == "response_cookie"%}
|
||||
{% endif %}
|
||||
</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>
|
||||
{% elif key in ["js", "exe", "css", "font", "html", "json", "image", "video",
|
||||
"unknown_mimetype", "text", "unset_mimetype", "octet-stream", "livestream"]
|
||||
and not urlnode.empty_response %}
|
||||
<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 key == "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>
|
||||
{% elif key != "redirect" %}
|
||||
<img src="{{ url_for('static', filename=icon_info['icon']) }}"
|
||||
alt="{{ icon_info['tooltip'] }}" title="{{ icon_info['tooltip'] }}" width="21" height="21"/>
|
||||
{%endif%}
|
||||
{% 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%}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% if "redirect" in lookup_dict and urlnode["redirect"] %}
|
||||
{% 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) }}
|
||||
<a href="#/" role="button" onclick="whereAmI('{{ child.hostnode_uuid }}')" title="See the node the URL redirects to.">
|
||||
<img src="{{ url_for('static', filename=lookup_dict['redirect']['icon']) }}" alt="{{ lookup_dict['redirect']['tooltip'] }}" width="21" height="21"/>
|
||||
<img src="{{ url_for('static', filename=icon_info['icon']) }}" alt="{{ icon_info['tooltip'] }}" width="21" height="21"/>
|
||||
</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<img src="{{ url_for('static', filename=lookup_dict['redirect']['icon']) }}"
|
||||
alt="{{ lookup_dict['redirect']['tooltip'] }}" title="{{ lookup_dict['redirect']['tooltip'] }}"
|
||||
<img src="{{ url_for('static', filename=icon_info['icon']) }}"
|
||||
alt="{{ icon_info['tooltip'] }}" title="{{ icon_info['tooltip'] }}"
|
||||
width="21" height="21"/>
|
||||
{% endfor %}
|
||||
{%endif%}
|
||||
|
|
|
@ -82,6 +82,13 @@
|
|||
});
|
||||
</script>
|
||||
<script>
|
||||
$('#bodyHashesModal').on('show.bs.modal', function(e) {
|
||||
var button = $(e.relatedTarget);
|
||||
var modal = $(this);
|
||||
modal.find('.modal-body').load(button.data("remote"));
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$('#mispPushModal').on('show.bs.modal', function(e) {
|
||||
var button = $(e.relatedTarget);
|
||||
var modal = $(this);
|
||||
|
@ -213,6 +220,10 @@
|
|||
<a href="#statsModal" data-remote="{{ url_for('stats', tree_uuid=tree_uuid) }}"
|
||||
data-bs-toggle="modal" data-bs-target="#statsModal" role="button">Tree Statistics</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#bodyHashesModal" data-remote="{{ url_for('tree_body_hashes', tree_uuid=tree_uuid) }}"
|
||||
data-bs-toggle="modal" data-bs-target="#bodyHashesModal" role="button">Tree ressources</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#modulesModal" data-remote="{{ url_for('trigger_modules', tree_uuid=tree_uuid, force=False) }}"
|
||||
data-bs-toggle="modal" data-bs-target="#modulesModal" role="button">Third Party Reports</a>
|
||||
|
@ -453,6 +464,23 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="bodyHashesModal" 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="bodyHashesModalLabel">Ressources in tree</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
... loading ressources ...
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="mispPushModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<script type="text/javascript">
|
||||
$('#bodyHashesTable')
|
||||
.on('order.dt', () => {
|
||||
$(function () {
|
||||
$('[data-bs-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
})
|
||||
.on('search.dt', () => {
|
||||
$(function () {
|
||||
$('[data-bs-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
})
|
||||
.on('page.dt', () => {
|
||||
$(function () {
|
||||
$('[data-bs-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
})
|
||||
.DataTable( {
|
||||
"order": [[ 1, "desc" ]],
|
||||
"pageLength": 50
|
||||
});
|
||||
</script>
|
||||
|
||||
{% if from_popup %}
|
||||
<script type="text/javascript">
|
||||
function openTreeInNewTab(treeUUID) {
|
||||
window.opener.openTreeInNewTab(treeUUID);
|
||||
};
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table id="bodyHashesTable" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>File type</th>
|
||||
<th>Captures total</th>
|
||||
<th>Hash (sha512)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for body_hash, info in body_hashes.items() %}
|
||||
{% set icon_info = get_icon(info['node'].generic_type) %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('get_ressource', tree_uuid=tree_uuid, node_uuid=info['node'].uuid) }}">
|
||||
<img src="{{ url_for('static', filename=icon_info['icon']) }}" alt="{{ icon_info['tooltip'] }}"
|
||||
width="21" height="21"
|
||||
{% if info['node'].generic_type == "image" %}
|
||||
data-bs-toggle="tooltip" data-bs-placement="left" data-bs-html="true" data-container="#bodyHashesTable"
|
||||
title='<img class="ressource_preview" src="{{ url_for('get_ressource_preview', tree_uuid=tree_uuid, node_uuid=info['node'].uuid) }}"/> </br>Click to download.'
|
||||
{% else %}
|
||||
data-bs-toggle="tooltip" data-bs-placement="left" data-bs-html="true" data-container="#bodyHashesTable"
|
||||
title="{{icon_info['tooltip']}} <br/>Click to download."
|
||||
{% endif %}
|
||||
/>
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ info['total_captures'] }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('body_hash_details', body_hash=body_hash) }}">{{body_hash}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
Loading…
Reference in New Issue