feat: add proxy template origin field and implement socket utilities for log streaming

This commit is contained in:
gabdevele
2026-05-07 10:54:57 +02:00 Unverified
parent 53dcdafdb1
commit 354ec150bc
32 changed files with 1681 additions and 1214 deletions
+40
View File
@@ -0,0 +1,40 @@
id: http-block-admin-paths
name: Block admin and debug paths
protocol: http
description: Protects common admin, console, and debug endpoints.
category: http
family: web-hardening
tags:
- admin-path
- debug-path
- web
- block
action: block
summary: Protects common admin, console, and debug endpoints.
behavior: Matches the request path against a small denylist and returns a blank 404
page before the request is forwarded.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import http
BLOCKED_PREFIXES = (
"/admin",
"/debug",
"/console",
"/actuator",
)
def request(flow: http.HTTPFlow) -> None:
if flow.request.path.startswith(BLOCKED_PREFIXES):
logging.warning(
"[http-block-admin-paths] blocked path=%s",
flow.request.path,
)
flow.response = http.Response.make(
404,
b"",
{"content-type": "text/html; charset=utf-8"},
)
@@ -0,0 +1,46 @@
id: http-block-blacklisted-substrings
name: Block blacklisted substrings
protocol: http
description: Blocks requests containing forbidden strings in path, query, or body.
category: http
family: web-hardening
tags:
- blacklist-string
- web
- block
action: block
summary: Blocks requests containing forbidden strings in path, query, or body.
behavior: Scans URL and request body for blacklisted markers, then serves a blank
HTML page with 200 OK and logs the first hit.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import http
BLOCKED_STRINGS = (
"flag{",
"give_me_shell",
"debug=1",
"/etc/passwd",
)
def request(flow: http.HTTPFlow) -> None:
body = flow.request.get_text(strict=False)
haystack = "\n".join(
[flow.request.path, str(flow.request.query), body]
).lower()
for marker in BLOCKED_STRINGS:
if marker.lower() in haystack:
logging.warning(
"[http-block-blacklisted-substrings] blocked marker=%r url=%s",
marker,
flow.request.pretty_url,
)
flow.response = http.Response.make(
200,
b"",
{"content-type": "text/html; charset=utf-8"},
)
return
@@ -0,0 +1,37 @@
id: http-block-command-injection-markers
name: Block command injection markers
protocol: http
description: Rejects obvious shell metacharacters and command-substitution markers.
category: http
family: web-hardening
tags:
- command-injection
- web
- block
action: block
summary: Rejects obvious shell metacharacters and command-substitution markers.
behavior: Scans URL and body for shell-style injection markers, logs the first hit,
and drops the client connection.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import http
BLOCKED_MARKERS = (";", "&&", "||", "$(", "`", "|sh", "|bash")
def request(flow: http.HTTPFlow) -> None:
body = flow.request.get_text(strict=False)
haystack = "\n".join(
[flow.request.pretty_url, body]
).lower()
for marker in BLOCKED_MARKERS:
if marker in haystack:
logging.warning(
"[http-block-command-injection-markers] blocked marker=%r url=%s",
marker,
flow.request.pretty_url,
)
flow.kill()
return
+37
View File
@@ -0,0 +1,37 @@
id: http-block-large-body
name: Block large request bodies
protocol: http
description: Rejects oversized HTTP request bodies before they hit the service.
category: http
family: web-hardening
tags:
- length-limit
- body-size
- web
- block
action: block
summary: Rejects oversized HTTP request bodies before they hit the service.
behavior: Checks the buffered request body length, returns 413 Payload Too Large,
and logs the observed size.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import http
MAX_BODY_BYTES = 8192
def request(flow: http.HTTPFlow) -> None:
size = len(flow.request.raw_content or b"")
if size > MAX_BODY_BYTES:
logging.warning(
"[http-block-large-body] blocked %s bytes on %s",
size,
flow.request.pretty_url,
)
flow.response = http.Response.make(
413,
b"",
{"content-type": "text/plain"},
)
+48
View File
@@ -0,0 +1,48 @@
id: http-block-path-traversal
name: Block path traversal
protocol: http
description: Stops common path traversal probes in path and query.
category: http
family: web-hardening
tags:
- path-traversal
- web
- block
action: block
summary: Stops common path traversal probes in path and query.
behavior: Logs the matched traversal token and immediately drops the client connection
before the request reaches the upstream service.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from urllib.parse import unquote
from mitmproxy import http
TRAVERSAL_MARKERS = (
"../",
"..\\",
"%2e%2e",
"%252e%252e",
"..%2f",
"..%5c",
)
def request(flow: http.HTTPFlow) -> None:
raw_target = (
f"{flow.request.path}?{flow.request.query}"
if flow.request.query
else flow.request.path
)
normalized = unquote(unquote(raw_target)).lower()
for marker in TRAVERSAL_MARKERS:
if marker in normalized:
logging.warning(
"[http-block-path-traversal] blocked %s %s from %s",
flow.request.method,
flow.request.pretty_url,
flow.client_conn.peername,
)
flow.kill()
return
+48
View File
@@ -0,0 +1,48 @@
id: http-block-sqli-markers
name: Block obvious SQLi markers
protocol: http
description: Stops common SQL injection probes before they reach the app.
category: http
family: web-hardening
tags:
- sqli
- web
- block
action: block
summary: Stops common SQL injection probes before they reach the app.
behavior: Matches a short list of high-signal SQLi markers in path, query, and body,
then serves a blank HTML page and logs the hit.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import http
BLOCKED_MARKERS = (
"' or 1=1",
'" or 1=1',
"union select",
"sleep(",
"information_schema",
"--",
)
def request(flow: http.HTTPFlow) -> None:
body = flow.request.get_text(strict=False)
haystack = "\n".join(
[flow.request.path, str(flow.request.query), body]
).lower()
for marker in BLOCKED_MARKERS:
if marker in haystack:
logging.warning(
"[http-block-sqli-markers] blocked marker=%r url=%s",
marker,
flow.request.pretty_url,
)
flow.response = http.Response.make(
200,
b"",
{"content-type": "text/html; charset=utf-8"},
)
return
@@ -0,0 +1,35 @@
id: http-block-suspicious-methods
name: Block suspicious HTTP methods
protocol: http
description: Denies uncommon or dangerous HTTP methods.
category: http
family: web-hardening
tags:
- method-filter
- web
- block
action: block
summary: Denies uncommon or dangerous HTTP methods.
behavior: Returns 405 Method Not Allowed for methods outside the allowlist and logs
the blocked method and target URL.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import http
ALLOWED_METHODS = {"GET", "POST", "HEAD"}
def request(flow: http.HTTPFlow) -> None:
if flow.request.method not in ALLOWED_METHODS:
logging.warning(
"[http-block-suspicious-methods] blocked method=%s url=%s",
flow.request.method,
flow.request.pretty_url,
)
flow.response = http.Response.make(
405,
b"",
{"allow": "GET, POST, HEAD"},
)
@@ -0,0 +1,40 @@
id: http-sanitize-headers-basic
name: Sanitize risky forwarding headers
protocol: http
description: Removes a few risky forwarding headers before the request is sent upstream.
category: http
family: web-hardening
tags:
- rewrite
- headers
- web
action: rewrite
summary: Removes a few risky forwarding headers before the request is sent upstream.
behavior: Deletes selected override or forwarding headers and logs what was rewritten
without blocking the request.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import http
STRIP_HEADERS = (
"x-forwarded-host",
"x-http-method-override",
"x-original-url",
"x-rewrite-url",
)
def request(flow: http.HTTPFlow) -> None:
removed = []
for header in STRIP_HEADERS:
if header in flow.request.headers:
removed.append(header)
del flow.request.headers[header]
if removed:
logging.info(
"[http-sanitize-headers-basic] stripped headers=%s url=%s",
",".join(removed),
flow.request.pretty_url,
)
@@ -0,0 +1,41 @@
id: tcp-block-blacklisted-byte-sequences
name: Block blacklisted TCP byte sequences
protocol: tcp
description: Blocks payloads containing forbidden byte sequences or marker strings.
category: tcp
family: tcp-hardening
tags:
- blacklist-bytes
- tcp
- block
action: block
summary: Blocks payloads containing forbidden byte sequences or marker strings.
behavior: Looks for dangerous byte patterns in client messages, then drops the message
and closes the flow.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import tcp
BLOCKED_SEQUENCES = (
b"/bin/sh",
b"cat flag",
b"AAAA%p%p",
b"\x90\x90\x90\x90",
)
def tcp_message(flow: tcp.TCPFlow) -> None:
message = flow.messages[-1]
if not message.from_client:
return
for sequence in BLOCKED_SEQUENCES:
if sequence in message.content:
logging.warning(
"[tcp-block-blacklisted-byte-sequences] blocked sequence=%r",
sequence,
)
message.drop()
flow.kill()
return
@@ -0,0 +1,35 @@
id: tcp-block-message-length-threshold
name: Block oversized TCP messages
protocol: tcp
description: Cuts off client messages that exceed a fixed size threshold.
category: tcp
family: tcp-hardening
tags:
- length-limit
- tcp
- block
action: block
summary: Cuts off client messages that exceed a fixed size threshold.
behavior: Checks every client TCP message size, logs the offending length, drops the
message, and kills the flow when the threshold is hit.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import tcp
MAX_MESSAGE_BYTES = 4096
def tcp_message(flow: tcp.TCPFlow) -> None:
message = flow.messages[-1]
if not message.from_client:
return
size = len(message.content)
if size > MAX_MESSAGE_BYTES:
logging.warning(
"[tcp-block-message-length-threshold] blocked message size=%d",
size,
)
message.drop()
flow.kill()
@@ -0,0 +1,42 @@
id: tcp-block-non-printable-threshold
name: Block binary-noise threshold
protocol: tcp
description: Blocks client messages with an excessive amount of non-printable bytes.
category: tcp
family: tcp-hardening
tags:
- non-printable
- binary-noise
- tcp
- block
action: block
summary: Blocks client messages with an excessive amount of non-printable bytes.
behavior: Treats unusually binary-heavy client payloads as suspicious, logs the ratio,
and closes the flow when the threshold is exceeded.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import tcp
NON_PRINTABLE_RATIO = 0.35
def tcp_message(flow: tcp.TCPFlow) -> None:
message = flow.messages[-1]
if not message.from_client or not message.content:
return
non_printable = sum(
1
for byte in message.content
if byte < 0x20 and byte not in {0x09, 0x0a, 0x0d}
)
ratio = non_printable / len(message.content)
if ratio > NON_PRINTABLE_RATIO:
logging.warning(
"[tcp-block-non-printable-threshold] blocked ratio=%.2f size=%d",
ratio,
len(message.content),
)
message.drop()
flow.kill()
@@ -0,0 +1,54 @@
id: tcp-block-repeated-byte-threshold
name: Block repeated-byte flood
protocol: tcp
description: Closes connections that send suspiciously long runs of the same byte.
category: tcp
family: tcp-hardening
tags:
- bof
- repeated-byte
- tcp
- block
action: block
summary: Closes connections that send suspiciously long runs of the same byte.
behavior: Measures the longest repeated-byte run in each client message, logs the
byte and run length, and closes the TCP flow on threshold hit.
source_url: https://docs.mitmproxy.org/stable/addons/examples/
code: |
import logging
from mitmproxy import tcp
MAX_REPEAT = 128
def longest_run(data: bytes) -> tuple[int, int]:
best_byte = -1
best_run = 0
current_byte = -1
current_run = 0
for byte in data:
if byte == current_byte:
current_run += 1
else:
current_byte = byte
current_run = 1
if current_run > best_run:
best_byte = byte
best_run = current_run
return best_byte, best_run
def tcp_message(flow: tcp.TCPFlow) -> None:
message = flow.messages[-1]
if not message.from_client:
return
repeated_byte, run_length = longest_run(message.content)
if run_length > MAX_REPEAT:
logging.warning(
"[tcp-block-repeated-byte-threshold] blocked byte=0x%02x run=%d",
repeated_byte,
run_length,
)
message.drop()
flow.kill()