From 02c3683d1e1dba7a4f91462c7831f5caec0e15fc Mon Sep 17 00:00:00 2001 From: RPRX <63339210+RPRX@users.noreply.github.com> Date: Sat, 13 May 2023 08:07:43 +0000 Subject: [PATCH] v1.0.0 --- README.md | 31 ++++++++++ example/example.com.cer | 20 +++++++ example/example.com.key | 28 ++++++++++ example/trojanClient.json | 49 ++++++++++++++++ example/trojanServer.json | 36 ++++++++++++ go.mod | 3 + main.go | 115 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 282 insertions(+) create mode 100644 README.md create mode 100644 example/example.com.cer create mode 100644 example/example.com.key create mode 100644 example/trojanClient.json create mode 100644 example/trojanServer.json create mode 100644 go.mod create mode 100644 main.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..c11eaf2 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# Trojan-Killer + +这个 POC 是为了 **狠 狠 打 脸** 某些认为 TLS in TLS 检测不存在或成本很高的人。 + +该程序在 `127.0.0.1:12345` 接收 TLS 流量,并用 **非 常 廉 价** 的方式检测出其中的 Trojan 代理。 + +1. 设置浏览器的 HTTP 代理至 `127.0.0.1:12345`,观察该程序的输出。 +2. 设置 Trojan 链式 HTTP 代理至 `127.0.0.1:12345`,观察该程序的输出。 + +我们的测试结果如下: + +1. 对于浏览器的 HTTPS 流量,**几乎没有阳性结果**。 +2. 对于 Trojan 的 TLS in TLS 流量,**Trojan 字样直接刷屏**。 + +这与我们多次收到的 Trojan 被封、XTLS Vision 存活的反馈相符(它们均可选 Golang 指纹)。 + +值得一提的是,根据我们的观察,目前 REALITY 的“白名单域名”会被豁免于这样的检测。 + +## License + +[GNU AFFERO GENERAL PUBLIC LICENSE](https://github.com/XTLS/Trojan-killer/blob/main/LICENSE) + +## Compilation + +```bash +go build -trimpath -ldflags "-s -w -buildid=" . +``` + +## Stargazers over time + +[![Stargazers over time](https://starchart.cc/XTLS/Trojan-killer.svg)](https://starchart.cc/XTLS/Trojan-killer) diff --git a/example/example.com.cer b/example/example.com.cer new file mode 100644 index 0000000..813811d --- /dev/null +++ b/example/example.com.cer @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIQAOACeeTO8xa8MX71sctjcTANBgkqhkiG9w0BAQsFADAW +MRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0yMzA1MTMwMzEwMTJaFw0zMzA1MTAw +MzEwMTJaMBYxFDASBgNVBAMMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAkiCjDSVLws/LaMVCgPPBDHrpzDqmfXiq3+CzIE7Vpipl +byAx16L0tRCQxYDuq/eKOQ1IrVPS9+v+XaT+17og/iWYK2lN/T7oXw8uDH+xqyTU +/OM2oKsHxbgqlY3eN64UA0XLl5POZitnMb9RbRyAsmEUeZKrd4GvJrYnj3qFheod +FO/r37QLEMUjwwlhCzhQ3XHdE+2cCIrtFUBKbqsbDWm4Gdrt+BIFHG6Gn/+PSRSh +/bt39uK8I9SMMwlXB3qWo1AcuasoTXYn6cunjJqmYnvtGf4XSTTMcRAQAWlZBAQn +ABcCpsnWE1emHmtyD557EVltoytUuI9MVCcTkCJ1pwIDAQABo4GeMIGbMB0GA1Ud +DgQWBBTUF0I2kmmFXQJQvOvtaJpip59CEzAOBgNVHQ8BAf8EBAMCBLAwDAYDVR0T +AQH/BAIwADA7BgNVHSUENDAyBggrBgEFBQcDAgYIKwYBBQUHAwEGCCsGAQUFBwMD +BggrBgEFBQcDBAYIKwYBBQUHAwgwHwYDVR0jBBgwFoAU1BdCNpJphV0CULzr7Wia +YqefQhMwDQYJKoZIhvcNAQELBQADggEBAHsNfIoIofaz6zsFfoh+yUzy7qIEYP5j +gaF9t6YY4gsJDcYkOhnQErG4cocOWHSC18MPxsxYXsgLQFixNqCzg7L9nhFGhpxr +vvqRD+j5HrjYKLUCJ+IxjJfJckD6WkINVUTO18HL0hbpIQclpHIJzSi8iMX7+uVY +/yXRnLeK8mJnyA5iblPQPqFnECdXKfdVX4w9JPRk/8pB6VokzsM/hclbbSJzGvzq +duuXweojyHx/MWka5BYb57xDb/8krS+G55U35JnXylhp88PScZl9V64j1vQcx/3I +lm160qduqHAVllOMBzNNgcFyPItzYNYmXYXn0OuUDfTZORnhBiKxAnM= +-----END CERTIFICATE----- diff --git a/example/example.com.key b/example/example.com.key new file mode 100644 index 0000000..1314fd5 --- /dev/null +++ b/example/example.com.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCSIKMNJUvCz8to +xUKA88EMeunMOqZ9eKrf4LMgTtWmKmVvIDHXovS1EJDFgO6r94o5DUitU9L36/5d +pP7XuiD+JZgraU39PuhfDy4Mf7GrJNT84zagqwfFuCqVjd43rhQDRcuXk85mK2cx +v1FtHICyYRR5kqt3ga8mtiePeoWF6h0U7+vftAsQxSPDCWELOFDdcd0T7ZwIiu0V +QEpuqxsNabgZ2u34EgUcboaf/49JFKH9u3f24rwj1IwzCVcHepajUBy5qyhNdifp +y6eMmqZie+0Z/hdJNMxxEBABaVkEBCcAFwKmydYTV6Yea3IPnnsRWW2jK1S4j0xU +JxOQInWnAgMBAAECggEABQ3RQIh5sP3e2yYiFrOs3vGhWcmYLd7D34ULV6K3tkzh +FTwtJ811s+LOybCb5fa5y8oEfs+CDHEXwHAPIFxKUn/vs2YA/IageCkzk9sWxK88 +GUMChgFkU2z7NruhY+ucEEDpubmy+cr71rdMlFQtX1NcPJgwtgFrkrsvbcGfEfKT +xmSyEE+kK2nzvMzt1GbivABcOkV9mz0EJnaZdHmf8a6n0cAMr7jeCPlyaojDkfR3 +sGvTjvVlf5lchJmcAz1UQEmMxMhjkRka2eMt0ZHnCKuRvC6ILR0Nn+bX0AjH9MnY +8WHJbN89G7KZjUUO/zHIHKRsEjvKB6+45ocjxA+TgQKBgQD6Nq1Qzv6Feh44Ij70 +To4DzIVrtFQswQM+zd2UIDuOpmONj+00BQCrl5Wd9z+rWaJO0yORFEo2McwGocGm +BaZvTC4w4L/FgKKu58yXViT5TZNtzJgGJvbS6oNSFWbxn5n8Vnc6tNqeJv317ngw +WxNII93tkMWkzVARlXA5KoqZxQKBgQCVgb7wouNlnrHbzn6IS34gKnmrNAkvWQDS +oSB2aTGb/cU+XuAMf2QgFl/BDn0+SEoVLJsRCVb3OdeRPhDO4NlUyTm+2/N6bNNT +7SLvwG4UGDpyYT8GLk0GhNcqK8qv8vf5zvaBBNVlEbqtMLWizltj5XDg5r4NflMK +dASZSE2EewKBgHax01vfJcxJ1uYIENcyIJpavfwOylOEqDZ10CQBel88PUOdQAgK +S3wa54XNEW4GkkFUVa3v8xhsXP3UZBmO2po3iD31j+NwFzxjh6FO4zFEhKh0grWA +bFw3lV4t+uyqKpESr3Kw8nhNxPGSU3+U5Lu3EAMvRyLbpp0AyADGVoOFAoGASlk2 +aham/O8ZRdT/qanZNAfLb6817hzVwukr6pbPe+KMR0MJKk3jre1SewBImkN6y+Ld +znAVlmZmZC04UJkSmw5isB5Ti4s44KCp4g6Q719JGX5wyBMYbOh809TpO+yZEtqw +TWLo+BUD/4KcoTT7z8bXBpDY7H7orucZLlz9Z6cCgYAh6Q/qJVAzz0rbL+La3dV3 +E95VophRXw9XgWVO41nJGvSTnuuH7e7+CgKxqvuNK8vCDyt5EDXxEk28DjCI7s1+ +7AGX9/oKRncOLZo8DFsnI8fMiFTna45hDar3bS6jZ9OV6Yhz4cZqr20fSYOAqwdu +DNqkspXj0DChZLLxGoUPhQ== +-----END PRIVATE KEY----- diff --git a/example/trojanClient.json b/example/trojanClient.json new file mode 100644 index 0000000..a60a35c --- /dev/null +++ b/example/trojanClient.json @@ -0,0 +1,49 @@ +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "listen": "127.0.0.1", + "port": 11111, + "protocol": "http" + } + ], + "outbounds": [ + { + "protocol": "trojan", + "settings": { + "servers": [ + { + "address": "127.0.0.1", + "port": 22222, + "password": "password" + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "tls", + "tlsSettings": { + "serverName": "example.com", + "allowInsecure": true + }, + "sockopt": { + "dialerProxy": "http" + } + } + }, + { + "tag": "http", + "protocol": "http", + "settings": { + "servers": [ + { + "address": "127.0.0.1", + "port": 12345 + } + ] + } + } + ] +} \ No newline at end of file diff --git a/example/trojanServer.json b/example/trojanServer.json new file mode 100644 index 0000000..301fe38 --- /dev/null +++ b/example/trojanServer.json @@ -0,0 +1,36 @@ +{ + "log": { + "loglevel": "warning" + }, + "inbounds": [ + { + "listen": "127.0.0.1", + "port": 22222, + "protocol": "trojan", + "settings": { + "clients": [ + { + "password": "password" + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "tls", + "tlsSettings": { + "certificates": [ + { + "certificateFile": "example.com.cer", + "keyFile": "example.com.key" + } + ] + } + } + } + ], + "outbounds": [ + { + "protocol": "freedom" + } + ] +} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ce3eec5 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/xtls/trojan-killer + +go 1.20 diff --git a/main.go b/main.go new file mode 100644 index 0000000..0c03e44 --- /dev/null +++ b/main.go @@ -0,0 +1,115 @@ +package main + +import ( + "bufio" + "bytes" + "fmt" + "io" + "net" + "net/http" + "strings" + "sync" + "time" +) + +func main() { + fmt.Printf("Trojan-killer v1.0.0 started\n") + l, _ := net.Listen("tcp4", "127.0.0.1:12345") + fmt.Printf("Listening on %v\n\n", l.Addr()) + for { + c, _ := l.Accept() + go Handle(c) + } +} + +var CCS = []byte{20, 3, 3, 0, 1, 1} + +func Handle(c net.Conn) { + req, err := http.ReadRequest(bufio.NewReader(c)) + if err != nil { + return + } + state := "accepted" + if !strings.EqualFold(req.Method, "CONNECT") { + state = "rejected" + } + fmt.Printf("%v from %v %v %v\n", time.Now().Format(time.DateTime), c.RemoteAddr(), state, req.URL.Host) + if state == "rejected" { + return + } + + conn, err := net.Dial("tcp", req.URL.Host) + if err != nil { + return + } + c.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n")) + + var mutex sync.Mutex + + uploading := false + upCount := 0 + + downloading := false + downCount := 0 + + go func() { + buf := make([]byte, 8192) + for { + n, err := c.Read(buf) + if err != nil { + return + } + mutex.Lock() + if upCount == 0 && n >= 6 && bytes.Equal(buf[:6], CCS) { + uploading = true + } + if uploading { + upCount += n + } + if downloading { + downloading = false + //fmt.Printf("%v\tupCount %v\tdownCount %v\n", req.URL.Host, upCount, downCount) + if upCount >= 650 && upCount <= 750 && + ((downCount >= 170 && downCount <= 180) || (downCount >= 3000 && downCount <= 7500)) { + fmt.Printf("%v is Trojan\n", req.URL.Host) + } + } + mutex.Unlock() + _, err = conn.Write(buf[:n]) + if err != nil { + return + } + if !downloading && downCount != 0 { + go io.CopyBuffer(conn, c, buf) + return + } + } + }() + + go func() { + buf := make([]byte, 8192) + for { + n, err := conn.Read(buf) + if err != nil { + return + } + mutex.Lock() + if uploading { + uploading = false + downloading = true + } + if downloading { + downCount += n + } + mutex.Unlock() + _, err = c.Write(buf[:n]) + if err != nil { + return + } + if !downloading && downCount != 0 { + go io.CopyBuffer(c, conn, buf) + return + } + } + }() +}