Calling existing TLS Lua dissector on TLS tunneled traffic gives wrong dissection.
Hi, everyone. I'm working on a Lua dissector for a proxy protocol called Trojan, which use TLS to tunnel HTTPS traffic (i.e., there is a TLS layer protecting the inner HTTPS traffic). I could decrypt the outer TLS and do some dissection. I'm sorry that it seems to requires 60 points to upload pictures, so I'll try my best to describe my problem.
Before I call the existing TLS dissector to dissect inner HTTPS payload, I successfully decrypt the outer TLS, and add the inner payload to the dissection tree. The dissection tree looks like this:
... Lower Layers...
Tranport Layer Security <---- The outer TLS layer
Trojan Protocol <---- The root of Trojan protocol tree
++++ Trojan Tunneled Data [...]: 160303007a020... <---- The inner HTTPS payload
As you could see, the '160303...' is the first bytes of a typical TLS packet. Now I want to use the existing TLS dissector to dissect inner payload by
Dissector.get('tls'):call(remaining_buffer, pktinfo, tree)
The first several TLS handshake packets are dissected correctly, like this:
... Lower Layers...
Tranport Layer Security <---- The outer TLS layer
Trojan Protocol <---- The root of Trojan protocol tree
++++ Trojan Tunneled Data [...]: 160303007a020... <---- The inner HTTPS payload
++++++ Tranport Layer Security <---- The inner TLS layer
++++++++ TLS 1.3 Record Layer: Handshake Protocol: Client Hello
++++++++ ...More TLS dissection info...
However, when the inner payload is TLS Application Data, the whole dissection seems not to work, the dissection tree becomes:
... Lower Layers...
Tranport Layer Security <---- The outer TLS layer
++++ Application Data <---- No further decoding, even the previous Trojan layer disappears.
Furthermore, I found that these Application Data packets are even not decrypted. However, if I don't call the built-in TLS dissector, the inner payload is decrypted, which seems weird to me.
UPDATE 1: I find that I could share related images about this problem through Github, I have written a related markdown file attached with pictures. If you are interested, please check it for better details. Sorry for that inconvenience.:)
UPDATE 2: I'm using Wireshark Version 4.3.0 (v4.3.0rc1-256-g49164027c622), built from the source following the official instructions. I'm using Windows 11, and Lua version is 5.4.2.
UPDATE 3: If you want to reproduce the issue, I have upload the related Trojan .pcapng file and the Lua file. I found that the built-in HTTPS dissector will override my dissector, i.e., the code
DissectorTable.get("tcp.port"):add(port, trojan)
DissectorTable.get("tls.port"):add(port, trojan)
will not work unless I disable the HTTPS heuristic dissection. Now this issue has been solved by a quicker fix by adding:
DissectorTable.get("tls.alpn"):add("h2", trojan)
DissectorTable.get("tls.alpn"):add("http/1.1", trojan)
UPDATE 4: Now the inner TLS dissection could be used properly, thanks to @johnthacker. I have released the updated code on Github. However, the actual HTTP payload is not handled properly (see the comment for more information), which may still be the ...
TLS tunneled within TLS is difficult. However, first things, can you please give the version of Wireshark you are using, e.g. copied from Help -> About Wireshark?
@johnthacker Thanks for your reply! I'm using Wireshark Version 4.3.0 (v4.3.0rc1-256-g49164027c622), which is built from source following the official instruction. Now I find that I could share my related images through Github, and I have updated my question to add more information.
What causes the HTTP2 dissector to be called is the ALPN, because there's no option to ignore that and prefer the port based table. So the only thing you need to do to have your dissector called is to comment out the registration
dissector_add_string("tls.alpn", "h2", http2_handle);
However, for your testing purposes you could just register your dissector to that ALPN in the Lua code:
DissectorTable.get("tls.alpn"):add("h2", trojan)
That doesn't solve the TLS tunnelling issue but it's a quicker way of getting your dissector called despite the bogus ALPN