Skip to content

Commit

Permalink
Merge pull request #64 from nabil-ak/custom-client-hello
Browse files Browse the repository at this point in the history
  • Loading branch information
sleeyax authored Mar 22, 2024
2 parents c9454a9 + 0a2848e commit d5711a6
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 57 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ This magic header is stripped from the request before it's forwarded to the dest
## Configuration
This extension is 'plug and play' and should speak for itself. You can hover with your mouse over each field in the 'Awesome TLS' tab for more information about each field.

To load your custom Client Hello, you can capture it in Wireshark, copy client hello record as hex stream and paste it into the field "Hex Client Hello".
![screenshot](./docs/wireshark_capture_client_hello.png)

<details>
<summary>Advanced usage</summary>

Expand Down
Binary file modified docs/settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src-go/server/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func main() {
InterceptProxyAddr: server.DefaultInterceptProxyAddress,
BurpAddr: server.DefaultBurpProxyAddress,
Fingerprint: tls.DefaultFingerprint,
HexClientHello: "",
UseInterceptedFingerprint: false,
HttpTimeout: int(internal.DefaultHttpTimeout.Seconds()),
HttpKeepAliveInterval: int(internal.DefaultHttpKeepAlive.Seconds()),
Expand Down
6 changes: 6 additions & 0 deletions src-go/server/internal/tls/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,11 @@ func (f *FactoryWithClientHelloId) NewUTLSConn(conn net.Conn, config *tls.Config

clientHelloID, spec := f.GetClientHello(config.ServerName)

if spec != nil {
clientHelloID = &utls.HelloCustom
} else if clientHelloID == nil {
clientHelloID = DefaultClientHelloID
}

return &uconnAdapter{UConn: utls.UClient(conn, uConfig, *clientHelloID), spec: spec}
}
26 changes: 20 additions & 6 deletions src-go/server/internal/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package internal
import (
"encoding/json"
"errors"
"fmt"
"net"
"strings"
"time"
Expand Down Expand Up @@ -38,6 +39,9 @@ type TransportConfig struct {
// The TLS fingerprint to use.
Fingerprint internalTls.Fingerprint

// Hexadecimal Client Hello to use
HexClientHello internalTls.HexClientHello

// The maximum amount of time a dial will wait for a connect to complete.
// Defaults to [DefaultHttpTimeout].
HttpTimeout int
Expand Down Expand Up @@ -102,26 +106,36 @@ func NewTransport(getInterceptedFingerprint func(sni string) string) (*oohttp.St
dialer.KeepAlive = time.Duration(config.HttpKeepAliveInterval) * time.Second
}

var spec *utls.ClientHelloSpec
clientHelloID := config.Fingerprint.ToClientHelloId()
var clientHelloSpec *utls.ClientHelloSpec
var clientHelloID *utls.ClientHelloID

if config.HexClientHello != "" {
spec, err := config.HexClientHello.ToClientHelloSpec()
if err != nil {
return nil, fmt.Errorf("create spec from client hello: %w", err)
}
clientHelloSpec = spec
} else if config.Fingerprint != "" {
clientHelloID = config.Fingerprint.ToClientHelloId()
}

getClientHello := func(sni string) (*utls.ClientHelloID, *utls.ClientHelloSpec) {
if !config.UseInterceptedFingerprint {
return clientHelloID, spec
if !config.UseInterceptedFingerprint || config.HexClientHello != "" {
return clientHelloID, clientHelloSpec
}

interceptedFingerprint := getInterceptedFingerprint(sni)

if interceptedFingerprint == "" {
return clientHelloID, spec
return clientHelloID, clientHelloSpec
}

interceptedSpec, err := internalTls.HexClientHello(interceptedFingerprint).ToClientHelloSpec()
if err == nil {
return &utls.HelloCustom, interceptedSpec
}

return clientHelloID, spec
return clientHelloID, clientHelloSpec
}

tlsFactory := &internalTls.FactoryWithClientHelloId{GetClientHello: getClientHello}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/burp/BurpExtender.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks)

var transportConfig = new TransportConfig();
transportConfig.Fingerprint = this.settings.getFingerprint();
transportConfig.HexClientHello = this.settings.getHexClientHello();
transportConfig.HttpTimeout = this.settings.getHttpTimeout();
transportConfig.HttpKeepAliveInterval = this.settings.getHttpKeepAliveInterval();
transportConfig.IdleConnTimeout = this.settings.getIdleConnTimeout();
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/burp/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class Settings {
private final String interceptProxyAddress = "InterceptProxyAddress";
private final String burpProxyAddress = "BurpProxyAddress";
private final String fingerprint = "Fingerprint";
private final String hexClientHello = "HexClientHello";
private final String useInterceptedFingerprint = "UseInterceptedFingerprint";
private final String httpTimeout = "HttpTimeout";
private final String httpKeepAliveInterval = "HttpKeepAliveInterval";
Expand Down Expand Up @@ -124,6 +125,10 @@ public void setFingerprint(String fingerprint) {
this.write(this.fingerprint, fingerprint);
}

public String getHexClientHello() { return this.read(this.hexClientHello); }

public void setHexClientHello(String hexClientHello) { this.write(this.hexClientHello, hexClientHello); }

public int getIdleConnTimeout() {
return Integer.parseInt(this.read(this.idleConnTimeout));
}
Expand Down
61 changes: 41 additions & 20 deletions src/main/java/burp/SettingsTab.form
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<properties/>
<border type="none"/>
<children>
<grid id="65d0" binding="panelSettings" layout-manager="GridLayoutManager" row-count="14" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="65d0" binding="panelSettings" layout-manager="GridLayoutManager" row-count="16" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<tabbedpane title="settings"/>
Expand Down Expand Up @@ -47,7 +47,7 @@
</component>
<component id="b51c9" class="javax.swing.JLabel" binding="labelFingerprint">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<enabled value="true"/>
Expand All @@ -59,91 +59,112 @@
</component>
<component id="b6939" class="javax.swing.JComboBox" binding="comboBoxFingerprint">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<component id="a5fce" class="javax.swing.JLabel" binding="labelTimeout">
<constraints>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Http connection timeout (seconds)"/>
</properties>
</component>
<component id="5078b" class="javax.swing.JSpinner" binding="spinnerHttpTimout">
<constraints>
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="7" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<toolTipText value="The maximum amount of time a dial will wait for a connect to complete."/>
</properties>
</component>
<component id="e91b6" class="javax.swing.JLabel" binding="labelKeepAlive">
<constraints>
<grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="8" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Http keep alive interval"/>
</properties>
</component>
<component id="bd213" class="javax.swing.JSpinner" binding="spinnerKeepAlive">
<constraints>
<grid row="7" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="9" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<toolTipText value="Specifies the interval between keep-alive probes for an active network connection."/>
</properties>
</component>
<component id="a2f49" class="javax.swing.JLabel" binding="labelIdleConnTimeout">
<constraints>
<grid row="8" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="10" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Idle connection timeout"/>
</properties>
</component>
<component id="5efb6" class="javax.swing.JSpinner" binding="spinnerIdleConnTimeout">
<constraints>
<grid row="9" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="11" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<toolTipText value="The maximum amount of time an idle (keep-alive) connection will remain idle before closing itself."/>
</properties>
</component>
<component id="e4f58" class="javax.swing.JLabel" binding="labelTlsHandshakeTimeout">
<constraints>
<grid row="10" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="12" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="TLS handshake timeout"/>
</properties>
</component>
<component id="2b2e5" class="javax.swing.JSpinner" binding="spinnerTlsHandshakeTimeout">
<constraints>
<grid row="11" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="13" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<toolTipText value="The maximum amount of time to wait for a TLS handshake."/>
</properties>
</component>
<component id="da183" class="javax.swing.JButton" binding="buttonSave">
<constraints>
<grid row="12" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Save all settings"/>
</properties>
</component>
<grid id="4bfb5" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="13" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="15" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
<component id="46b0e" class="javax.swing.JLabel" binding="labelHexClientHello">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<requestFocusEnabled value="false"/>
<text value="Hex Client Hello:"/>
<toolTipText value=""/>
</properties>
</component>
<component id="a196c" class="javax.swing.JTextField" binding="textFieldHexClientHello">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
<properties>
<text value=""/>
<toolTipText value="Custom client hello as hex stream. Leave it empty if you want it to be automatically detected."/>
</properties>
</component>
<component id="da183" class="javax.swing.JButton" binding="buttonSave">
<constraints>
<grid row="14" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Save all settings"/>
</properties>
</component>
</children>
</grid>
<grid id="9c113" binding="panelAdvanced" layout-manager="GridLayoutManager" row-count="7" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
Expand Down
Loading

0 comments on commit d5711a6

Please sign in to comment.