gosplit

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2025 License: MIT Imports: 16 Imported by: 3

README

GoSplit is a simple TLS-aware TCP proxy that can be used to extract cleartext data from TLS tunnels.

Quick Usage

  1. Download a binary from the releases page.
  2. Generate a PEM using the pem subcommand. (gosplit pem --help for examples)
  3. Start the proxy. (gosplit run --help for examples)

Warning (Intended Use)

This project was developed for security research purposes (like eavesarp-ng) and is inefficient. Don't use it in production scenarios.

Limitations

  • As SSL has been deprecated in Go's crypto library, only TLS is currently supported
  • A static PEM certificate is used for all connections
    • Support for dynamically generated and cached certificates may be implemented in the future
  • The client is presumed to send data first, and that first transmission should contain a TLS handshake
    • This breaks protocols where the TLS tunnel is negotiated during later stages (STARTTLS)
    • Protocols expecting the server to send the initial data will result in the connection blocking until timeout

Using in Other Go Projects

GoSplit was developed as a module so that it can be used in any Go project. Any type that implements the Cfg interface can be used to run a TCP proxy server, allowing the implementor to customize everything from TLS connection fingerprinting to handling of intercepted data.

See the GoSplit utility for a simple example of how the interface can be implemented.

How it Works

GoSplit checks the bytes of each initial client TCP segment to determine if the connection should be upgraded to TLS. Data extracted from connections are base64 encoded and logged to disk in JSONL format.

The following sequence diagram roughly illustrates the connection splitting process.

sequenceDiagram
participant C as Victim TCP Client
participant GSP as GoSplit Proxy
participant S as Downstream<br/>TLS Server

C<<->>GSP: TCP Handshake

critical Client must send data first
C->>GSP: TCP Segment w/<br/>TLS Client Hello
GSP->>GSP: Fingerprint TLS<br/>Client Hello
GSP-->>GSP: Upgrade client<br/>conn to TLS
end
GSP<<->>S: TCP Handshake
GSP<<->>S: TLS Handshake
GSP<<->>C: TLS Handshake
C->>GSP: Send client data
GSP->>GSP: Log client data
GSP->>S: Send client data
S->>GSP: Send server data
GSP->>GSP: Log server data
GSP->>C: Send server data

Documentation

Index

Constants

View Source
const (
	InfoLogLvl  = "info"
	ErrorLogLvl = "error"
	DebugLogLvl = "debug"
	DataLogLvl  = "data"
)

Variables

This section is empty.

Functions

func GenSelfSignedCert

func GenSelfSignedCert(subject pkix.Name, ips []net.IP, dnsNames []string, priv *RSAPrivKey) (*tls.Certificate, error)

GenSelfSignedCert generates a X509 certificate with:

- Random RSA key of keyBitSize bits - Expiration date one year into the future - Not before of the time of generation

If priv is nil, an RSAPrivKey will be generated.

Reference: https://go.dev/src/crypto/tls/generate_cert.go

func StartRSAPrivKeyGenerator added in v0.0.4

func StartRSAPrivKeyGenerator(ctx context.Context, bitLen int) (c chan *RSAPrivKey, err error)

StartRSAPrivKeyGenerator starts a distinct routine that yields RSAPrivKey instances of a specific bit length until the ctx is done.

This helps to reduce wait time introduced by waiting for random data generation when needing to generate keys of a consistent length.

func WritePEM

func WritePEM(crt tls.Certificate, crtWriter, keyWriter io.Writer) (err error)

Types

type Addr

type Addr struct {
	IP   string `json:"ip,omitempty"`
	Port string `json:"port,omitempty"`
}

Addr provides IP and Port fields for Addr, Addr, and Addr, which are reflected in ConnInfo instances.

func (Addr) String added in v0.0.6

func (a Addr) String() string

type Cfg

type Cfg interface {
	// GetProxyTLSConfig gets the tls config used by the proxy
	// upon handshake detection.
	//
	// This allows implementors to retrieve custom configurations
	// based on victim IP and port.
	//
	// Note: downstream is a pointer to allow capture of initial
	// data for connections that do not have a downstream. Implementors
	// should account for this.
	GetProxyTLSConfig(victim Addr, proxy Addr, downstream *Addr) (*tls.Config, error)
	// GetDownstreamAddr is used to retrieve the target downstream address
	// information. The current downstream IP address and proxy port are
	// passed to allow the underlying type to retrieve the right downstream.
	//
	// Note: a pointer is returned to allow for capture of initial
	// data for connections that do not have a downstream.
	GetDownstreamAddr(victim Addr, proxy Addr) (*Addr, error)
	// GetDownstreamTLSConfig allows implementers to customize the
	// TLS configuration that is used to connect to the downstream.
	//
	// Note: Unlike GetProxyTLSConfig and GetDownstreamAddr, a downstream
	// is required.
	GetDownstreamTLSConfig(victim Addr, proxy Addr, downstream Addr) (*tls.Config, error)
}

Cfg establishes methods used by ProxyServer to run and handle connections.

Cfg type functionality can be extended by implementing the following interfaces:

- Handshaker to customize TLS fingerprinting - ConnInfoReceiver to receive notifications on when connections are started/ended - LogReceiver to handle LogRecord events - DataReceiver to handle data captured while dissecting connections

type ConnInfo

