TLSMirror: Looks like TLS Censorship Resistant Transport Protocol is Looking for Developer Feedback
TLSMirror is a Looks like TLS Censorship Resistant Transport Protocol.
Its primary objective is create an connection between client and server that looks like a port forwarder or SNI proxy to a third party service. This allow users to deploy a looks like TLS proxy service without the need to acquire a domain name or TLS certificate, and make sure the connection looks like a connection to a well-known server name, rather than a domain name operated by service operator.
Conceptually, TLSMirror is very similar to other looks like TLS protocols like REALITY, ShadowTLSv3, Restls, JLS. However, it is designed to be a more user twistable protocol that allow users to adjust its protocol behavior freely, and by design resistant to packet length fingerprinting before and after handshake.
While all other protocols mentioned above generate the carrier traffic or otherwise requires making change to the client hello of the carrier traffic. TLSMirror by design does not require any change to the client hello or server hello or otherwise any packet while the carrier connection is being handshake and setup. As a result, the carrier traffic can either come from the embedded traffic generator for more precise control, or even be externally generated from a web browser or even a external device like a smartphone, game console, IoT device or even a telescreen. During the entire transmission of payload traffic, the carrier traffic is not impacted at all, and continue to function. This means shape of traffic of the original connection is always preserved, and the content of the handshake message is never changed in anyway. This allows ALL client hello, server hello fingerprint or traffic shapes be used to carry proxy traffic, not just those can be generated by uTLS.
By doing so, TLSMirror automatically has defense against Aparecium or other post handshake length based detection, and the embedded traffic generator will consistently generate programmable and probabilistically generated traffic get get mixed with payload traffic, making it very difficult to discriminate TLSMirror traffic based on its shape, as the traffic is always bit-identical to the original traffic until it is ready for payload traffic.
Additionally, TLSMirror is designed to work with TLS1.2 traffic(including AEAD with explicit nonce), and avoided the pitfall of many websites disabling TLS1.3 support to avoid being used as a forwarding site. The explicit nonce issue for TLS1.2 AEAD ciphers has been specifically addressed, and visible nonce fields are automatically adjusted when configured to do so.
The design of TLSMirror is rather simple: it will forward the carrier traffic as is to the destination server without modify its content, until the connection is ready for payloads. Once the connection is ready for payloads, the tlsmirror client and servers will insert application data frames to the TLS connection with a different TLSMirror transport key than the original client, and remove any application data frame, whose content can be decrypted with tlsmirror transport key. The data from successful decryption are then forwarded to application as payload traffic.
Currently this protocol is still incomplete with enrollment confirmation(confirm connection is not redirected to forwarded site via a external channel), traffic shaping, and external traffic generator connection ready signaling(wait sometime or packets before using externally generated carrier connection), and traffic generator gracefully recall not implemented. However, it is currently seeking developer feedback about bugs and weakness of its protocol design while it is still being developed. Please compile from the primary branch of v2ray-core directly to try it.
这些代理协议的历史是这样的,2021 年初的 Qv 开发群,我说既然 XTLS 是拼接别的 TLS 进来,那么可以“反向拼接”:先与目标网站握手,再把代理流量拼后面,让 GFW 以为在访问白名单网站,@xiaokangwang 说用于握手的 TLS 流量也可以由外部程序发起
但后来我们都没开发这样的协议,直至 2022 年中出现了 ShadowTLS,就是干的这件事,半年后我写 REALITY 时选择了另一个路线
看描述 TLSMirror 的拼接部分更像是初始版本的 ShadowTLS,它无法防御重定向等攻击,所以才有了 v2v3,针对这类协议的重定向攻击指的是,服务端为了区分连接是否由代理协议客户端提供,客户端需要先提供身份证明,但是如果身份证明不够隐蔽,比如说直接从某个 TLS record 开始换成自己的 AEAD,攻击者可以把某个连接导到真正的网站,并观察会不会异常断开,以此来识别协议
仅看描述而言,当前版本的 TLSMirror 似乎无法防御这种攻击
The history of these proxy protocols is as follows: In early 2021, in the Qv development group, I suggested that since XTLS concatenates other TLS protocols, we could “reverse concatenate” it: first establish a handshake with the target website, then append the proxy traffic to the end, making the Great Firewall (GFW) believe it is accessing a whitelisted website. @xiaokangwang suggested that the TLS traffic used for the handshake could also be initiated by an external program.
However, none of us developed such a protocol until mid-2022, when ShadowTLS emerged, which did exactly that. Half a year later, when I wrote REALITY, I chose a different approach.
According to the description, the concatenation part of TLSMirror is more like the initial version of ShadowTLS, which cannot defend against redirect attacks, hence the need for v2v3.Redirect attacks targeting such protocols refer to scenarios where the server needs to distinguish whether a connection is provided by a proxy protocol client. The client must first provide an identity proof, but if the proof is inadequately obfuscated (if, for example, it is obfuscated by directly switching to its own AEAD from a TLS record), an attacker can redirect a connection to the actual website and observe whether it abnormally disconnects to identify the protocol.
Based solely on the description, the current version of TLSMirror appears unable to defend against this attack
补充:当时没直接写 ShadowTLS 这种东西,以及后来 REALITY 选择另一个路线的一个原因是,ShadowTLS 这样的路线需要使用外部的加密方案,但是我不是很想自创一种加密,所以干脆直接复用 TLS 的加密方案,这也是与 Cloak 等其它方案最大的区别
我觉得 REALITY 这个路线的优点是显而易见的,那就是直接获得了 TLS 级别的加密水平,比如 TLSv1.3 只保留了最安全的加密方式,有前向安全,最近的抗量子也可以直接上,此外 REALITY 的认证部分采用了公私钥的设计,仅拿到客户端配置无法识别、解密流量
流量整形的部分可以交给内层比如 Vision,长远来看的话也可以由 REALITY 的 TLSv1.3 padding 直接完成 https://github.com/net4people/bbs/issues/481#issuecomment-2984668432
Additional note: At the time, I didn't directly mention ShadowTLS, and one of the reasons REALITY chose a different approach later was that ShadowTLS requires the use of an external encryption scheme. However, I didn't want to create my own encryption scheme, so I decided to reuse TLS's encryption scheme instead. This is also the biggest difference between REALITY and other solutions like Cloak.
I believe the advantages of the REALITY approach are clear: it directly achieves TLS-level encryption strength, such as TLSv1.3, which retains only the most secure encryption methods, including forward secrecy, and the latest quantum-resistant encryption can be implemented directly. Additionally, the authentication component of REALITY uses a public-private key design, meaning that without the client configuration, it is impossible to identify or decrypt the traffic.
Traffic shaping can be handled by the inner layer, such as Vision. In the long run, it could also be directly implemented using REALITY's TLSv1.3 padding. https://github.com/net4people/bbs/issues/481#issuecomment-2984668432
Let me see if I understand. The user makes a TLS connection (through a proxy IP address) to a destination TLS server. The proxy, at first, does not modify the content of the communication at all (not the packet payloads, nor their size and timing). The contents of the TLS connection are generated by a "carrier" TLS client, which can be anything. At some point, the user begins covert communication: it begins replacing TLS application records (in the manner of Slitheen, Protozoa, or Balboa) with different TLS applications of the same size, encrypted under a different key. The proxy server somehow detects when this change happens, and begins forwarding traffic to covert destinations, now repurposing the original TLS connection as a proxy to other hosts.
It makes me think a little of TapDance, specifically the way TapDance used an incomplete HTTP request to the overt destination to steganographically carry signaling data. See Section 4.1. Is that comparison appropriate? The TapDance authors had to do experiments to find out how long web servers, in the wild, keep connections open for incomplete HTTP requests; it was a bit involved. Are there any similar difficulties with suddenly repurposing a TLS connection? The original, overt, destination stop receiving data; what happens when the destination closes the connection?
The carrier TLS client is no longer actually communicating with the original destination. Let's say it was an Internet radio client, for example. The traffic analysis signature will be the same until the moment of the switch, but then the pattern will probably change because the Internet radio client won't still be getting the same feedback from the radio station web server anymore. When Slitheen did traffic replacement, it did so only for "leaf" resources such as images, whose contents don't affect the rest of traffic.
How does the TLSMirror proxy server know when the change has occurred, and the TLS application records are now encrypted with a different key?
原始 TLS 流量还会持续进行传输,我觉得这个挺有意思的,@wkrp 提出原始 TLS 连接可能会关闭,我觉得这个不是大问题,以及服务端识别客户端身份也不成问题,最关键的问题在于我刚注意到 @xiaokangwang 也写道,当前版本的 TLSMirror 没有防御重定向攻击,但当开始处理该问题时,就会发现客户端必须隐蔽地提供身份证明,所以 ShadowTLS 后来才会变成“修改 TLS 握手信息”的样子,或者其实可以使用另一条连接来告知服务端哪些连接是代理,但需要借助别的东西,使得 TLSMirror 自身无法成为“完备的代理”
The original TLS traffic will continue to be transmitted, which I find quite interesting. @wkrp suggested that the original TLS connection might close, but I don't think this is a major issue, and the server identifying the client's identity is also not a problem. The most critical issue is that I recently noticed that @xiaokangwang also mentioned, The current version of TLSMirror does not defend against redirection attacks. However, when addressing this issue, it becomes necessary for the client to secretly provide identity proof. This is why ShadowTLS later evolved into a method that modifies TLS handshake information. Alternatively, another connection could be used to inform the server which connections are proxied, but this would require additional components, preventing TLSMirror from becoming a “complete proxy.”
(Replied messages in chronological order)
Thanks @RPRX,
Based solely on the description, the current version of TLSMirror appears unable to defend against this attack
(about redirection attack) Yes, at the time of making this post, TLSMirror does not has defense against redirection attack. The required connection enrollment confirmation was later implemented after this post: https://github.com/v2fly/v2ray-core/commit/5a003982dbd1beb26761480a909674a05d9e268c .
The reason TLSMirror is currently not released to users is that its development is still on going, so please expect additional improvement of its functionality.
当时没直接写 ShadowTLS 这种东西,以及后来 REALITY 选择另一个路线的一个原因是,ShadowTLS 这样的路线需要使用外部的加密方案,但是我不是很想自创一种加密,所以干脆直接复用 TLS 的加密方案
(@wkrp: The translation for this sentence was substantially different from its actual meaning in Chinese. I was unable to quote it. )
RPRX said RPRX was didn't wrote something like ShadowTLS and have chosen a different path for REALITY is that RPRX don't wants to invent your own crypto and wish to reuse TLS's encryption scheme. This make it different from Cloak and other protocols.
I agree there are some balancing done between don't invent your own crypto and censorship resistant. In my case I wish to maximize TLSMirror's censorship resistance property so I done differently by not interrupting the original TLS connection. The users are expected to use a encrypted proxy protocol within this tunnel to protect their traffic, and the TLSMirror layer only transform traffic with encryption, without don't always securely encrypt the traffic.
I understand your intention of never encrypt a traffic more than once(presumably for benchmark reason), so the transport layer should securely handle encryption(since it is already doing so anyway) so that the proxy protocol do not need to encrypt the traffic again. TLSMirror has different trade offs.
Thanks @wkrp ,
the user begins covert communication: it begins replacing TLS application records
In TLSMirror's case, the payload traffic are inserted into TLS Connection, coexist with original connection. So the original TLS connection is still there and keep communication open, and working for both original client and forwarded server.
The proxy server somehow detects when this change happens, and begins forwarding traffic to covert destinations, now repurposing the original TLS connection as a proxy to other hosts.
How does the TLSMirror proxy server know when the change has occurred, and the TLS application records are now encrypted with a different key?
The original connection is keep intact the entire duration of the payload connection's lifetime. The TLSMirror will try to decrypt each packet with its own key to see if the packet is decryptable. If the decryption is successful, then the packet will not be forward to the original host and get delivered to the payload connection, otherwise the packet get forwarded to forwarded upstream. So the original application data are always bidirectional forwarded, while payload application data get inserted into it while passing through the hostile network, and removed once it reach the other end of the V2Ray TLSMirror transport. Since TLS connection does has a checksum, TLSMirror can detect if its key is the correct key or not.
It makes me think a little of TapDance, specifically the way TapDance used an incomplete HTTP request to the overt destination to steganographically carry signaling data. See Section 4.1. Is that comparison appropriate?
In my opinion, these design are slightly different as the connection to the original site is not interrupted so for the remote server's end, the connection is working as normal.
One of the issue with other protocol that close the original connection or otherwise doesn't keep the original connection intact is that the site administer of the fronting site will see anomaly on their end as there is a lot of unsuccessful TLS handshakes. As a result they might attempt to block or adjust their settings to prevent themselves being used as a forwarded site(often by disabling TLS1.3 support). TLSMirror prevent this by keep the original connection open, and functional, so the site administrator of the forwarded site will not see any unsuccessful handshake or error messages, while simultaneously support TLS1.2 as well so the forwarded site could not sabotage TLSMirror by disabling the support for TLS1.3 connections.
The TapDance authors had to do experiments to find out how long web servers, in the wild, keep connections open for incomplete HTTP requests; it was a bit involved. Are there any similar difficulties with suddenly repurposing a TLS connection? The original, overt, destination stop receiving data; what happens when the destination closes the connection?
In TLSMirror's case, the original connection is still working for both client and server. So the client(either embedded traffic generator or an external program generates TLS traffic) is responsible for keep the server happy and busy, and sending valid and "useful" request to the forwarded server to keep the connection open, and its traffic shape looks like original payload traffic. The forwarded server will not close the forwarded carrier connection as from its point of view the client is still communicating with it normally.
When Slitheen did traffic replacement, it did so only for "leaf" resources such as images, whose contents don't affect the rest of traffic. In TLSMirror's case, the traffic pattern does get changed as it does traffic insertion, not replacement. So when the traffic pass through the hostile network, there will be more traffic on carrier connection.
I understand by just replacing the traffic the traffic shape will in theory remain "the same" of the original traffic. But for practical usability concerns, I did not choose this path as this would result in artificially slow down of the payload connection without significant additional complexity in sending traffic over multiple carrier connections.
The good thing about only inserting traffic is that the carrier connection will still keep working, so the original connection's traffic shape will still be there, acting as a nature padding for the connection in the original traffic's shape.
Thanks @RPRX,
Alternatively, another connection could be used to inform the server which connections are proxied, but this would require additional components, preventing TLSMirror from becoming a “complete proxy.”
It is right that TLSMirror does requires an additional layer of "connection confirmation". I understand there is some usability concern around here, as it makes this protocol much harder to configure. However, since the confirmation traffic can be sent over TLSMirror transport connection as well, only the initial confirmation requires a separate proxy connection, subsequent confirmation can be done over the same TLSMirror transport.
TLSMirror is not just a protocol, alone on its own, it is a part of V2Ray ecosystem that will take advantage of other components to achieve its function. I don't believe a protocol will need to transport all information within the same TCP connection to call it complete proxy protocol, nor does I think a protocol need to aim such target at the expense of compromising its anti-censorship capacity(such as using external TLS connection as a carrier connection). However I understand these requirements does increase the complexity of setup, which is undesirable(despite necessary).
深入分析“原始 TLS 流量还会持续进行传输”,它虽然有趣,但会造成一个安全问题是,原始 TLS 的 AEAD 并不包含对 TLSMirror 那些 records 的顺序保护,也就是说,基于目前的设计描述,可以想象如果攻击者只把 TLSMirror 的 records 抽离出来,该 TLS 连接并不会异常断开(当然也可以多开一条连接来传递顺序信息,但更复杂了)。此外原始 TLS 是正常断开还是异常断开只有自身知道,我前面说“原始 TLS 连接可能会关闭,我觉得这个不是大问题”是因为我们完全可以在原始 TLS 正常断开后继续传输流量,但是如果攻击者插入一个 TLS record 使它异常断开,而我们认为它是正常断开并继续传输流量,就会露馅。
并且我细想了一下,“原始 TLS 流量还会持续进行传输”也存在流量整形上的问题,因为在它常规的流量形状外面再加别的东西,就很容易偏离它常规的流量形状。更优解似乎是直接把被代理流量整形为目标网站常规的流量形状、替换掉原始 TLS,效率也更高。
A deeper analysis of “raw TLS traffic continues to be transmitted” is interesting, but it poses a security issue: the AEAD in raw TLS does not include sequence protection for the records in TLSMirror. In other words, based on the current design description, it is conceivable that if an attacker extracts the TLSMirror records, the TLS connection will not abnormally disconnect (though opening an additional connection to transmit sequence information is also possible, but more complex).Additionally, whether the original TLS connection closes normally or abnormally is only known to itself. I previously stated, “The original TLS connection may close, but I don’t think this is a major issue,” because we can continue transmitting traffic after the original TLS connection closes normally. However, if an attacker inserts a TLS record to cause an abnormal disconnect, and we mistakenly assume it closed normally and continue transmitting traffic, this would expose the vulnerability.
Furthermore, upon further consideration, “the original TLS traffic continues to be transmitted” also poses a traffic shaping issue, as adding additional elements outside its regular traffic pattern makes it easy to deviate from its normal traffic shape. A better solution seems to be directly shaping the proxied traffic into the target website's regular traffic pattern and replacing the original TLS, which is also more efficient.
the user begins covert communication: it begins replacing TLS application records
In TLSMirror's case, the payload traffic are inserted into TLS Connection, coexist with original connection. So the original TLS connection is still there and keep communication open, and working for both original client and forwarded server.
I see. Thank you for correcting my misunderstanding. The idea is not to use traffic replacement, but instead to add the covert application records to the carrier stream. So the resulting traffic analysis signature will be carrier + covert. But you can delay the start of the covert stream, so that, at the beginning of the connection (the most crucial part), the traffic analysis signature can exactly match the carrier stream. Even when both carrier and covert are operating simultaneously, the carrier may act as padding to provide some degree of obfuscation for covert.
I am not an expert on website fingerprinting, but the problem of classifying a traffic analysis signature that is composed of multiple flows mixed together, such as carrier + covert, might be known as "multi-tab website fingerprinting". See, for example, Section 4.5 of "A critical evaluation of website fingerprinting attacks" from 2014. "We observe a dramatic drop in the accuracy for all the classifiers with respect to the accuracy obtained with the control crawl (when the classifiers are trained and tested using single tab traces)…". Since then, there has been a lot of research (which I am not familiar with) on how to do multi-tab website fingerprinting. I found "Towards Robust Multi-tab Website Fingerprinting", which is an extension of an S&P 2023 paper. It has a survey of prior work in Section I.
Thanks @RPRX ,
深入分析“原始 TLS 流量还会持续进行传输”,它虽然有趣,但会造成一个安全问题是,原始 TLS 的 AEAD 并不包含对 TLSMirror 那些 records 的顺序保护,也就是说,基于目前的设计描述,可以想象如果攻击者只把 TLSMirror 的 records 抽离出来,该 TLS 连接并不会异常断开(当然也可以多开一条连接来传递顺序信息,但更复杂了)。
对 其实这个调换原流量和插入流量的顺序问题的解决方法已经想好了,不过还没实现。当然这个需要再单独加一个功能来解决,尽管方法并不是单独再开一个连接。在首个加密帧被插入后的每个加密TLS帧的最后8个字节的加密数据都会被根据发送端的序列号被再原地加密一次。在接收端都会先根据接收端的序列号进行原地解密后再尝试解密或转发到原链接。如果序列号错误就会在TLSMirror段和远程都解密失败,然后在远端按照正常的TLS错误处理流程进行处理(这个错误在TLSMirror处不能被检测到,但是没关系因为这个错误给转发端进行处理反审查效果才更强)。
而我们认为它是正常断开并继续传输流量,就会露馅。
已经 实现 了在转发 TLS Alert 后就不再传输的功能,TLS协议要求关闭连接的时候发送的close notify可以被正确处理。当然这个需要本地的真实TLS客户端收到服务器的TLS Alert后自己也发出TLS Alert给服务器后才行(所以需要一个真的TLS客户端作为TLS流量生成器)。
(Translated by ChatGPT4.1 Copilot, proof-read by author)
A deeper analysis of “raw TLS traffic continues to be transmitted” is interesting, but it poses a security issue: the AEAD in raw TLS does not include sequence protection for the records in TLSMirror. In other words, based on the current design description, it is conceivable that if an attacker extracts the TLSMirror records, the TLS connection will not abnormally disconnect (though opening an additional connection to transmit sequence information is also possible, but more complex)
Actually, I have already thought of a solution to the problem of swapping the order of original traffic and inserted traffic, but it hasn't been implemented yet. Of course, this will require adding a separate feature to solve it, although the solution does not involve opening a new connection. After the first encrypted frame is inserted, the last 8 bytes of encrypted data in each subsequent encrypted TLS frame will be re-encrypted in place based on the sender's sequence number. On the receiving end, the data will first be decrypted in place using the receiver's sequence number before attempting to decrypt or forward it to the original connection. If the sequence number is incorrect, decryption will fail both at the TLSMirror end and at the remote end, and then the remote end will handle it according to the normal TLS error handling process (this error cannot be detected at the TLSMirror, but that's fine because letting the forwarding end handle the error actually makes more senses when it comes to anti-censorship purpose).
However, if an attacker inserts a TLS record to cause an abnormal disconnect, and we mistakenly assume it closed normally and continue transmitting traffic, this would expose the vulnerability.
The functionality to stop transmission after forwarding a TLS Alert has already been implemented. The close notify is sent when closing the connection, as required by the TLS protocol, can be handled correctly. Of course, this requires that the local, real TLS client also sends a TLS Alert to the server after receiving a TLS Alert from the server (so a real TLS client is needed as the TLS traffic generator).
对 其实这个调换原流量和插入流量的顺序问题的解决方法已经想好了,不过还没实现。当然这个需要再单独加一个功能来解决,尽管方法并不是单独再开一个连接。在首个加密帧被插入后的每个加密TLS帧的最后8个字节的加密数据都会被根据发送端的序列号被再原地加密一次。在接收端都会先根据接收端的序列号进行原地解密后再尝试解密或转发到原链接。
如果采用这种方式则需要额外的字节来传递认证信息,比如 AEAD 会增加 16 字节的长度,从而破坏原始的流量形状,虽然不及 ShadowTLSv3 给关键 records 加了四字节导致被 Aparecium 宣告“dead”那么严重。其实我觉得既然都有一条主控连接了,直接用它来传递主控信息就可以,缺点是当这条主控连接被 GFW 干扰时会影响其它所有连接。
当然产生这个问题的根本原因还是 TLSMirror 希望保持原始 TLS 连接的传输,这也是它与其它类似代理协议的最大不同之处,但如前所述,这样做其实存在一些流量整形上的问题,如果细想的话不一定优于其它类似代理协议的“扔掉原始 TLS 连接”。
If this approach is adopted, additional bytes are required to transmit authentication information. For example, AEAD adds 16 bytes to the length, thereby disrupting the original traffic pattern. However, this is not as severe as ShadowTLSv3, which adds four bytes to critical records, leading to it being declared “dead” by Aparecium. In my opinion, since there is already a control connection, it would be more straightforward to use it to transmit control information.The downside is that if this control connection is interfered with by the GFW, it will affect all other connections.
Of course, the fundamental cause of this issue is that TLSMirror aims to preserve the original TLS connection's transmission, which is its key distinction from other similar proxy protocols. However, as mentioned earlier, this approach actually introduces some traffic shaping issues, and upon closer examination, it may not necessarily be superior to other similar proxy protocols that “discard the original TLS connection.”
已经 实现 了在转发 TLS Alert 后就不再传输的功能
如果选择在原始 TLS 连接断开后不再传输流量则的确不太需要区分它是正常 alert 还是异常,缺点是更加复杂一些、可用性低一些。
If you choose not to transmit traffic after the original TLS connection is disconnected, it is indeed unnecessary to distinguish between normal alerts and abnormal alerts. However, the disadvantage is that it is more complex and less usable.
Thanks @wkrp,
But you can delay the start of the covert stream, so that, at the beginning of the connection (the most crucial part), the traffic analysis signature can exactly match the carrier stream.
Yes, this feature is already implemented as connectionReady in embedded traffic generator, that the user can(and should) configure the payload to start only after certain traffic generation step are finished. So initially, during the most dangerous period, maybe TLS and HTTP2 protocol handshaking, where the attacker know for sure what shape of traffic to expect, the payload traffic is being hold until the script is over, when attacker knows less about the connection state.
I am not an expert on website fingerprinting, but the problem of classifying a traffic analysis signature that is composed of multiple flows mixed together, such as carrier + covert, might be known as "multi-tab website fingerprinting".
For anti-censorship protocol traffic shaping, there is an existing research about the effectiveness of different traffic shaping attempts: 《Fingerprinting Obfuscated Proxy Traffic with Encapsulated TLS Handshakes》's Table 3 . In this paper, the result is similar: mux(blending more than one streams together) is more effective than most padding schemes, with the highest censorship resistance achieved with V2Ray's mux system. I understand TLSMirror's traffic shape is neither payload(application) independent nor a replay of the a training traffic's length, and more research/work is needed on this.
I still have open research question about what kind of configurations user should feed into their traffic generator, what is the best carrier traffic? I will read the paper you suggested/referenced to find out some hypothesis to try.
Thanks @RPRX ,
如果采用这种方式则需要额外的字节来传递认证信息,比如 AEAD 会增加 16 字节的长度,从而破坏原始的流量形状
我的设计是把序列认证信息叠加于原有的数据帧中不改变长度,然后,虽然自己不能检测这个信息,但是如果错误的话就会直接让被转发站检测到校验失败进行相应的处理。
My design is to overlay the sequence authentication information onto the original data frames without changing their length. Although TLSMirror cannot detect this information itself, if there is an error, it will be detected by the forwarded site as a checksum error and be handled accordingly.
《Fingerprinting Obfuscated Proxy Traffic with Encapsulated TLS Handshakes》's Table 3
该论文在草案阶段时我看过并提出了两个主要问题,但并没有被采纳,一是该论文的被代理流量均为 TLSv1.2,而现实世界中大多数流量为 TLSv1.3,会少一次握手从而少一些流量特征,据第一作者称针对内层 TLSv1.3 的检测效果不佳,所以选择了 TLSv1.2
另一个问题是 table 3 并没有放出通用性的 c1 模型检测 XTLS Vision 的数据,而是用一个有针对性逆向 Vision 的 c2 模型去检测(如果对每个协议都做一个针对性的模型,那当然能提高准确度),使得最后的 TPR 数据缺乏直接可对比性,误导了读者与最后的结论,据第一作者称 c1 模型针对 XTLS Vision 的检测效果不佳,所以没有把数据放出来
I reviewed this paper during the draft stage and raised two main issues, which were not adopted. First, all the traffic analyzed in the paper was TLSv1.2, while most real-world traffic is TLSv1.3, resulting in one fewer handshake and fewer traffic features. According to the first author, detection performance for inner-layer TLSv1.3 was poor, so TLSv1.2 was chosen.
The second issue is that Table 3 does not provide data for the generic C1 model detecting XTLS Vision, but instead uses a C2 model specifically reverse-engineered for Vision (if a tailored model is created for each protocol, accuracy would naturally improve), making the final TPR data lack direct comparability and misleading readers regarding the final conclusions.According to the first author, the C1 model performed poorly in detecting XTLS Vision, so the data was not included.
我的设计是把序列认证信息叠加于原有的数据帧中不改变长度
~~这是已经实现的吗,因为从信息论的角度来说似乎无法实现~~
My design is to overlay the sequence authentication information onto the original data frame without changing the length.
~~Is this already implemented? Because from an information theory perspective, it seems impossible to achieve.~~
然后,虽然自己不能检测这个信息,但是如果错误的话就会直接让被转发站检测到校验失败进行相应的处理。
I see,大概猜到比如生成一个序列用于 XOR,代理协议服务端只能还原但自己检测不了,我需要思考一下这样设计是否存在问题
Then, although it cannot detect this information itself, if there is an error, the forwarded station will directly detect the verification failure and take corresponding measures.
I see, I guess it's like generating a sequence for XOR, which the proxy protocol server can only restore but cannot detect itself. I need to think about whether this design has any problems.
比如说数据的发送序列是这样的,real 代表原始 TLS 的包,fake 代表 TLSMirror 的包:
real real fake real fake real...
从第三个包开始叠上 XOR,为了避免两个相邻包叠上的数据重复,可以是单调递增,比如 1 2 3 4 5 6 7 8 9...
这样做有一个小问题是,由于代理协议服务端只能还原但自己检测不了,会出现如果攻击者改了第四个包(real),但在时间差内第五个包(fake)仍被代理协议服务端正常解密的情况,不过这并非 XOR 带来的问题,而是同时传输两个连接时固有的问题,等待网站服务端一小段时间即可,但这样会引入延迟,~~或者干脆就不管,等 GFW 有这种攻击了再说~~
我觉得最主要的问题还是在于 TLSMirror 的创新之处,即同时传输两个连接,即由外部程序发起的原始 TLS 连接也有价值,由于 TLSMirror 已经选择了在转发 TLS alert 后不继续使用该连接,则代理的可用性取决于外部程序什么时候有连接。如果要控制外部程序发起原始 TLS 连接则增加了复杂度,且此时它的数据无价值,由自己发起原始 TLS 连接也是数据无价值,这一点是矛盾之处。
For example, the data transmission sequence is as follows, where “real” represents the original TLS packet and “fake” represents the TLSMirror packet:
real real fake real fake real...
Starting from the third packet, apply XOR. To avoid data duplication between adjacent packets, use a monotonically increasing sequence, such as 1 2 3 4 5 6 7 8 9...
There is a minor issue with this approach: since the proxy protocol server can only decrypt but cannot detect the original data, if the attacker modifies the fourth packet (real) but the fifth packet (fake) is still decrypted by the proxy protocol server within the time difference, the modified data will be decrypted. However, this is not an issue caused by XOR but an inherent issue when transmitting two connections simultaneously. Waiting for the website server for a short period of time can resolve this, but this introduces latency. ~~Or just ignore it and deal with it when GFW encounters this attack~~
I think the main issue lies in the innovation of TLSMirror, which is the simultaneous transmission of two connections. The original TLS connection initiated by the external program also has value. Since TLSMirror has chosen not to continue using the connection after forwarding the TLS alert, the availability of the proxy depends on when the external program has a connection. Controlling the external program to initiate the original TLS connection adds complexity, and at this point, its data is worthless. Initiating the original TLS connection yourself also results in worthless data, which is a contradiction.
由于 TLSMirror 已经选择了在转发 TLS alert 后不继续使用该连接
需要指出的是,上面的所有攻防推导都已经基于这个前提,否则会出现攻击者改了 real 包但 TLSMirror 还在继续传输 fake 包的情况
Since TLSMirror has chosen not to continue using the connection after forwarding the TLS alert
It should be noted that all of the above attack and defense deductions are based on this premise. Otherwise, an attacker could change a real packet, but TLSMirror would continue to transmit the fake packets.
会出现如果攻击者改了第四个包(real),但在时间差内第五个包(fake)仍被代理协议服务端正常解密的情况
我想了一下这个问题还有另一个解法:在第五个 fake 包内对上一个 fake 包后所有的 real 包进行额外认证,~~不会违反信息论~~
至此,最核心的问题还是“原始 TLS 连接有价值”和“代理可用性”的矛盾,基于当前的设计,代理可用性取决于外部程序的连接需求(一个解法是使用尽可能多的境外 IP 搭建尽可能多的端口转发,或者 IPv6 也不是不行),而如果我们倾向于自己发起原始 TLS 连接,则数据无价值、其实可以被丢弃,就失去了 TLSMirror 最大的创新之处(不过至少还是优于 ShadowTLS 系列)。
A situation may arise where the attacker modifies the fourth packet (real), but the fifth packet (fake) is still decrypted normally by the proxy protocol server within the time difference.
I thought about this problem and came up with another solution: perform additional authentication on all real packets after the previous fake packet in the fake fifth packet. ~~This does not violate information theory.~~
At this point, the core issue remains the conflict between “the value of the original TLS connection” and “proxy availability.” Based on the current design, proxy availability depends on the connection requirements of external programs (one solution is to use as many overseas IP addresses as possible to set up as many port forwarding rules as possible, or IPv6 is also an option). If we prefer to initiate the original TLS connection ourselves, the data becomes worthless and can be discarded, thereby losing the greatest innovation of TLSMirror (though it is still superior to the ShadowTLS series).
但仔细想想如果包含“对 real 包认证”的 fake 包到达及时,仍然可以扔掉正常的 TLS alert、继续传输流量,从而解决代理可用性的问题
~~不过似乎还有一些边缘情况,比如常规的流量断开 pattern(不活跃、max 时间等)、fake 包应当多及时等,有点烧脑,先不想了~~
But think about it carefully. If a fake packet containing “authentication for the real packet” arrives in time, you can still discard the normal TLS alert and continue to transmit traffic, thereby solving the proxy availability issue.
~~However, there seem to be some edge cases, such as regular traffic disconnect patterns (inactivity, max time, etc.) and fake packets needing to arrive more promptly, which is a bit brain-teasing. Let's not think about it for now.~~
在第五个 fake 包内对上一个 fake 包后所有的 real 包进行额外认证
hash(hash+real) 不断循环就行,这样就能知道流量有没有被 GFW 篡改,从而避开异常 TLS alert,成为“继续传输流量”的基础
perform additional authentication on all real packets after the previous fake packet in the fake fifth packet.
hash(hash+real) Just keep looping, and you will be able to determine whether the traffic has been tampered with by GFW, thereby avoiding abnormal TLS alerts and becoming the basis for “continuing to transmit traffic.”
这样的话比 ShadowTLS 更优,只剩三个小问题,一是传输初始认证信息需要别的通道,二是加密机制一般,三是目标是结合外部程序
This is better than ShadowTLS, with only three minor issues remaining. First, a separate channel is required to transmit the initial authentication information. Second, the encryption mechanism is mediocre. Third, the goal is to integrate with external programs.
hash(hash+real)不断循环就行,这样就能知道流量有没有被 GFW 篡改,从而避开异常 TLS alert,成为“继续传输流量”的基础
实际上实现的版本并没有丢弃"正常"的TLSAlert或者其他的正常连接关闭消息的功能。就是普普通通的加密水印一下数据包。毕竟区分是不是正常的Alert容易出问题,不如先保守一点保证协议没办法被识别,足够易用,再想别的。
Actually, the implemented version does not discard "normal" TLS Alerts or other regular connection termination messages. It simply adds an encrypted watermark to the data packets in a straightforward manner. After all, distinguishing whether an Alert is normal can easily lead to issues, so it's better to take a conservative approach at first to ensure the protocol cannot be identified and is sufficiently usable, and then consider other improvements.
实际上实现的版本并没有丢弃"正常"的TLSAlert或者其他的正常连接关闭消息的功能。就是普普通通的加密水印一下数据包。毕竟区分是不是正常的Alert容易出问题,不如先保守一点保证协议没办法被识别,足够易用,再想别的。
我觉得挺好区分是不是正常的 alert,因为基本上当有人篡改数据时才会异常 alert
不过我想了下防止包被调换位置确实需要加密,因为简单的 XOR 会容易受到攻击
但这样还是没有解决攻击者可以利用时间差来发现其实有两个检测端点,从而识别协议的风险,所以 fake 包里附带认证是必要的
这样也可以在有价值的 TLS 连接关闭后继续传输信息,因为 TLSMirror 的特性要利用外部程序发起的有价值的 TLS 连接才比较有意义,而它们是不可控的。如果要用 v2ray 自己发起连接,就不太有必要搞这种两个 TLS 同时传输这么麻烦,直接流量整形就行了。并且 TLS 握手基本上没有限制,但 HTTP 请求会有风控,无意义请求数多了可能就会被目标网站拒绝。
I think it's pretty easy to distinguish between normal alerts and abnormal ones, because abnormal alerts basically only occur when someone tampers with the data.
However, I thought about it and realized that encryption is indeed necessary to prevent packets from being swapped, because simple XOR is vulnerable to attacks.
But this still doesn't solve the risk that attackers can exploit the time difference to discover that there are actually two detection endpoints and identify the protocol. Therefore, it is necessary to include authentication in the fake packet.
This also allows information to continue to be transmitted after valuable TLS connections are closed, because the TLSMirror feature is only useful when valuable TLS connections are initiated by external programs, which are uncontrollable.If you want to use V2Ray to initiate connections yourself, there is no need to go through the hassle of transmitting two TLS connections simultaneously. Simply traffic shaping is sufficient. Additionally, TLS handshakes have few constraints, but HTTP requests may trigger security controls, and an excessive number of meaningless requests could result in the target website rejecting the connection.
顺序问题应该是好解决的 通过初始的密钥材料协商获得一个连续密钥流(aes-ctr或者chacha什么的方案都可以) 然后拿个16字节出来和每个record(无论真假)的最后16字节进行异或 服务端用同样的方法生成同样的密钥流异或回来 最后再丢进去解密或者转发到伪装目标 任何对record的位置调换或者摘掉一部分都会导致认证失败抛出alert 而且不会影响长度 (其实就是用流密码加密每个record的最后几个字节 认证不重要 因为解密出错误的明文给到服务端它可以检测出)
The sequence issue should be easy to resolve. Obtain a continuous key stream (using an aes-ctr or chacha scheme, for example) through initial key material negotiation. Then take a 16-byte segment and XOR it with the last 16 bytes of each record (regardless of authenticity). The server generates the same key stream using the same method and XORs it back. Finally, it is decrypted or forwarded to the target. Any rearrangement of record positions or removal of parts will cause authentication failure and trigger an alert, without affecting the length. (Essentially, this is using a stream cipher to encrypt the last few bytes of each record. Authentication is not critical because the server can detect errors by decrypting the plaintext.)
@Fangliding 如果不认证,攻击者可以利用两个检测端点的时间差来实现改了 real 包,但 fake 包仍被正常接收、处理
不过我想了下,如果在 fake 包里包含对前面的 real 包的认证,但攻击者给这个 fake 包加延迟,也会有点问题,~~又烧脑了~~
但是审查者通过篡改 TLS record 来确认自己的怀疑,我觉得目前不太可能这样干,除非哪天大家都用 TLSMirror 或~~形势严峻~~
If not authenticated, an attacker can exploit the time difference between the two detection endpoints to modify the real packet while the fake packet is still received and processed normally.
However, I thought about it, and if the fake packet includes authentication for the preceding real packet, but the attacker adds a delay to the fake packet, there would also be some issues. ~~This is getting complicated.~~
However, reviewers could confirm their suspicions by tampering with the TLS record, but I think this is unlikely at the moment, unless everyone starts using TLSMirror or ~~the situation becomes dire~~.
《Fingerprinting Obfuscated Proxy Traffic with Encapsulated TLS Handshakes》's Table 3
该论文在草案阶段时我看过并提出了两个主要问题,但并没有被采纳,一是该论文的被代理流量均为 TLSv1.2,而现实世界中大多数流量为 TLSv1.3,会少一次握手从而少一些流量特征,据第一作者称针对内层 TLSv1.3 的检测效果不佳,所以选择了 TLSv1.2
另一个问题是 table 3 并没有放出通用性的 c1 模型检测 XTLS Vision 的数据,而是用一个有针对性逆向 Vision 的 c2 模型去检测(如果对每个协议都做一个针对性的模型,那当然能提高准确度),使得最后的 TPR 数据缺乏直接可对比性,误导了读者与最后的结论,据第一作者称 c1 模型针对 XTLS Vision 的检测效果不佳,所以没有把数据放出来
I reviewed this paper during the draft stage and raised two main issues, which were not adopted. First, all the traffic analyzed in the paper was TLSv1.2, while most real-world traffic is TLSv1.3, resulting in one fewer handshake and fewer traffic features. According to the first author, detection performance for inner-layer TLSv1.3 was poor, so TLSv1.2 was chosen.
The second issue is that Table 3 does not provide data for the generic C1 model detecting XTLS Vision, but instead uses a C2 model specifically reverse-engineered for Vision (if a tailored model is created for each protocol, accuracy would naturally improve), making the final TPR data lack direct comparability and misleading readers regarding the final conclusions.According to the first author, the C1 model performed poorly in detecting XTLS Vision, so the data was not included.
另外刚想到一个问题,由于被代理的流量均为 TLSv1.2,并不会触发 XTLS Vision 的裸奔机制,也就是说握手之后仍有 TLS in TLS 特征
取决于 c2 模型到底利用了哪些特征,不知道可解释性如何
反正“有针对性逆向”的问题只是因为 Vision 尚未开放 padding 的用户配置(Seed)而已,当初不确定该设计到哪种程度、消息依赖等
Additionally, I just thought of another issue: since all proxied traffic uses TLSv1.2, it won't trigger XTLS Vision's exposure mechanism. This means TLS-in-TLS characteristics remain present after the handshake.
It depends on which features the c2 model actually utilizes, I'm unsure about its interpretability.
Anyway, the “targeted reverse engineering” issue is merely because Vision hasn't yet opened user configuration for padding (Seed). Back then, we weren't sure how far to design it or handle message dependencies.