先说结论:mKCP的加密方案(其实应该称作混淆)引入的特征,可导致mKCP流量,以极低的开销被精准识别
目前没有找到除了重新设计mkcp加密以外的缓解措施。我个人的建议是,用标准的加密系统替代当前的混淆方式。
PoC比较简单,下面是核心部分,完整代码放在最后
func IsMKCPPacket(packet []byte) bool {
auth := NewSimpleAuthenticator()
_, err := auth.Open(packet, nil, nil, nil)
if err != nil {
return false
}
return true
}
其中的NewSimpleAuthenticator是core/transport/kcp中的函数
下面是分析和PoC
mKCP被识别不是一天两天的事情了,下面这个只是一种可能的思路。
mKCP的加密实现了一个AEAD接口,但是nonce和tag都没有被使用,仅仅使用了一个不需要密钥的xor进行混淆(汇编实现),然后使用附在末尾的校验值来判定包的完整性。
虽然注释写的是legacy,但是在mkcp的设置中的确被使用了
混淆和校验本身没有问题,问题在于这种混淆太过特殊,而且存在一个校验和判断内容是否正确,并且加解密开销很低。
所以检测的思路就是:对一个未知的UDP包,简单地用这个算法解密,然后判断校验和是否正确,如果正确,为mKCP。否则不是mKCP。
我猜测设计者应该是想使用简单的xor替换常规加密方式,降低开销,提升计算速度。但是,加密的开销越低,检测的开销就越低。因此使得大规模部署和检测成为可能。考虑到mKCP暴力发包的特性,防火墙只需要抽取其中几个包进行抽样测试即可准确判定。在我本地,mtu为1350的情况下(默认的最大的mKCP包),可以每秒检测超过20k个包。
建议使用标准的密码系统,或者直接明文传输,带来的特征都会比使用这种加密算法少。
完整PoC代码
package main
import (
"flag"
"log"
"net"
"v2ray.com/core/transport/internet/kcp"
)
var listenAddr = flag.String("from", "127.0.0.1:4444", "listen address")
var verbose = flag.Bool("verbose", false, "enable detailed output")
func init() {
flag.Parse()
}
func isMKCPPacket(packet []byte) bool {
auth := kcp.NewSimpleAuthenticator()
_, err := auth.Open(packet, nil, nil, nil)
if err != nil {
return false
}
return true
}
func main() {
udpAddr, _ := net.ResolveUDPAddr("udp4", *listenAddr)
l, _ := net.ListenUDP("udp", udpAddr)
log.Printf("mKCP PoC opened at %s...", *listenAddr)
for {
buf := make([]byte, 2048)
nRecv, _, e := l.ReadFromUDP(buf)
if e == nil {
result := isMKCPPacket(buf[:nRecv])
if *verbose {
log.Printf("detected=%v, size=%d, data=%x", result, nRecv, buf[:nRecv])
} else {
log.Printf("detected=%v, size=%d", result, nRecv)
}
}
}
}
这个程序监听本地4444端口,开启一个v2ray客户端向4444端口发送mkcp数据包即可识别。发送其他udp包,如dns,quic等不会误报。
mKCP 被封是很早之前的事情了……不过这次是把原因挖出来了。
不管怎么说,建议立刻停止侥幸,停用 mKCP。
实在有需求的,可以考虑使用 gost 提供的 kcptun,可以避免这个问题。
没了,瞬间识别:

VPS用mkcp几天就封了 后来才听说mkcp 会被识别
mKCP 活不过一天的原因找到了。
就KCP这个拥塞控制的机制本身就没啥好抗识别的把。。。
混淆是为了得到isp 优待的QoS级别,不是用来让GFW不识别的。WontFix
混淆是为了得到isp 优待的QoS级别,不是用来让GFW不识别的。WontFix
那这样等于宣告mKCP不能用于翻越长城了
其实改进措施也不难,替换aead的实现,增加解密的开销
混淆是为了得到isp 优待的QoS级别,不是用来让GFW不识别的。WontFix
而且最主要的问题是,运营商部署这一识别,比防火墙更容易
如此还能得到ISP的优待吗?
不能就不用,提供了配置选项就是让用户自己选的,本身作为一个网络工具就不只有一种应用场景。
混淆是为了得到isp 优待的QoS级别,不是用来让GFW不识别的。WontFix
一个很轻易就能识别出来的流量为何会受到 ISP 的优待……不明……
那还是不用 mKCP 吧……
不能就不用,提供了配置选项就是让用户自己选的,本身作为一个网络工具就不只有一种应用场景。
你或许应该瞧瞧用户们实际上是怎么用mKCP的,issue里面往上翻就行。至少请在文档里标明此类手段不适用于此场景。
不能就不用,提供了配置选项就是让用户自己选的,本身作为一个网络工具就不只有一种应用场景。
我的提议是,使用aes等加密方式替换当前的简单xor混淆,哪怕是硬编码的都比当前方案优。这是开销的问题。
gfw不可能所有包都做一次aes来校验,但是可以所有包都做一次xor校验,因为xor的开销太低了。
不能就不用,提供了配置选项就是让用户自己选的,本身作为一个网络工具就不只有一种应用场景。
你或许应该瞧瞧用户们实际上是怎么用mKCP的,issue里面往上翻就行。至少请在文档里标明此类手段不适用于此场景。
同意,如果不打算修复或者改进,至少应该提醒用户不能用来翻墙。
就我自己而言,我最初使用mKCP的唯一目的就是翻墙,直到几个小时后服务器IP被封禁,反复几次。最终才决定使用其他方案。
我不希望更多的用户与我有相同的经历,浪费大量的时间,精力和财力在无用功上。
不能就不用,提供了配置选项就是让用户自己选的,本身作为一个网络工具就不只有一种应用场景。
你或许应该瞧瞧用户们实际上是怎么用mKCP的,issue里面往上翻就行。至少请在文档里标明此类手段不适用于此场景。
同意,如果不打算修复或者改进,至少应该提醒用户不能用来翻墙。
就我自己而言,我最初使用mKCP的唯一目的就是翻墙,直到几个小时后服务器IP被封禁,反复几次。最终才决定使用其他方案。
我不希望更多的用户与我有相同的经历,浪费大量的时间,精力和财力在无用功上。
支持,一个和谐的社区不应该只有一种声音
kcp不能过墙的问题先不说,,,早几年开发者解释过,这个协议不做加密,只是针对运营商QOS限速突破用的。混淆模拟伪装成BT下载之类的流量。
那么,有谁能提交下修复代码解决游戏不能玩的问题?延迟999+
https://github.com/v2ray/discussion/issues/558#issuecomment-637069133
膜拜,识别原因终于找到了
kcp不能过墙的问题先不说,,,早几年开发者解释过,这个协议不做加密,只是针对运营商QOS限速突破用的。混淆模拟伪装成BT下载之类的流量。
那么,有谁能提交下修复代码解决游戏不能玩的问题?延迟999+
v2ray/discussion#558 (comment)
改ss白名单秒解
mark
Most helpful comment
同意,如果不打算修复或者改进,至少应该提醒用户不能用来翻墙。
就我自己而言,我最初使用mKCP的唯一目的就是翻墙,直到几个小时后服务器IP被封禁,反复几次。最终才决定使用其他方案。
我不希望更多的用户与我有相同的经历,浪费大量的时间,精力和财力在无用功上。