sleeyax / burp-awesome-tls

Burp extension to evade TLS fingerprinting. Bypass WAF, spoof any browser.
GNU General Public License v3.0
992 stars 66 forks source link

[Backend] Add customizable HTTP 2 SETTINGS frame #11

Closed sleeyax closed 1 year ago

sleeyax commented 2 years ago

rfc7540

sleeyax commented 1 year ago

Full customization of the frames might be overkill, perhaps we should just set the recommended SETTINGS frame based on the selected browser fingerprint (especially chrome).

ChrisMcMStone commented 1 year ago

Hi @sleeyax. Thanks for your great work with this project. Would be happy to help with this feature. Any tips you could provide to help me get started?

sleeyax commented 1 year ago

Hey @ChrisMcMStone sure thing, thanks for your interest and willingness to contribute to the project! It's been a while but I can point you in a general direction.

The inital settings are created here: https://github.com/sleeyax/burp-awesome-tls/blob/main/src-go/server/internal/net/http2/transport.go#L674 You could patch it like this (this is from a different project of mine, so adjust accordingly):

From 2c399035ddb74e8c40e7f60fba3299b463fd44fd Mon Sep 17 00:00:00 2001
From: Sleeyax <yourd3veloper@gmail.com>
Date: Thu, 3 Jun 2021 21:46:23 +0200
Subject: [PATCH] Customizable initial SETTINGS frame

---
 packages/http2/transport.go | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/packages/http2/transport.go b/packages/http2/transport.go
index ff71e3e..7ab542d 100644
--- a/packages/http2/transport.go
+++ b/packages/http2/transport.go
@@ -89,6 +89,21 @@ type Transport struct {
    // plain-text "http" scheme. Note that this does not enable h2c support.
    AllowHTTP bool

+   // HeaderTableSize is the http2 SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame.
+   HeaderTableSize uint32
+
+   // EnablePush is the http2 SETTINGS_ENABLE_PUSH to send in the initial settings frame.
+   EnablePush uint32
+
+   // MaxConcurrentStreams is the http2 SETTINGS_MAX_CONCURRENT_STREAMS to send in the initial settings frame.
+   MaxConcurrentStreams uint32
+
+   // InitialWindowSize is the http2 SETTINGS_INITIAL_WINDOW_SIZE to send in the initial settings frame.
+   InitialWindowSize uint32
+
+   // MaxFrameSize is the http2 SETTINGS_MAX_FRAME_SIZE to send in the initial settings frame.
+   MaxFrameSize uint32
+
    // MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
    // send in the initial settings frame. It is how many bytes
    // of response headers are allowed. Unlike the http2 spec, zero here
@@ -675,8 +690,11 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
    }

    initialSettings := []Setting{
-       {ID: SettingEnablePush, Val: 0},
-       {ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow},
+       {ID: SettingHeaderTableSize, Val: t.HeaderTableSize},
+       {ID: SettingEnablePush, Val: t.EnablePush},
+       {ID: SettingMaxConcurrentStreams, Val: t.MaxConcurrentStreams},
+       {ID: SettingInitialWindowSize, Val: t.InitialWindowSize},
+       {ID: SettingMaxFrameSize, Val: t.MaxFrameSize},
    }
    if max := t.maxHeaderListSize(); max != 0 {
        initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max})

Next, make sure any hardcoded defaults are overriden by these new settings:

diff --git a/packages/http2/transport.go b/packages/http2/transport.go
index 7ab542d..82a691f 100644
--- a/packages/http2/transport.go
+++ b/packages/http2/transport.go
@@ -648,10 +648,10 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
        tconn:                 c,
        readerDone:            make(chan struct{}),
        nextStreamID:          1,
-       maxFrameSize:          16 << 10,           // spec default
-       initialWindowSize:     65535,              // spec default
-       maxConcurrentStreams:  1000,               // "infinite", per spec. 1000 seems good enough.
-       peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead.
+       maxFrameSize:          t.MaxFrameSize,         // spec default
+       initialWindowSize:     t.InitialWindowSize,    // spec default
+       maxConcurrentStreams:  t.MaxConcurrentStreams, // "infinite", per spec. 1000 seems good enough.
+       peerMaxHeaderListSize: 0xffffffffffffffff,     // "infinite", per spec. Use 2^64-1 instead.
        streams:               make(map[uint32]*clientStream),
        singleUse:             singleUse,
        wantSettingsAck:       true,
@@ -666,14 +666,14 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
    }

    cc.cond = sync.NewCond(&cc.mu)
-   cc.flow.add(int32(initialWindowSize))
+   cc.flow.add(int32(t.InitialWindowSize))

    // TODO: adjust this writer size to account for frame size +
    // MTU + crypto/tls record padding.
    cc.bw = bufio.NewWriter(stickyErrWriter{c, &cc.werr})
    cc.br = bufio.NewReader(c)
    cc.fr = NewFramer(cc.bw, cc.br)
-   cc.fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
+   cc.fr.ReadMetaHeaders = hpack.NewDecoder(t.InitialWindowSize, nil)
    cc.fr.MaxHeaderListSize = t.maxHeaderListSize()

    // TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on
@@ -703,7 +703,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
    cc.bw.Write(clientPreface)
    cc.fr.WriteSettings(initialSettings...)
    cc.fr.WriteWindowUpdate(0, transportDefaultConnFlow)
-   cc.inflow.add(transportDefaultConnFlow + initialWindowSize)
+   cc.inflow.add(transportDefaultConnFlow + int32(t.InitialWindowSize))
    cc.bw.Flush()
    if cc.werr != nil {
        cc.Close()

Finally, you can set set the correct initial settings frame based on the specified r.TlsFingerprint here: https://github.com/sleeyax/burp-awesome-tls/blob/main/src-go/server/roundtripper.go#L115

You can use Charles proxy to see which settings are the defaults for several browsers. Please try to add support for the latest Chrome version at minimum.

I hope that's enough information to get you started. Good luck and have fun!

sleeyax commented 1 year ago

Hi @ChrisMcMStone any news? Let me know if you need any additional help!