Skip to content

Commit 52cda9c

Browse files
committed
fix: [security] csrf in website, and others in modules
- As reported by Bilal Teke
1 parent 89abdc6 commit 52cda9c

5 files changed

Lines changed: 43 additions & 8 deletions

File tree

misp_modules/modules/expansion/html_to_markdown.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import json
2+
import socket
23

34
import requests
5+
import ipaddress
6+
from urllib.parse import urlparse
47
from bs4 import BeautifulSoup
58
from markdownify import markdownify
69

@@ -24,11 +27,44 @@
2427
}
2528

2629

30+
31+
BLOCKED_RANGES = [
32+
ipaddress.ip_network("127.0.0.0/8"),
33+
ipaddress.ip_network("10.0.0.0/8"),
34+
ipaddress.ip_network("172.16.0.0/12"),
35+
ipaddress.ip_network("192.168.0.0/16"),
36+
ipaddress.ip_network("169.254.0.0/16"),
37+
ipaddress.ip_network("::1/128"),
38+
]
39+
40+
def _is_ip_blocked(ip_str: str) -> bool:
41+
ip = ipaddress.ip_address(ip_str)
42+
return any(ip in net for net in BLOCKED_RANGES)
43+
44+
45+
def _hostname_resolves_to_blocked_ip(hostname: str) -> bool:
46+
try:
47+
resolved = socket.getaddrinfo(hostname, None)
48+
return any(_is_ip_blocked(info[4][0]) for info in resolved)
49+
except socket.gaierror:
50+
return True
51+
52+
53+
def is_safe_url(url: str) -> bool:
54+
parsed = urlparse(url)
55+
if parsed.scheme not in ("http", "https"):
56+
return False
57+
try:
58+
return not _is_ip_blocked(parsed.hostname)
59+
except ValueError:
60+
return not _hostname_resolves_to_blocked_ip(parsed.hostname)
61+
2762
def fetchHTML(url):
28-
r = requests.get(url)
63+
if not is_safe_url(url):
64+
raise ValueError(f"Blocked URL: {url}")
65+
r = requests.get(url, timeout=10)
2966
return r.text
3067

31-
3268
def stripUselessTags(html):
3369
soup = BeautifulSoup(html, "html.parser")
3470
toRemove = ["script", "head", "header", "footer", "meta", "link"]

misp_modules/modules/expansion/jinja_template_rendering.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python\
22

33
import json
4+
import logging
45

56
from jinja2.sandbox import SandboxedEnvironment
67

@@ -41,7 +42,8 @@ def handler(q=False):
4142
templateData = data.get("data", {})
4243
try:
4344
rendered = renderTemplate(templateData, template)
44-
except TypeError:
45+
except Exception as e:
46+
logging.warning("Template render failed: %s", type(e).__name__)
4547
rendered = ""
4648

4749
r = {"results": [{"types": mispattributes["output"], "values": [rendered]}]}

misp_modules/modules/expansion/qrcode.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ def fetch_url_image(target_url):
100100
target_url,
101101
headers=headers,
102102
timeout=TIMEOUT_SECONDS,
103-
stream=True,
104-
verify=False
103+
stream=True
105104
) as response: # nosec
106105
response.raise_for_status()
107106

website/app/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ def create_app():
5858
app.register_blueprint(history_blueprint, url_prefix="/")
5959
app.register_blueprint(account_blueprint, url_prefix="/")
6060
app.register_blueprint(external_tools_blueprint, url_prefix="/")
61-
csrf.exempt(home_blueprint)
6261

6362
# Register 404 error handler
6463
@app.errorhandler(404)

website/app/home.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import ast
21
import json
32

43
from flask import Blueprint, jsonify, render_template, request
@@ -23,7 +22,7 @@ def home():
2322

2423
sess["admin_user"] = bool(admin_user_active())
2524
if "query" in request.args:
26-
sess["query"] = ast.literal_eval(request.args.get("query"))
25+
sess["query"] = json.loads(request.args.get("query"))
2726
if "query" in request.form:
2827
sess["query"] = json.loads(request.form.get("query"))
2928
return render_template("home.html")

0 commit comments

Comments
 (0)