Skip to content

Instantly share code, notes, and snippets.

@wv-jessejjohnson
Created July 30, 2025 19:37
Show Gist options
  • Select an option

  • Save wv-jessejjohnson/73780b5fae05c91bbb8abafaafeaedab to your computer and use it in GitHub Desktop.

Select an option

Save wv-jessejjohnson/73780b5fae05c91bbb8abafaafeaedab to your computer and use it in GitHub Desktop.
TCP Fingerprinting
package fingerprint
import (
"context"
"fmt"
"net"
"syscall"
"time"
)
// TCPFingerprinter handles TCP-level fingerprinting
type TCPFingerprinter struct {
profile *TCPProfile
}
// CustomDialer provides TCP fingerprinting capabilities
type CustomDialer struct {
tcpProfile *TCPProfile
baseDialer *net.Dialer
}
func NewTCPFingerprinter(profile *TCPProfile) *TCPFingerprinter {
return &TCPFingerprinter{
profile: profile,
}
}
func NewCustomDialer(profile *TCPProfile) *CustomDialer {
return &CustomDialer{
tcpProfile: profile,
baseDialer: &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
},
}
}
func (cd *CustomDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
// Use base dialer to establish connection
conn, err := cd.baseDialer.DialContext(ctx, network, address)
if err != nil {
return nil, err
}
// Apply TCP fingerprinting options
if tcpConn, ok := conn.(*net.TCPConn); ok {
if err := cd.applyTCPOptions(tcpConn); err != nil {
conn.Close()
return nil, err
}
}
return conn, nil
}
func (cd *CustomDialer) applyTCPOptions(conn *net.TCPConn) error {
// Get raw connection for socket options
rawConn, err := conn.SyscallConn()
if err != nil {
return err
}
var sockErr error
err = rawConn.Control(func(fd uintptr) {
sockErr = cd.setSocketOptions(int(fd))
})
if err != nil {
return err
}
return sockErr
}
func (cd *CustomDialer) setSocketOptions(fd int) error {
// Set TCP window size
if cd.tcpProfile.WindowSize > 0 {
if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, cd.tcpProfile.WindowSize); err != nil {
return err
}
if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, cd.tcpProfile.WindowSize); err != nil {
return err
}
}
// Set MSS (Maximum Segment Size)
if cd.tcpProfile.MSS > 0 {
// Note: MSS setting is platform-specific and may require different approaches
// This is a simplified example
if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_MAXSEG, cd.tcpProfile.MSS); err != nil {
// MSS setting might not be available on all platforms
// Continue without error in production
}
}
// Set TCP_NODELAY (disable Nagle's algorithm)
if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1); err != nil {
return err
}
// Set SO_KEEPALIVE
if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
return err
}
// Platform-specific TCP options would go here
// For example, on Linux:
// - TCP_WINDOW_CLAMP
// - TCP_USER_TIMEOUT
// - TCP_TIMESTAMP
// - TCP_SACK
return nil
}
// Platform-specific implementations would be in separate files:
// tcp_linux.go, tcp_windows.go, tcp_darwin.go
// LinuxTCPOptions applies Linux-specific TCP options
func (cd *CustomDialer) applyLinuxTCPOptions(fd int) error {
// TCP Window Scaling
if cd.tcpProfile.WindowScaling {
// This would use Linux-specific socket options
// syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, TCP_WINDOW_CLAMP, value)
}
// TCP Timestamps
if cd.tcpProfile.Timestamps {
// syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, TCP_TIMESTAMP, 1)
}
// TCP Selective Acknowledgment
if cd.tcpProfile.SelectiveAck {
// syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, TCP_SACK_ENABLE, 1)
}
return nil
}
// WindowsTCPOptions applies Windows-specific TCP options
func (cd *CustomDialer) applyWindowsTCPOptions(fd int) error {
// Windows has different socket options and registry settings
// that would need to be configured differently
return nil
}
// DarwinTCPOptions applies macOS-specific TCP options
func (cd *CustomDialer) applyDarwinTCPOptions(fd int) error {
// macOS/Darwin specific TCP stack options
return nil
}
// TCPStackDetection provides methods to detect and mimic different TCP stacks
type TCPStackDetection struct {
knownStacks map[string]*TCPSignature
}
type TCPSignature struct {
Name string
WindowSize int
MSS int
TTL int
Options []TCPOption
WindowScaling bool
Timestamps bool
SelectiveAck bool
ECN bool
}
type TCPOption struct {
Kind uint8
Length uint8
Data []byte
}
func NewTCPStackDetection() *TCPStackDetection {
tsd := &TCPStackDetection{
knownStacks: make(map[string]*TCPSignature),
}
tsd.loadKnownSignatures()
return tsd
}
func (tsd *TCPStackDetection) loadKnownSignatures() {
// Windows 10/11 signature
tsd.knownStacks["windows10"] = &TCPSignature{
Name: "Windows 10/11",
WindowSize: 65535,
MSS: 1460,
TTL: 128,
WindowScaling: true,
Timestamps: true,
SelectiveAck: true,
ECN: false,
}
// Linux signature
tsd.knownStacks["linux"] = &TCPSignature{
Name: "Linux",
WindowSize: 29200,
MSS: 1460,
TTL: 64,
WindowScaling: true,
Timestamps: true,
SelectiveAck: true,
ECN: true,
}
// macOS signature
tsd.knownStacks["macos"] = &TCPSignature{
Name: "macOS",
WindowSize: 65535,
MSS: 1460,
TTL: 64,
WindowScaling: true,
Timestamps: true,
SelectiveAck: true,
ECN: false,
}
// FreeBSD signature
tsd.knownStacks["freebsd"] = &TCPSignature{
Name: "FreeBSD",
WindowSize: 65535,
MSS: 1460,
TTL: 64,
WindowScaling: true,
Timestamps: true,
SelectiveAck: true,
ECN: false,
}
}
func (tsd *TCPStackDetection) GetSignature(stackName string) *TCPSignature {
if sig, exists := tsd.knownStacks[stackName]; exists {
return sig
}
return tsd.knownStacks["linux"] // Default
}
func (tsd *TCPStackDetection) CreateProfileFromSignature(sig *TCPSignature) *TCPProfile {
return &TCPProfile{
Name: sig.Name,
WindowSize: sig.WindowSize,
MSS: sig.MSS,
TTL: sig.TTL,
WindowScaling: sig.WindowScaling,
Timestamps: sig.Timestamps,
SelectiveAck: sig.SelectiveAck,
}
}
// Advanced TCP fingerprinting techniques
type AdvancedTCPFingerprinter struct {
stackDetection *TCPStackDetection
evasionMode bool
}
func NewAdvancedTCPFingerprinter() *AdvancedTCPFingerprinter {
return &AdvancedTCPFingerprinter{
stackDetection: NewTCPStackDetection(),
evasionMode: false,
}
}
func (atf *AdvancedTCPFingerprinter) SetEvasionMode(enabled bool) {
atf.evasionMode = enabled
}
func (atf *AdvancedTCPFingerprinter) GetRandomProfile() *TCPProfile {
stacks := []string{"windows10", "linux", "macos", "freebsd"}
randomStack := stacks[time.Now().UnixNano()%int64(len(stacks))]
sig := atf.stackDetection.GetSignature(randomStack)
profile := atf.stackDetection.CreateProfileFromSignature(sig)
// Apply evasion techniques if enabled
if atf.evasionMode {
atf.applyEvasionTechniques(profile)
}
return profile
}
func (atf *AdvancedTCPFingerprinter) applyEvasionTechniques(profile *TCPProfile) {
// Randomize window size within realistic ranges
baseWindow := profile.WindowSize
variation := baseWindow / 10 // ±10% variation
profile.WindowSize = baseWindow + int(time.Now().UnixNano()%int64(variation*2)) - variation
// Randomize MSS slightly
if profile.MSS > 0 {
profile.MSS += int(time.Now().UnixNano()%40) - 20 // ±20 bytes
if profile.MSS < 536 {
profile.MSS = 536 // Minimum MSS
}
if profile.MSS > 1460 {
profile.MSS = 1460 // Standard Ethernet MSS
}
}
// Occasionally disable some features for evasion
if time.Now().UnixNano()%10 == 0 {
profile.WindowScaling = false
}
if time.Now().UnixNano()%8 == 0 {
profile.Timestamps = false
}
if time.Now().UnixNano()%12 == 0 {
profile.SelectiveAck = false
}
}
// TCPFingerprintMatcher helps identify and match TCP fingerprints
type TCPFingerprintMatcher struct {
database map[string]*TCPSignature
}
func NewTCPFingerprintMatcher() *TCPFingerprintMatcher {
return &TCPFingerprintMatcher{
database: make(map[string]*TCPSignature),
}
}
func (tfm *TCPFingerprintMatcher) AnalyzePacket(windowSize, mss, ttl int, options []TCPOption) string {
// Simple fingerprint matching based on common patterns
// Windows detection
if ttl == 128 && windowSize == 65535 {
if mss == 1460 {
return "Windows 10/11"
}
return "Windows (version unknown)"
}
// Linux detection
if ttl == 64 && windowSize > 25000 && windowSize < 35000 {
return "Linux"
}
// macOS detection
if ttl == 64 && windowSize == 65535 && mss == 1460 {
return "macOS"
}
// FreeBSD detection
if ttl == 64 && windowSize == 65535 {
return "FreeBSD"
}
return "Unknown"
}
// Connection pool with TCP fingerprinting
type FingerprintedConnPool struct {
pools map[string]*ConnectionPool
dialer map[string]*CustomDialer
}
type ConnectionPool struct {
connections chan net.Conn
maxConns int
profile *TCPProfile
}
func NewFingerprintedConnPool() *FingerprintedConnPool {
return &FingerprintedConnPool{
pools: make(map[string]*ConnectionPool),
dialer: make(map[string]*CustomDialer),
}
}
func (fcp *FingerprintedConnPool) GetConnection(profileName string, address string) (net.Conn, error) {
pool, exists := fcp.pools[profileName]
if !exists {
return nil, fmt.Errorf("profile %s not found", profileName)
}
// Try to get existing connection from pool
select {
case conn := <-pool.connections:
// Test if connection is still alive
if fcp.isConnAlive(conn) {
return conn, nil
}
conn.Close()
default:
// No available connections, create new one
}
// Create new connection with fingerprinting
dialer := fcp.dialer[profileName]
if dialer == nil {
return nil, fmt.Errorf("dialer for profile %s not found", profileName)
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return dialer.DialContext(ctx, "tcp", address)
}
func (fcp *FingerprintedConnPool) ReturnConnection(profileName string, conn net.Conn) {
pool, exists := fcp.pools[profileName]
if !exists || !fcp.isConnAlive(conn) {
conn.Close()
return
}
select {
case pool.connections <- conn:
// Successfully returned to pool
default:
// Pool is full, close connection
conn.Close()
}
}
func (fcp *FingerprintedConnPool) isConnAlive(conn net.Conn) bool {
// Simple connection liveness check
conn.SetReadDeadline(time.Now().Add(time.Millisecond))
var buf [1]byte
_, err := conn.Read(buf[:])
conn.SetReadDeadline(time.Time{})
// If we get a timeout, connection is likely alive
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
return true
}
return false
}
func (fcp *FingerprintedConnPool) AddProfile(name string, profile *TCPProfile, maxConns int) {
pool := &ConnectionPool{
connections: make(chan net.Conn, maxConns),
maxConns: maxConns,
profile: profile,
}
fcp.pools[name] = pool
fcp.dialer[name] = NewCustomDialer(profile)
}
// Network interface and routing manipulation for advanced evasion
type NetworkEvasion struct {
interfaces []NetworkInterface
}
type NetworkInterface struct {
Name string
IP net.IP
Gateway net.IP
MTU int
}
func NewNetworkEvasion() *NetworkEvasion {
ne := &NetworkEvasion{}
ne.discoverInterfaces()
return ne
}
func (ne *NetworkEvasion) discoverInterfaces() {
interfaces, err := net.Interfaces()
if err != nil {
return
}
for _, iface := range interfaces {
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
netIface := NetworkInterface{
Name: iface.Name,
IP: ipnet.IP,
MTU: iface.MTU,
}
ne.interfaces = append(ne.interfaces, netIface)
}
}
}
}
}
func (ne *NetworkEvasion) SelectRandomInterface() *NetworkInterface {
if len(ne.interfaces) == 0 {
return nil
}
index := time.Now().UnixNano() % int64(len(ne.interfaces))
return &ne.interfaces[index]
}
// IP fragmentation and packet manipulation for evasion
type PacketManipulator struct {
fragmentationEnabled bool
maxFragmentSize int
}
func NewPacketManipulator() *PacketManipulator {
return &PacketManipulator{
fragmentationEnabled: false,
maxFragmentSize: 1400,
}
}
func (pm *PacketManipulator) EnableFragmentation(maxSize int) {
pm.fragmentationEnabled = true
pm.maxFragmentSize = maxSize
}
func (pm *PacketManipulator) DisableFragmentation() {
pm.fragmentationEnabled = false
}
// TCP sequence number randomization
type SequenceRandomizer struct {
baseSequence uint32
increment uint32
}
func NewSequenceRandomizer() *SequenceRandomizer {
now := time.Now().UnixNano()
return &SequenceRandomizer{
baseSequence: uint32(now),
increment: uint32(now % 10000),
}
}
func (sr *SequenceRandomizer) NextSequence() uint32 {
sr.baseSequence += sr.increment
return sr.baseSequence
}
func (sr *SequenceRandomizer) RandomizeIncrement() {
sr.increment = uint32(time.Now().UnixNano() % 10000)
}
// Utility functions for TCP fingerprinting
func CalculateChecksum(data []byte) uint16 {
var sum uint32
// Process pairs of bytes
for i := 0; i < len(data)-1; i += 2 {
sum += uint32(data[i])<<8 + uint32(data[i+1])
}
// Handle odd byte
if len(data)%2 == 1 {
sum += uint32(data[len(data)-1]) << 8
}
// Add carry
for (sum >> 16) > 0 {
sum = (sum & 0xFFFF) + (sum >> 16)
}
return ^uint16(sum)
}
func GenerateRandomTCPOptions() []TCPOption {
options := []TCPOption{}
// MSS option
options = append(options, TCPOption{
Kind: 2,
Length: 4,
Data: []byte{0x05, 0xB4}, // 1460 bytes
})
// Window scale option
options = append(options, TCPOption{
Kind: 3,
Length: 3,
Data: []byte{0x08}, // Scale factor 8
})
// SACK permitted option
options = append(options, TCPOption{
Kind: 4,
Length: 2,
Data: []byte{},
})
// Timestamp option
timestamp := uint32(time.Now().Unix())
options = append(options, TCPOption{
Kind: 8,
Length: 10,
Data: []byte{
byte(timestamp >> 24),
byte(timestamp >> 16),
byte(timestamp >> 8),
byte(timestamp),
0, 0, 0, 0, // Echo timestamp (0 for SYN)
},
})
return options
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment