-
Notifications
You must be signed in to change notification settings - Fork 8.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
vmess协议设计和实现缺陷可导致服务器遭到主动探测特征识别(附PoC) #2523
Comments
简而言之,如果 GFW 怀疑你鸡上有个 vmess + tcp,他抓个包,然后按上面的方法进行重放,在我电脑上实测不用一秒钟你的 vmess + tcp 就被识别了,更别提 GFW 了。希望大家予以重视。 更新:目前服务端基本没有反制措施了,16 个包即可完全确定,基本无误报。重新设计吧。 作为 V2Ray 的下游项目(Qv2ray)维护者之一,我希望 V2Ray 能对自己的协议实现进行充分的安全审计,尽可能避免类似的事情再度发生。 ps1: ps2: ps3: |
参考文章: 为何 shadowsocks 要弃用一次性验证 (OTA) v2ray在vmess命令部分采用的MAC-then-Encrypt的做法,与当年的ss类似。 |
This comment has been minimized.
This comment has been minimized.
这一缓解措施不成立,对P的密文的改动只会影响P和Sec。 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@ActiveIce 赞同123的具体做法 |
This comment has been minimized.
This comment has been minimized.
如果我理解无误,也就是说:裸vmess协议不再被支持。
|
没错,或者说,可以用,但不主张,包括ss和ssr,因为这些都在“创造特征” 自己在tcp上设计的协议,注重加密和防各种攻击是少不了的(这部分性能始终要损失),而tls1.3本来就是一种最佳实践(如本issue提到的aead加密改进),所以不如直接用tls以减少特征、减轻心智负担 |
他意思是纠结这个就是做无用功,我也赞同这一点。无论怎么设计/修复协议,都是画虎不成反类犬,在可见的未来会有新特征被识别。还不如直接用大众协议,并处理tls明文部分特征,才是长久之计。 |
This comment has been minimized.
This comment has been minimized.
翻车?😂 大家都知道ss和vmess是什么时候出现的,而那时互联网上tls并不普及,tls1.3也没出来。但现在是2020年,tls已成为主流,tls1.3也已被广泛应用了,所以我认为目前套tls才是最佳的选择与长久之计。 |
我们现在要做的看来只是正式宣布vmess+非tls不被支持了 |
确实如此,但是我们这里讨论的是vmess的问题。单从修复这个问题的角度来说,最好的方法是重新设计这个协议。 |
并不。毕竟瘦身后的vmess协议或新协议还未开始设计。 不过,不少人已经是vmess+ws+tls了,也证明了这种方案的可靠性。 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
我认为,与其在此争论vmess是否有存在必要/研究是否具有意义的话题,不如转而讨论,本地能否复现此攻击;如何改进vmess协议,使得这样的攻击不可能发生。上面的讨论我个人认为是离题的。 |
This comment has been minimized.
This comment has been minimized.
我认为校验版本号只是 mitigation,向后不兼容的 solution 可能较好,例如对 fixed/variable sized fields 分别提供校验,或是切换到 aead 上。 另外,我认为用「重放攻击」来描述不太妥当,这个问题更类似 padding oracle。 |
CFB模式下,攻击P不会影响版本号 切AEAD可以根治 |
This comment has been minimized.
This comment has been minimized.
请勿抬杠,况且新协议不需要考虑大多数攻击,重点考虑混淆大流量特征,将比vmess简单很多。 在新协议被设计出来之前,尚有安全的vmess+wss可以使用 |
一直用ws+tls+cdn的方法,感觉挺稳的 |
目前GFW没有执行本帖所说的特征码匹配拦截 |
哈哈,我就一小白,能翻稳定就行,从去年ws+caddy+tls+cdn一直稳到现在,以前的ssr包括v2ray的tcp还有mkcp根本不行,立马封很快的,换了“终级”配置以后就很稳,我感觉只要是和vps直连的若没有cdn,就没有稳定的保障,有了cdn就无所谓vps被封不被封了 |
VMess+WS+端口80,VMess+WS+TLS+端口443都可以由CF代理。如果VPS不止跑V2Ray,就在CF里面新建www的A记录,www由CF代理,主域名直连。 |
GFW完全可以利用这次的漏洞封杀一批V2ray节点,但没这么做。极有可能GFW早就将注意力重点放在流量特征分析上(分析你的流量有多少、流向哪个IP域名或VPS厂商机房、与大陆外IP通讯多长时间、你每天与大陆外IP通讯的时间段)。站在GFW的角度思考:这人每天下午都要与境外一个小网站交换大量流量,这个境外小网站八成是个伪装的V2ray或Trojan。 |
使用WG和AnyConnect有时浏览Google、YouTube会出现「facebook.com证书错误」提示,说明GFW有时可干扰VPN流量中的DNS流量。 |
现在似乎没有免费IP证书,只有免费域名证书。我对TLS 1.2 ECDHE_ECDSA_WITH_AES_128_GCM_SHA256进行了抓包,证书已经用ECDHE加密,只有SNI(访问的域名)没有加密。 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
mark security |
您好,我尝试重现上诉描述。我在客户端使用的是4444端口与服务器连接,服务器监听8888端口,正常使用时利用浏览器代理监听4444端口,进而转发流量。 |
Fix Issued an emergency fix for VMess weakness described in v2ray/v2ray-core#2523 This fix can significantly hindrance attack based on the weakness described. Only servers need to be updated to apply this emergency fix, it not expected for well-behaved clients to be influenced. A more permanent solution is underway.
喜报,2022年TLS+VMess已死 |
怎么死了,TLS死了不就是说HTTPS死了。 |
https的设备指纹特征码精准识别,自己搜索引擎吧,v2至今为止的新版依旧未修复。 |
Update: 我们构造出了更具杀伤性的PoC,仅需16次探测即可准确判定vmess服务,误报可能性几乎为0,校验的缓解措施均无效。唯一的解决方案是禁用vmess或者重新设计协议。我们决定提高issue的严重性等级。
Update:v4.23.4及以后已经采取随机读取多个字节的方式阻止P的侧信道泄漏,目前下面的PoC(16次探测)以及概率探测(暴力发包探测)的PoC已经失效,无法准确探测vmess服务。但是,由于这是协议设计层面的问题,彻底解决问题需要引入AEAD等无法向下兼容的设计。好消息是,这一缓解可以为我们讨论制订新协议争取非常多的时间。vmess+tcp的组合仍然存在一定风险,不建议使用。
先说结论:开启了tcp+vmess的服务端,在和客户端进行通讯时,攻击者可以通过重放攻击的方式准确判定是否为vmess服务。
这个缺陷的利用基于重放攻击和密文填充攻击,需要以下条件(经过讨论,结合之前ss遭到的重放攻击,我们认为对于GFW来说,此条件并不苛刻):
攻击者可以进行中间人攻击,捕获vmess的TCP流前16 + 38字节。
攻击者可以在30秒内据此发送16个探测包
目前的缓解方案均可以被绕过,唯一解决方案是修改协议实现 。
个人认为,最好的解决方案是采用gcm等具有认证能力的aead加密模式对指令部分进行加密,而不是cfb。这和现有vmess设计冲突且无法向下兼容,可能需要重新设计vmess协议。
mkcp+vmess和tls+vmess等底层传输不使用tcp的组合不受此问题直接影响,但有可能收到波及。
下面是分析和PoC
鉴于近期vmess协议遭到封锁的情况较为严重,因此研究了一下vmess的协议设计和实现,发现服务端一个实现缺陷导致的特征,可以利用主动探测,区分vmess服务与其他服务。
vmess的协议的设计和实现缺陷
这是vmess的客户端请求格式。
前16字节为认证信息,内容为和时间、用户ID相关的散列值。根据协议设计,每个16字节的认证信息auth的有效期只有30秒。
问题出在指令部分。指令部分使用了没有认证能力的aes-cfb方式,因此攻击者可以篡改其中内容,而仍然能被服务器接受。
我们对照代码来看,v2ray服务端的vmess解析代码如下:
v2ray-core/proxy/vmess/encoding/server.go
Lines 124 to 209 in 4b81ba9
可以看到,前16字节的认证信息可以被重复使用,并且只要通过认证,执行流即可进行到140行,初始化aes密钥流。接着在144行处,服务端在没有经过任何认证的情况下,读入38字节的密文,并使用aes-cfb进行解密,在没有进行任何校验的情况下,将其中版本号,余量P,加密方式等信息,直接填入结构体中。
这里问题已经很明显了,攻击者只需要得知16字节的认证信息,就可以在30秒内反复修改这38字节的信息进行反复的重放攻击/密文填充攻击。
aes本身可以抵抗已知明文攻击,因此安全性方面基本没有问题。出现问题的是余量P。我猜想设计者应该是为了避免包的长度特征而引入这个字段,但是读入余量的方式出现了问题:
此处代码实现,在没有校验余量P、加密方式Sec、版本号Ver、指令 Cmd、地址类型T、地址A的情况下,将P直接代入ReadFullFrom中读取P字节(182行)。注意,这里P的范围是2^4=16字节以内。
v2ray-core/proxy/vmess/encoding/server.go
Lines 163 to 198 in 4b81ba9
读取P+4字节后,v2ray才会对前面读入的内容进行校验,判断命令部分是否合法。如果不合法,断开连接。
缺陷的利用
Update:这个更强的攻击思路来自@studentmain。
我们假定攻击者已经捕获前16 + 38字节。如何判定该服务是否为vmess呢?
下面是一种攻击载荷构造方法,我们构造这样的流
恶意修改的指令部分:
方法很简单,我们让i从0-16开始枚举,构造探测载荷。Key的最后一个字节赋值为i,用以绕过v2ray防护。P也赋值为i,用以遍历其明文空间。发送了16+38字节后,尝试还能发送几个字节后连接被断开。发送成功的字节数记做M。
发送载荷,累计16次,记录测得的所有M的值。如果M的最大值和最小值差值为16,并且无重复,该服务为vmess服务。否则不是vmess服务。这个检测方式不会漏报,也几乎不会误报。
原理很简单:
由于攻击者拥有前16字节的验证信息,因此可以通过服务端校验。
攻击者修改了key绕过基于nonce的防重放检测。并且,由于修改的是key最后一个字节,cfb加密模式中,由于是同一块的修改,错误不会扩散到P。
攻击者仅修改并枚举P,遍历所有密文空间,解密后的P同样遍历明文空间。也就是说,从0-16的枚举,将得到十六个不同的P值。
服务端读入接下来的地址后,开始期待客户端发送P字节的余量,以及最后4个字节的校验码。于是接下来就会读入P+4个字节,并因为校验和不正确,连接被断开。我们因此可以测得M的值。M的实际值为 目标地址长度+P+4
下面是一个PoC,使用go实现,比较粗糙,见谅:
这段PoC使用方法是,开启两个v2ray实例,客户端使用vmess连接本地4444端口,服务端vmess监听本地4445端口。客户端开启1080端口接受socks流量。
使用浏览器向客户端1080发送socks请求,客户端向4444端口发送vmess请求时,PoC模拟中间人攻击,获得16字节的有效认证信息。并且以此向4445端口的服务器发送恶意构造的包,测量N的值。
需要注意的是测量M时,可以使用每个字节Sleep后再发送的方式,使得服务端的BufferReader不工作,以此我们可以测量得到准确的M。
你可以通过--from --to 参数来指定想要监听的地址和想要测试的服务器。可以将--to换成其他服务的地址,如ssh,http,https进行检验。对于vmess服务,将输出This is a vmess server。
The text was updated successfully, but these errors were encountered: