Documentation
¶
Overview ¶
Support code for TLS camouflage using uTLS.
The goal is: provide an http.RoundTripper abstraction that retains the features of http.Transport (e.g., persistent connections and HTTP/2 support), while making TLS connections using uTLS in place of crypto/tls. The challenge is: while http.Transport provides a DialTLS hook, setting it to non-nil disables automatic HTTP/2 support in the client. Most of the uTLS fingerprints contain an ALPN extension containing "h2"; i.e., they declare support for HTTP/2. If the server also supports HTTP/2, then uTLS may negotiate an HTTP/2 connection without the http.Transport knowing it, which leads to an HTTP/1.1 client speaking to an HTTP/2 server, a protocol error.
The code here uses an idea adapted from meek_lite in obfs4proxy: https://gitlab.com/yawning/obfs4/commit/4d453dab2120082b00bf6e63ab4aaeeda6b8d8a3 Instead of setting DialTLS on an http.Transport and exposing it directly, we expose a wrapper type, UTLSRoundTripper, that contains within it either an http.Transport or an http2.Transport. The first time a caller calls RoundTrip on the wrapper, we initiate a uTLS connection (bootstrapConn), then peek at the ALPN-negotiated protocol: if "h2", create an internal http2.Transport; otherwise, create an internal http.Transport. In either case, set DialTLS on the created Transport to a function that dials using uTLS. As a special case, the first time the DialTLS callback is called, it reuses bootstrapConn (the one made to peek at the ALPN), rather than make a new connection.
Subsequent calls to RoundTripper on the wrapper just pass the requests though the previously created http.Transport or http2.Transport. We assume that in future RoundTrips, the ALPN-negotiated protocol will remain the same as it was in the initial RoundTrip. At this point it is the http.Transport or http2.Transport calling DialTLS, not us, so we can't dynamically swap the underlying transport based on the ALPN.
https://bugs.torproject.org/29077 https://github.com/refraction-networking/utls/issues/16
Index ¶
- Constants
- Variables
- func AES_GCM_Decrypt(password, ciphertext []byte) ([]byte, error)
- func AES_GCM_Encrypt(password, plaintext []byte) ([]byte, error)
- func Base64URLDecode(text string) []byte
- func Base64URLEncode(text string) string
- func DeriveKey(password, salt []byte) []byte
- func EmpHTTPClient(c2_addr, proxyServer string) *http.Client
- func ExtractCABundle() (*x509.CertPool, error)
- func FindIPToUse(target string) string
- func FwdToDport(ctx context.Context, cancel context.CancelFunc, to, sessionID, protocol string, ...)
- func GenCerts(hosts []string, outname string, isCA bool) ([]byte, error)
- func GenerateRandomBytes(size int) ([]byte, error)
- func GenerateSSHKeyPair() (privateKey, publicKey []byte, err error)
- func GetFingerprint(cert_file string) string
- func HTTPClientWithEmpCA(target_url, proxy string) (client *http.Client)
- func IPIfaces() (ifaces []net.Interface)
- func IPLink() (links []netlink.Link)
- func IPNeigh() []string
- func IPa() (ips []string)
- func IPbroadcastAddr(ipMask IPWithMask) string
- func IPinCIDR(port, cidr string) (ips []string)
- func IPr() (routes []string)
- func IsPortOpen(host string, port string) bool
- func IsProxyOK(proxy, test_url string) bool
- func IsTor(addr string) bool
- func KCPTunClient(remote_kcp_addr, kcp_listen_port, password, salt string, ctx context.Context, ...) error
- func KCPTunServer(target, kcp_server_port, password, salt string, ctx context.Context, ...) error
- func LogError(format string, a ...interface{})
- func LogFatalError(format string, a ...interface{})
- func LogInfo(format string, a ...interface{})
- func LogWarn(format string, a ...interface{})
- func MD5Sum(text string) string
- func NamesInCert(cert_file string) (names []string)
- func NewUTLSRoundTripper(name string, cfg *utls.Config, proxyURL *url.URL) (http.RoundTripper, error)
- func PKCS5Padding(ciphertext []byte, blockSize int) []byte
- func PKCS5Trimming(encrypt []byte) []byte
- func ParseCertPemFile(cert_file string) (cert *x509.Certificate, err error)
- func ParseKeyPemFile(key_file string) (cert *ecdsa.PrivateKey, err error)
- func ParsePem(data []byte) (*x509.Certificate, error)
- func ProxyHTTP(network, addr string, auth *proxy.Auth, forward proxy.Dialer) (*httpProxy, error)
- func ProxyHTTPS(network, addr string, auth *proxy.Auth, forward proxy.Dialer, cfg *utls.Config, ...) (*httpProxy, error)
- func SHA256Sum(text string) string
- func SHA256SumFile(path string) string
- func SHA256SumRaw(data []byte) string
- func SSHPublicKey(privkey []byte) (pubkey ssh.PublicKey, err error)
- func SSHRemoteFwdClient(ssh_serverAddr, password string, hostkey ssh.PublicKey, local_port int, ...) (err error)
- func SSHRemoteFwdServer(port, password string, hostkey []byte) (err error)
- func SSHReverseProxyClient(ssh_serverAddr string, password string, proxyPort int, ...) (err error)
- func ServeFileHTTP(file_path, port string, ctx context.Context, cancel context.CancelFunc) (err error)
- func SignECDSA(message []byte, privateKey *ecdsa.PrivateKey) ([]byte, error)
- func SignWithCAKey(data []byte) ([]byte, error)
- func StartSocks5Proxy(addr, doh string, proxyserver *socks5.Server) (err error)
- func TCPFwd(addr, port string, ctx context.Context, cancel context.CancelFunc) (err error)
- func TestConnectivity(test_url, proxy string) bool
- func ValidateIP(ip string) bool
- func ValidateIPPort(to string) bool
- func VerifySignatureWithCA(data []byte, signature []byte) (bool, error)
- func XOREncrypt(key []byte, plaintext []byte) []byte
- type Config
- type IPWithMask
- type UTLSDialer
- type UTLSRoundTripper
Constants ¶
const ( // WebRoot root path of APIs WebRoot = "emp3r0r" // CheckInAPI agent send POST to this API to report its system info CheckInAPI = WebRoot + "/checkin" // MsgAPI duplex tunnel between agent and cc MsgAPI = WebRoot + "/msg" // ReverseShellAPI duplex tunnel between agent and cc ReverseShellAPI = WebRoot + "/rshell" // ProxyAPI proxy interface ProxyAPI = WebRoot + "/proxy" // FTPAPI file transfer FTPAPI = WebRoot + "/ftp" // FileAPI host some files FileAPI = WebRoot + "/www" // Static hosting WWW = "/www/" )
const ( CA_CERT_FILE = "ca-cert.pem" CA_KEY_FILE = "ca-key.pem" )
const ( TGT_UNIX = iota TGT_TCP )
const ( // MicrosoftNCSIURL is the URL used by Microsoft to check internet connectivity MicrosoftNCSIURL = "http://www.msftncsi.com/ncsi.txt" MicrosoftNCSIResp = "Microsoft NCSI" // UbuntuConnectivityURL is the URL used by Ubuntu to check internet connectivity UbuntuConnectivityURL = "https://connectivity-check.ubuntu.com" // UbuntuConnectivityResp will be empty with 204 status code UbuntuConnectivityResp = 204 )
Variables ¶
var ( Stager_HTTP_Server http.Server Stager_Ctx context.Context Stager_Cancel context.CancelFunc )
var CACrt = []byte("")
CACrt for TLS server cert signing
var ServerPubKey string
PEM encoded server public key
Functions ¶
func AES_GCM_Decrypt ¶
AES_GCM_Decrypt decrypts ciphertext with password using AES-GCM
func AES_GCM_Encrypt ¶
AES_GCM_Encrypt encrypts plaintext with password using AES-GCM
func Base64URLDecode ¶
Base64URLDecode decode a base64 encoded string (to []byte)
func Base64URLEncode ¶
Base64URLEncode encode a string with base64
func EmpHTTPClient ¶
EmpHTTPClient add our CA to trusted CAs, while keeps TLS InsecureVerify on
func ExtractCABundle ¶
ExtractCABundle extracts built-in Ubuntu CA bundle
func FindIPToUse ¶
FindIPToUse find an IP that resides in target IP range target: 192.168.1.1/24
func FwdToDport ¶
func FwdToDport(ctx context.Context, cancel context.CancelFunc, to, sessionID, protocol string, h2 *h2conn.Conn, timeout int, )
FwdToDport forward request to agent-side destination, h2 <-> tcp/udp
func GenCerts ¶
GenCerts generate a CA cert or a server cert signed by CA cert if isCA is true, the outfile will be a CA cert/key named as ca-cert.pem/ca-key.pem if isCA is false, the outfile will be named as is, for example, outfile-cert.pem, outfile-key.pem Returns public key bytes
func GenerateRandomBytes ¶
func GenerateSSHKeyPair ¶
Generate a new key pair for use with openssh
func GetFingerprint ¶
GetFingerprint return SHA256 fingerprint of a cert
func HTTPClientWithEmpCA ¶
HTTPClientWithEmpCA is a http client with system CA pool with utls client hello randomization url: target URL, proxy: proxy URL
func IPbroadcastAddr ¶
func IPbroadcastAddr(ipMask IPWithMask) string
IPbroadcastAddr calculate broadcast address of an IP
func KCPTunClient ¶
func KCPTunClient(remote_kcp_addr, kcp_listen_port, password, salt string, ctx context.Context, cancel context.CancelFunc) error
main function for KCP tunneling using smux remote_kcp_addr: KCP server address (host:port) kcp_listen_port: KCP client listen port password: Runtime password salt: emp3r0r_def.MagicString
func KCPTunServer ¶
func KCPTunServer(target, kcp_server_port, password, salt string, ctx context.Context, cancel context.CancelFunc) error
target: target address (host:port) kcp_server_port: KCP server listen port password: Runtime password salt: emp3r0r_def.MagicString
func LogFatalError ¶
func LogFatalError(format string, a ...interface{})
LogFatalError print log in red, and exit
func NamesInCert ¶
NamesInCert find domain names and IPs in server certificate
func NewUTLSRoundTripper ¶
func PKCS5Padding ¶
Go implementation of PKCS5Padding
func PKCS5Trimming ¶
func ParseCertPemFile ¶
func ParseCertPemFile(cert_file string) (cert *x509.Certificate, err error)
ParseCertPemFile read from PEM file and return parsed cert
func ParseKeyPemFile ¶
func ParseKeyPemFile(key_file string) (cert *ecdsa.PrivateKey, err error)
ParseKeyPemFile read from PEM file and return parsed cert
func ProxyHTTPS ¶
func SHA256SumFile ¶
SHA256SumFile calc sha256 of a file (of any size)
func SHA256SumRaw ¶
func SSHPublicKey ¶
SSHPublicKey return ssh.PublicKey from PEM encoded private key
func SSHRemoteFwdClient ¶
func SSHRemoteFwdClient(ssh_serverAddr, password string, hostkey ssh.PublicKey, local_port int, conns *map[string]context.CancelFunc, ctx context.Context, cancel context.CancelFunc, ) (err error)
SSHRemoteFwdClient dial SSHRemoteFwdServer, forward local TCP port to remote server serverAddr format: 127.0.0.1:22 hostkey is the ssh server public key
func SSHRemoteFwdServer ¶
SSHRemoteFwdServer start a ssh proxy server that forward to client side TCP port port: binding port on server side, ssh client will try authentication with this port password: ssh client will try authentication with this password. We will always use RuntimeConfig.ShadowsocksPassword
func SSHReverseProxyClient ¶
func SSHReverseProxyClient(ssh_serverAddr string, password string, proxyPort int, reverseConns *map[string]context.CancelFunc, socks5proxy *socks5.Server, ctx context.Context, cancel context.CancelFunc, ) (err error)
SSHReverseProxyClient dial SSHProxyServer, start a reverse proxy serverAddr format: 127.0.0.1:22 FIXME: when using KCP, port number calculation is wrong
func ServeFileHTTP ¶
func SignECDSA ¶
func SignECDSA(message []byte, privateKey *ecdsa.PrivateKey) ([]byte, error)
SignECDSA sign a message with ECDSA private key
func SignWithCAKey ¶
SignWithCAKey signs the given data using the CA's private key
func StartSocks5Proxy ¶
StartSocks5Proxy sock5 proxy server on agent, listening on addr
func TCPFwd ¶
TCPFwd listen on a TCP port and forward to another TCP address addr: forward to this addr port: listen on this port
func TestConnectivity ¶
TestConnectivity does this machine has internet access,
func ValidateIPPort ¶
ValidateIPPort check if the host string looks like IP:Port
func VerifySignatureWithCA ¶
VerifySignatureWithCA verifies the given signature against the data using the CA's public key
Types ¶
type Config ¶
type Config struct { LocalAddr string `json:"localaddr"` // Local listen address, e.g., ":12948" Listen string `json:"listen"` // kcp server listen address, eg: "IP:29900" for a single port, "IP:minport-maxport" Target string `json:"target"` // target server address, or path/to/unix_socket RemoteAddr string `json:"remoteaddr"` // KCP server address, e.g., "vps:29900", can be a single port or port range "IP:minport-maxport" Key string `json:"key"` // Pre-shared secret between client and server, e.g., "it's a secret" Crypt string `json:"crypt"` // Encryption method, e.g., aes, aes-128, aes-192, salsa20, blowfish, twofish, etc. Mode string `json:"mode"` // Performance profile, e.g., fast, fast2, fast3, normal, or manual Conn int `json:"conn"` // Number of UDP connections to the server AutoExpire int `json:"autoexpire"` // Auto expiration time (in seconds) for a single UDP connection, 0 disables auto-expire ScavengeTTL int `json:"scavengettl"` // Time (in seconds) an expired connection can remain active before scavenging MTU int `json:"mtu"` // Maximum Transmission Unit size for UDP packets SndWnd int `json:"sndwnd"` // Send window size (number of packets) RcvWnd int `json:"rcvwnd"` // Receive window size (number of packets) DataShard int `json:"datashard"` // Number of data shards for Reed-Solomon erasure coding ParityShard int `json:"parityshard"` // Number of parity shards for Reed-Solomon erasure coding DSCP int `json:"dscp"` // DSCP value for quality of service (QoS) marking (6-bit) NoComp bool `json:"nocomp"` // Disable compression if set to true AckNodelay bool `json:"acknodelay"` // Flush ACK immediately when a packet is received (reduces latency) NoDelay int `json:"nodelay"` // KCP 'NoDelay' mode configuration (latency vs throughput trade-off) Interval int `json:"interval"` // KCP update interval in milliseconds Resend int `json:"resend"` // KCP resend parameter, controls packet retransmission NoCongestion int `json:"nc"` // Disable KCP congestion control (1 = disable, 0 = enable) SockBuf int `json:"sockbuf"` // Per-socket buffer size (in bytes), e.g., 4194304 SmuxVer int `json:"smuxver"` // Smux version, either 1 or 2 SmuxBuf int `json:"smuxbuf"` // Overall de-mux buffer size (in bytes), e.g., 4194304 StreamBuf int `json:"streambuf"` // Per-stream receive buffer size (in bytes) for Smux v2+, e.g., 2097152 KeepAlive int `json:"keepalive"` // NAT keep-alive interval in seconds Log string `json:"log"` // Path to the log file, default is empty (logs to stderr) SnmpLog string `json:"snmplog"` // Path to collect SNMP logs, follows Go time format e.g., "./snmp-20060102.log" SnmpPeriod int `json:"snmpperiod"` // SNMP collection period in seconds Quiet bool `json:"quiet"` // Suppress 'stream open/close' messages if set to true TCP bool `json:"tcp"` // Emulate a TCP connection (Linux only) Pprof bool `json:"pprof"` // Enable a profiling server on port :6060 if set to true QPP bool `json:"qpp"` // Enable Quantum Permutation Pads (QPP) for added encryption security QPPCount int `json:"qpp-count"` // Number of pads to use for QPP (must be a prime number) CloseWait int `json:"closewait"` // Time (in seconds) to wait before tearing down a connection }
Config holds the client configuration for KCP tunneling.
type IPWithMask ¶
IPWithMask net.IP and net.IPMask
type UTLSDialer ¶
type UTLSDialer struct {
// contains filtered or unexported fields
}
type UTLSRoundTripper ¶
A http.RoundTripper that uses uTLS (with a specified Client Hello ID) to make TLS connections.
Can only be reused among servers which negotiate the same ALPN.