mirror of https://github.com/CIRCL/lookyloo
new: Submit to Pandora button for file URLs
parent
f232eba662
commit
f4dfa0343e
|
@ -14,6 +14,11 @@
|
||||||
"autosubmit": false,
|
"autosubmit": false,
|
||||||
"allow_auto_trigger": false
|
"allow_auto_trigger": false
|
||||||
},
|
},
|
||||||
|
"Pandora": {
|
||||||
|
"url": "http://127.0.0.1:6100",
|
||||||
|
"autosubmit": false,
|
||||||
|
"allow_auto_trigger": false
|
||||||
|
},
|
||||||
"SaneJS": {
|
"SaneJS": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"allow_auto_trigger": true
|
"allow_auto_trigger": true
|
||||||
|
@ -70,6 +75,7 @@
|
||||||
"Phishtank": "Module to query Phishtank Lookup (https://github.com/Lookyloo/phishtank-lookup). URL set to none means querying the public instance.",
|
"Phishtank": "Module to query Phishtank Lookup (https://github.com/Lookyloo/phishtank-lookup). URL set to none means querying the public instance.",
|
||||||
"Hashlookup": "Module to query Hashlookup (https://github.com/adulau/hashlookup-server). URL set to none means querying the public instance.",
|
"Hashlookup": "Module to query Hashlookup (https://github.com/adulau/hashlookup-server). URL set to none means querying the public instance.",
|
||||||
"FOX": "Submission only interface by and for CCCS",
|
"FOX": "Submission only interface by and for CCCS",
|
||||||
|
"Pandora": "Submission only interface for https://github.com/pandora-analysis/",
|
||||||
"RiskIQ": "Module to query RiskIQ (https://community.riskiq.com/)"
|
"RiskIQ": "Module to query RiskIQ (https://community.riskiq.com/)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ from .helpers import (CaptureStatus, get_captures_dir, get_email_template,
|
||||||
from .indexing import Indexing
|
from .indexing import Indexing
|
||||||
from .modules import (MISP, PhishingInitiative, UniversalWhois,
|
from .modules import (MISP, PhishingInitiative, UniversalWhois,
|
||||||
UrlScan, VirusTotal, Phishtank, Hashlookup,
|
UrlScan, VirusTotal, Phishtank, Hashlookup,
|
||||||
RiskIQ, RiskIQError)
|
RiskIQ, RiskIQError, Pandora)
|
||||||
|
|
||||||
|
|
||||||
class Lookyloo():
|
class Lookyloo():
|
||||||
|
@ -90,6 +90,10 @@ class Lookyloo():
|
||||||
if not self.riskiq.available:
|
if not self.riskiq.available:
|
||||||
self.logger.warning('Unable to setup the RiskIQ module')
|
self.logger.warning('Unable to setup the RiskIQ module')
|
||||||
|
|
||||||
|
self.pandora = Pandora(get_config('modules', 'Pandora'))
|
||||||
|
if not self.pandora.available:
|
||||||
|
self.logger.warning('Unable to setup the Pandora module')
|
||||||
|
|
||||||
self.logger.info('Initializing context...')
|
self.logger.info('Initializing context...')
|
||||||
self.context = Context()
|
self.context = Context()
|
||||||
self.logger.info('Context initialized.')
|
self.logger.info('Context initialized.')
|
||||||
|
|
|
@ -7,6 +7,7 @@ from .sanejs import SaneJavaScript # noqa
|
||||||
from .urlscan import UrlScan # noqa
|
from .urlscan import UrlScan # noqa
|
||||||
from .uwhois import UniversalWhois # noqa
|
from .uwhois import UniversalWhois # noqa
|
||||||
from .vt import VirusTotal # noqa
|
from .vt import VirusTotal # noqa
|
||||||
|
from .pandora import Pandora # noqa
|
||||||
from .phishtank import Phishtank # noqa
|
from .phishtank import Phishtank # noqa
|
||||||
from .hashlookup import HashlookupModule as Hashlookup # noqa
|
from .hashlookup import HashlookupModule as Hashlookup # noqa
|
||||||
from .riskiq import RiskIQ, RiskIQError # noqa
|
from .riskiq import RiskIQ, RiskIQError # noqa
|
||||||
|
|
|
@ -903,6 +903,20 @@ pdfexport = ["reportlab (>=3.6.11,<4.0.0)"]
|
||||||
url = ["pyfaup (>=1.2,<2.0)", "chardet (>=5.0.0,<6.0.0)"]
|
url = ["pyfaup (>=1.2,<2.0)", "chardet (>=5.0.0,<6.0.0)"]
|
||||||
brotli = ["urllib3[brotli] (>=1.26.11,<2.0.0)"]
|
brotli = ["urllib3[brotli] (>=1.26.11,<2.0.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pypandora"
|
||||||
|
version = "1.0.2"
|
||||||
|
description = "Python CLI and module for pandora"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8,<4.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
requests = ">=2.28.1,<3.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["Sphinx (>=5.1.1,<6.0.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyparsing"
|
name = "pyparsing"
|
||||||
version = "3.0.9"
|
version = "3.0.9"
|
||||||
|
@ -1217,7 +1231,7 @@ python-versions = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "types-redis"
|
name = "types-redis"
|
||||||
version = "4.3.16"
|
version = "4.3.17"
|
||||||
description = "Typing stubs for redis"
|
description = "Typing stubs for redis"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
|
@ -1413,7 +1427,7 @@ misp = ["python-magic", "pydeep2"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = ">=3.8,<3.11"
|
python-versions = ">=3.8,<3.11"
|
||||||
content-hash = "b813c16a36c8bfd612488d2fdfce36b34234e03fae997dc56a6613672c31d9b4"
|
content-hash = "0dcbbf79ed17ddfa5f0f66c8ffa0b0b6025527aa287761d1730a992be6b42dab"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
aiohttp = [
|
aiohttp = [
|
||||||
|
@ -2276,6 +2290,10 @@ pymisp = [
|
||||||
{file = "pymisp-2.4.160.1-py3-none-any.whl", hash = "sha256:3499dc55819e874eeecd7d1b10229cb957600a52452ca5360db3b32f21714718"},
|
{file = "pymisp-2.4.160.1-py3-none-any.whl", hash = "sha256:3499dc55819e874eeecd7d1b10229cb957600a52452ca5360db3b32f21714718"},
|
||||||
{file = "pymisp-2.4.160.1.tar.gz", hash = "sha256:d6cf306100d7c936951db9cb1bff53276a94d75b3ff5ae4c35a952f001169021"},
|
{file = "pymisp-2.4.160.1.tar.gz", hash = "sha256:d6cf306100d7c936951db9cb1bff53276a94d75b3ff5ae4c35a952f001169021"},
|
||||||
]
|
]
|
||||||
|
pypandora = [
|
||||||
|
{file = "pypandora-1.0.2-py3-none-any.whl", hash = "sha256:520801d7e6488ae474e6e1e713db52e12a220749ace68361f863ab1de3f29a96"},
|
||||||
|
{file = "pypandora-1.0.2.tar.gz", hash = "sha256:d8603d68cdd41e5ce9f2b5fcd9a7db0e25bbf3d6bcb99b26d90bfc28ecac81cd"},
|
||||||
|
]
|
||||||
pyparsing = [
|
pyparsing = [
|
||||||
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
||||||
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
||||||
|
@ -2484,8 +2502,8 @@ types-python-dateutil = [
|
||||||
{file = "types_python_dateutil-2.8.19-py3-none-any.whl", hash = "sha256:6284df1e4783d8fc6e587f0317a81333856b872a6669a282f8a325342bce7fa8"},
|
{file = "types_python_dateutil-2.8.19-py3-none-any.whl", hash = "sha256:6284df1e4783d8fc6e587f0317a81333856b872a6669a282f8a325342bce7fa8"},
|
||||||
]
|
]
|
||||||
types-redis = [
|
types-redis = [
|
||||||
{file = "types-redis-4.3.16.tar.gz", hash = "sha256:ed53e35eac4303ef70cf7f5c205e210f2238b7fdd9306b7f8676669c1070943e"},
|
{file = "types-redis-4.3.17.tar.gz", hash = "sha256:03b023c08acf344f4f0821cc1c7e4dbecb7b17bc5483927c3e73d80f7fe1768e"},
|
||||||
{file = "types_redis-4.3.16-py3-none-any.whl", hash = "sha256:41da87dc80f39573a71873e4265f181d9628b0a2a862e850ecc896a0cd6cacd2"},
|
{file = "types_redis-4.3.17-py3-none-any.whl", hash = "sha256:a34c4e7aafa4b2fb9090d3a7f3ad0ac969089c7b4a05c21dff593a0c37405916"},
|
||||||
]
|
]
|
||||||
types-requests = [
|
types-requests = [
|
||||||
{file = "types-requests-2.28.9.tar.gz", hash = "sha256:feaf581bd580497a47fe845d506fa3b91b484cf706ff27774e87659837de9962"},
|
{file = "types-requests-2.28.9.tar.gz", hash = "sha256:feaf581bd580497a47fe845d506fa3b91b484cf706ff27774e87659837de9962"},
|
||||||
|
|
|
@ -67,6 +67,7 @@ playwrightcapture = "^1.14.3"
|
||||||
passivetotal = "^2.5.9"
|
passivetotal = "^2.5.9"
|
||||||
werkzeug = "2.1.2"
|
werkzeug = "2.1.2"
|
||||||
filetype = "^1.1.0"
|
filetype = "^1.1.0"
|
||||||
|
pypandora = "^1.0.2"
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
misp = ['python-magic', 'pydeep2']
|
misp = ['python-magic', 'pydeep2']
|
||||||
|
@ -74,7 +75,7 @@ misp = ['python-magic', 'pydeep2']
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
mypy = "^0.971"
|
mypy = "^0.971"
|
||||||
ipython = "^8.4.0"
|
ipython = "^8.4.0"
|
||||||
types-redis = "^4.3.16"
|
types-redis = "^4.3.17"
|
||||||
types-requests = "^2.28.9"
|
types-requests = "^2.28.9"
|
||||||
types-Flask = "^1.1.6"
|
types-Flask = "^1.1.6"
|
||||||
types-pkg-resources = "^0.1.3"
|
types-pkg-resources = "^0.1.3"
|
||||||
|
|
|
@ -246,6 +246,7 @@ def hostnode_popup(tree_uuid: str, node_uuid: str):
|
||||||
hostnode_uuid=node_uuid,
|
hostnode_uuid=node_uuid,
|
||||||
hostnode=hostnode,
|
hostnode=hostnode,
|
||||||
urls=urls,
|
urls=urls,
|
||||||
|
has_pandora=lookyloo.pandora.available,
|
||||||
enable_context_by_users=enable_context_by_users,
|
enable_context_by_users=enable_context_by_users,
|
||||||
uwhois_available=lookyloo.uwhois.available)
|
uwhois_available=lookyloo.uwhois.available)
|
||||||
|
|
||||||
|
@ -713,6 +714,13 @@ def tree_body_hashes(tree_uuid: str):
|
||||||
return render_template('tree_body_hashes.html', tree_uuid=tree_uuid, body_hashes=body_hashes)
|
return render_template('tree_body_hashes.html', tree_uuid=tree_uuid, body_hashes=body_hashes)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/tree/<string:tree_uuid>/pandora', methods=['GET'])
|
||||||
|
def pandora_submit(tree_uuid: str):
|
||||||
|
filename, content = lookyloo.get_data(tree_uuid)
|
||||||
|
response = lookyloo.pandora.submit_file(content, filename)
|
||||||
|
return jsonify(response)
|
||||||
|
|
||||||
|
|
||||||
# ##### helpers #####
|
# ##### helpers #####
|
||||||
|
|
||||||
def index_generic(show_hidden: bool=False, show_error: bool=True, category: Optional[str]=None):
|
def index_generic(show_hidden: bool=False, show_error: bool=True, category: Optional[str]=None):
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
"stats.css": "/kY943FwWBTne4IIyf7iBROSfbGd82TeBicEXqKkRwawMVRIvM/Pk5MRa7okUyGIxaDjFQGmV/U1vy+PhN6Jbw==",
|
"stats.css": "/kY943FwWBTne4IIyf7iBROSfbGd82TeBicEXqKkRwawMVRIvM/Pk5MRa7okUyGIxaDjFQGmV/U1vy+PhN6Jbw==",
|
||||||
"stats_graph.js": "0OEouA6NAxLG2wMd7D2vtGoMrXKna7My98Euc6ecyfdO4/6mIJS87vzISOS4zSZ8u4ehpa+p7E0nWhsXXE7H/Q==",
|
"stats_graph.js": "0OEouA6NAxLG2wMd7D2vtGoMrXKna7My98Euc6ecyfdO4/6mIJS87vzISOS4zSZ8u4ehpa+p7E0nWhsXXE7H/Q==",
|
||||||
"tree.css": "THJ9LnnSJ91DSTvrYoOCxRrenGgwsgG5zKo+eZLH2rRFHn6lpX9UpmRhRic4th9ZYuM9/NJUS7LqYBDRPPnB1Q==",
|
"tree.css": "THJ9LnnSJ91DSTvrYoOCxRrenGgwsgG5zKo+eZLH2rRFHn6lpX9UpmRhRic4th9ZYuM9/NJUS7LqYBDRPPnB1Q==",
|
||||||
"tree.js": "gHr2HiDbQYfVhBtt95VP6+f7k4neVnfcXV66o4oKg7wB3HVNs/XrTCXpthS3W8yfouySLpZoTVTaPHrAvs5wwg==",
|
"tree.js": "H6ibjUxG7eD+Dz+jFBnERtxTIdR1aPssd86rCrwHH8CHUySn70aCE3mCmGYwNWw0GCpGT1IYWuZ+K0us+selNg==",
|
||||||
"up.jpg": "d1ljZJ9f5JekyM6RLFFH2Ua44j6neiQBdUIXOenRTjGppQr3JaeglpQIH6BjPCJL177+TH52U3UIRNS5YAyKIg==",
|
"up.jpg": "d1ljZJ9f5JekyM6RLFFH2Ua44j6neiQBdUIXOenRTjGppQr3JaeglpQIH6BjPCJL177+TH52U3UIRNS5YAyKIg==",
|
||||||
"up_right.jpg": "OMmz+n+MxR34P8/fn5t4DkqKqdJRzQbXQ7fAi2lhkZIJGhVs2vIyY1f2hpYoBxDAX1OcYsSE2lqIR2vXNDGZsA==",
|
"up_right.jpg": "OMmz+n+MxR34P8/fn5t4DkqKqdJRzQbXQ7fAi2lhkZIJGhVs2vIyY1f2hpYoBxDAX1OcYsSE2lqIR2vXNDGZsA==",
|
||||||
"video.png": "gJtmkfr8I1Kw43pYEKjg6CAjgmhl1vIBKBQ3ZkxCu3wvxQm+6kf93iLrrFiY2WuiXzxEn2Leu52GJzmVN5id0g==",
|
"video.png": "gJtmkfr8I1Kw43pYEKjg6CAjgmhl1vIBKBQ3ZkxCu3wvxQm+6kf93iLrrFiY2WuiXzxEn2Leu52GJzmVN5id0g==",
|
||||||
|
|
|
@ -157,11 +157,7 @@ if (parent_uuid != null) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function openTreeInNewTab(capture_uuid, hostnode_uuid=null) {
|
function openURLInNewTab(url) {
|
||||||
let url = `/tree/${capture_uuid}`;
|
|
||||||
if (hostnode_uuid != null) {
|
|
||||||
url += `/${hostnode_uuid}`;
|
|
||||||
}
|
|
||||||
let win = window.open(url, '_blank');
|
let win = window.open(url, '_blank');
|
||||||
if (win == null) {
|
if (win == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -170,6 +166,14 @@ function openTreeInNewTab(capture_uuid, hostnode_uuid=null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openTreeInNewTab(capture_uuid, hostnode_uuid=null) {
|
||||||
|
let url = `/tree/${capture_uuid}`;
|
||||||
|
if (hostnode_uuid != null) {
|
||||||
|
url += `/${hostnode_uuid}`;
|
||||||
|
}
|
||||||
|
openURLInNewTab(url);
|
||||||
|
}
|
||||||
|
|
||||||
function open_hostnode_popup(hostnode_uuid) {
|
function open_hostnode_popup(hostnode_uuid) {
|
||||||
let win = window.open(`/tree/${treeUUID}/host/${hostnode_uuid}`, '_blank', 'width=1024,height=768,left=200,top=100');
|
let win = window.open(`/tree/${treeUUID}/host/${hostnode_uuid}`, '_blank', 'width=1024,height=768,left=200,top=100');
|
||||||
if (win == null) {
|
if (win == null) {
|
||||||
|
|
|
@ -62,6 +62,28 @@
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<script>
|
||||||
|
function submit_pandora(){
|
||||||
|
fetch("{{ url_for('pandora_submit', tree_uuid=tree_uuid)}}", {
|
||||||
|
method: "GET",
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
openURLInNewTab(data.link)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
throw new Error(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let openURLInNewTab = (url) => {
|
||||||
|
let success = window.opener.openURLInNewTab(url);
|
||||||
|
if (! success) {
|
||||||
|
alert("Your browser doesn't allow Lookyloo to open a new tab. There should be an icon on the right side of your URL bar *in the main window* to allow it.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -183,9 +205,14 @@
|
||||||
{{ popup_icons_response(url['url_object'], tree_uuid) }}
|
{{ popup_icons_response(url['url_object'], tree_uuid) }}
|
||||||
|
|
||||||
{% if url['url_object'].has_dl_file %}
|
{% if url['url_object'].has_dl_file %}
|
||||||
|
{% if has_pandora %}
|
||||||
|
<button id="pandora_submit_button" type="button" class="btn btn-primary" onclick="submit_pandora()">Submit to Pandora</button>
|
||||||
|
{% else %}
|
||||||
<a href="{{ url_for('data', tree_uuid=tree_uuid)}}">
|
<a href="{{ url_for('data', tree_uuid=tree_uuid)}}">
|
||||||
Download {{url['url_object'].downloaded_filename}}
|
Download {{url['url_object'].downloaded_filename}}
|
||||||
</a> ({{sizeof_fmt(url['url_object'].downloaded_filesize)}})
|
</a> ({{sizeof_fmt(url['url_object'].downloaded_filesize)}})
|
||||||
|
{% endif%}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if url['url_object'].rendered_html %}
|
{% if url['url_object'].rendered_html %}
|
||||||
<a href="{{ url_for('urlnode_rendered_content', tree_uuid=tree_uuid, node_uuid=url['url_object'].uuid) }}">
|
<a href="{{ url_for('urlnode_rendered_content', tree_uuid=tree_uuid, node_uuid=url['url_object'].uuid) }}">
|
||||||
|
|
Loading…
Reference in New Issue