V2ray-core: mKCP加密设计不当可导致流量被精准识别(附PoC)

Created on 2 Jun 2020  ·  17Comments  ·  Source: v2ray/v2ray-core

先说结论: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进行混淆(汇编实现),然后使用附在末尾的校验值来判定包的完整性。

https://github.com/v2ray/v2ray-core/blob/1eb00981dee08ba981a1ee8298032566e19c3b55/transport/internet/kcp/crypt.go#L14-L78

虽然注释写的是legacy,但是在mkcp的设置中的确被使用了

https://github.com/v2ray/v2ray-core/blob/1eb00981dee08ba981a1ee8298032566e19c3b55/transport/internet/kcp/config.go#L62-L65

混淆和校验本身没有问题,问题在于这种混淆太过特殊,而且存在一个校验和判断内容是否正确,并且加解密开销很低

所以检测的思路就是:对一个未知的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等不会误报。

Enhancement PR Wanted Wontfix

Most helpful comment

不能就不用,提供了配置选项就是让用户自己选的,本身作为一个网络工具就不只有一种应用场景。

你或许应该瞧瞧用户们实际上是怎么用mKCP的,issue里面往上翻就行。至少请在文档里标明此类手段不适用于此场景。

同意,如果不打算修复或者改进,至少应该提醒用户不能用来翻墙。

就我自己而言,我最初使用mKCP的唯一目的就是翻墙,直到几个小时后服务器IP被封禁,反复几次。最终才决定使用其他方案。

我不希望更多的用户与我有相同的经历,浪费大量的时间,精力和财力在无用功上。

All 17 comments

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

Was this page helpful?
0 / 5 - 0 ratings