type ConnInfo struct {
	Time   time.Time `json:"time"`
	Victim Addr      `json:"victim,omitempty"` // address of the victim
	Proxy  Addr      `json:"proxy,omitempty"`  // address of the proxy
	// Downstream address.
	//
	// Unlike Victim and Proxy, null values are supported to enable
	// capture of initial traffic and then terminating the connection.
	Downstream *Addr `json:"downstream"`
}

ConnInfo adds connection information to LogRecord.

type ConnInfoReceiver

type ConnInfoReceiver interface {
	// RecvConnStart receives connection information related to new
	// connections.
	RecvConnStart(ConnInfo)
	// RecvConnEnd receives connection information related to connections
	// that have ended.
	RecvConnEnd(ConnInfo)
}

ConnInfoReceiver defines methods that implementors can use to receive ConnInfo events from this module.

type CtxKey

type CtxKey string

type DataReceiver

type DataReceiver interface {
	// RecvVictimData handles victim data as it passes through
	// the proxy.
	RecvVictimData(ConnInfo, []byte)
	// RecvDownstreamData handles data returned
	// from downstream servers.
	RecvDownstreamData(ConnInfo, []byte)
}

DataReceiver allows implementors to receive cleartext data passing through the proxy.

type Handshaker

type Handshaker interface {
	// IsHandshake checks the byte slice for a TLS handshake.
	IsHandshake([]byte) bool
	// GetHandshakeLen indicates the number of bytes to consume
	// for fingerprinting.
	//
	// WARNING: the connections block until a downstream TCP connection
	// has received at least the number of bytes returned by this
	// method.
	GetHandshakeLen() int
}

Handshaker defines methods used to check the initial data sent by TCP clients to determine if they wish to speak TLS.

type LogReceiver

type LogReceiver interface {
	// RecvLog receives LogRecord at various points of execution as
	// connections are handled.
	RecvLog(LogRecord)
}

LogReceiver defines methods allowing implementors to receive LogRecord objects from this module.

type LogRecord

type LogRecord struct {
	Level    string `json:"level"`
	Msg      string `json:"msg"`
	ConnInfo `json:"conn_info,inline,omitempty"`
}

LogRecord is a standard set of fields that are send to Cfg.RecvLog.

type ProxyListenerAddr

type ProxyListenerAddr struct {
	Addr      // ip and port that the listener is bound to
	Req  Addr // requested address sent by GetProxyAddr
}

ProxyListenerAddr contains Addr information for a newly created ProxyServer.

type ProxyServer

type ProxyServer struct {
	// contains filtered or unexported fields
}

ProxyServer proxies TCP traffic to downstream servers during AITM attacks. It exists mainly to accept and maintain a count of connections.

Use NewProxyServer to initialize a new server.

ConnCount can be used to determine the number of connections active with the server.

func NewProxyServer

func NewProxyServer(cfg Cfg, l net.Listener) *ProxyServer

NewProxyServer initializes a ProxyServer.

func (*ProxyServer) ConnCount

func (s *ProxyServer) ConnCount() int

ConnCount returns the total number of active connections to the server.

func (*ProxyServer) Serve

func (s *ProxyServer) Serve(ctx context.Context) (err error)

Serve a TCP server capable of handling TLS connections.

The method obtains the IP and port the server binds to in on of two ways:

1. Addr 2. Or dynamically by having the cfg embedded in ProxyServer implement ProxyAddrGetter.

Supplying a Addr argument takes precedence over ProxyAddrGetter.

type RSAPrivKey added in v0.0.3

type RSAPrivKey struct {
	*rsa.PrivateKey
	// contains filtered or unexported fields
}

RSAPrivKey wraps rsa.PrivateKey, giving us a type to carry configuration values and errors through StartRSAPrivKeyGenerator.

Use NewRSAPrivKey If standalone initialization is needed.

func NewRSAPrivKey added in v0.0.4

func NewRSAPrivKey(bitLen int) (k *RSAPrivKey)

NewRSAPrivKey initializes a new instance and generates a new private key.

Common bitLen values:

- 1024 - 2048 - 3072 - 4092 - 512 (works, but less likely to be accepted by clients)

func (*RSAPrivKey) BitLen added in v0.0.3

func (r *RSAPrivKey) BitLen() int

BitLen returns the bit length of the private key.

func (*RSAPrivKey) Err added in v0.0.3

func (r *RSAPrivKey) Err() error

Err returns any error that occurred while generating the private key.

type RSAPrivKeyGenerator added in v0.0.3

type RSAPrivKeyGenerator struct {
	// contains filtered or unexported fields
}

RSAPrivKeyGenerator is a thread safe type that conveniently manages a background generator routine started by StartRSAPrivKeyGenerator.

func (*RSAPrivKeyGenerator) Generate added in v0.0.4

func (p *RSAPrivKeyGenerator) Generate() *RSAPrivKey

Generate a RSAPrivKey.

nil is returned if the Start has not been called, or if Stop has been called.

func (*RSAPrivKeyGenerator) Running added in v0.0.4

func (p *RSAPrivKeyGenerator) Running() bool

Running determines if the generator routine is currently running.

func (*RSAPrivKeyGenerator) Start added in v0.0.4

func (p *RSAPrivKeyGenerator) Start(bitLen int) (err error)

Start a generator background routine.

Subsequent calls to Generate will yield non-nil values.

This method has no affect if the generator is already running.

The returned error originates from StartRSAPrivKeyGenerator.

func (*RSAPrivKeyGenerator) Stop added in v0.0.4

func (p *RSAPrivKeyGenerator) Stop()

Stop the background routine.

Subsequent calls to Generate will return nil values.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL