From de871df53bfbec1c52c5a1b05bdbecee2efa1098 Mon Sep 17 00:00:00 2001 From: Gaurav Jain <64748057+errorxyz@users.noreply.github.com> Date: Tue, 28 May 2024 21:40:46 +0530 Subject: [PATCH] Add blockech addon (#6876) * Add blockech addon * Update CHANGELOG.md * [autofix.ci] apply automated fixes * Add tests * [autofix.ci] apply automated fixes * Fix tests * Add suggested changes * [autofix.ci] apply automated fixes * rephrase changelog to be more user-centric --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Maximilian Hils --- CHANGELOG.md | 4 ++- mitmproxy/addons/__init__.py | 2 ++ mitmproxy/addons/block_ech.py | 22 ++++++++++++++++ test/mitmproxy/addons/test_block_ech.py | 34 +++++++++++++++++++++++++ web/src/js/ducks/_options_gen.ts | 2 ++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 mitmproxy/addons/block_ech.py create mode 100644 test/mitmproxy/addons/test_block_ech.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 093fa94f1..bc14175b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ ([#6866](https://github.com/mitmproxy/mitmproxy/pull/6866), @mhils) * Fix slowdown when sending large data over HTTP/2 ([#6875](https://github.com/mitmproxy/mitmproxy/pull/6875), @aib) +* Add an option to strip HTTPS records from DNS responses to block encrypted ClientHellos. + ([#6876](https://github.com/mitmproxy/mitmproxy/pull/6876), @errorxyz) ## 17 April 2024: mitmproxy 10.3.0 @@ -30,7 +32,7 @@ * Fix multipart form content view being unusable. ([#6653](https://github.com/mitmproxy/mitmproxy/pull/6653), @DaniElectra) * Documentation Improvements on CA Certificate Generation - ([#5370](https://github.com/mitmproxy/mitmproxy/pull/5370), @zioalex) + ([#5370](https://github.com/mitmproxy/mitmproxy/pull/5370), @zioalex) * Make it possible to read flows from stdin with mitmweb. ([#6732](https://github.com/mitmproxy/mitmproxy/pull/6732), @jaywor1) * Update aioquic dependency to >= 1.0.0, < 2.0.0. diff --git a/mitmproxy/addons/__init__.py b/mitmproxy/addons/__init__.py index fd36bb0cd..f4b6cb5c3 100644 --- a/mitmproxy/addons/__init__.py +++ b/mitmproxy/addons/__init__.py @@ -1,6 +1,7 @@ from mitmproxy.addons import anticache from mitmproxy.addons import anticomp from mitmproxy.addons import block +from mitmproxy.addons import block_ech from mitmproxy.addons import blocklist from mitmproxy.addons import browser from mitmproxy.addons import clientplayback @@ -34,6 +35,7 @@ def default_addons(): core.Core(), browser.Browser(), block.Block(), + block_ech.BlockECH(), blocklist.BlockList(), anticache.AntiCache(), anticomp.AntiComp(), diff --git a/mitmproxy/addons/block_ech.py b/mitmproxy/addons/block_ech.py new file mode 100644 index 000000000..a0e2d055b --- /dev/null +++ b/mitmproxy/addons/block_ech.py @@ -0,0 +1,22 @@ +from mitmproxy import ctx +from mitmproxy import dns +from mitmproxy.net.dns import types + + +class BlockECH: + def load(self, loader): + loader.add_option( + "block_ech", + bool, + True, + "Strip DNS HTTPS records to prevent clients from sending Encrypted ClientHello (ECH) messages", + ) + + def dns_response(self, flow: dns.DNSFlow): + # TODO: parse HTTPS records and remove ech value alone. For now, + # if HTTPS record is part of response, remove that record. + assert flow.response + if ctx.options.block_ech: + flow.response.answers = [ + answer for answer in flow.response.answers if answer.type != types.HTTPS + ] diff --git a/test/mitmproxy/addons/test_block_ech.py b/test/mitmproxy/addons/test_block_ech.py new file mode 100644 index 000000000..00a1a6baa --- /dev/null +++ b/test/mitmproxy/addons/test_block_ech.py @@ -0,0 +1,34 @@ +from mitmproxy import dns +from mitmproxy.addons import block_ech +from mitmproxy.net.dns import types +from mitmproxy.test import taddons +from mitmproxy.test import tflow +from mitmproxy.test import tutils + + +class TestBlockECH: + def test_simple(self): + be = block_ech.BlockECH() + with taddons.context(be) as tctx: + answers = [ + dns.ResourceRecord( + "dns.google", + dns.types.HTTPS, + dns.classes.IN, + 32, + b"\x08\x08\x08\x08", + ), + dns.ResourceRecord( + "dns.google", dns.types.A, dns.classes.IN, 32, b"\x08\x08\x04\x04" + ), + ] + resp = tutils.tdnsresp(answers=answers) + f = tflow.tdnsflow(resp=resp) + + tctx.configure(be, block_ech=False) + be.dns_response(f) + assert len(f.response.answers) == 2 + + tctx.configure(be, block_ech=True) + be.dns_response(f) + assert not any(answer.type == types.HTTPS for answer in f.response.answers) diff --git a/web/src/js/ducks/_options_gen.ts b/web/src/js/ducks/_options_gen.ts index da939e0bd..d94b9fc62 100644 --- a/web/src/js/ducks/_options_gen.ts +++ b/web/src/js/ducks/_options_gen.ts @@ -4,6 +4,7 @@ export interface OptionsState { allow_hosts: string[]; anticache: boolean; anticomp: boolean; + block_ech: boolean; block_global: boolean; block_list: string[]; block_private: boolean; @@ -100,6 +101,7 @@ export const defaultState: OptionsState = { allow_hosts: [], anticache: false, anticomp: false, + block_ech: true, block_global: true, block_list: [], block_private: false,