This is a static archive of our old Q&A Site. Please post any new questions and answers at

How can I decrypt SSL session with Lua dissector ?


Hello everyone

I used to decrypt HTTPS session by providing "Client Random" and "Master Secret" into wireshark.

Recently, I need to decrypt SSL session which is created in USB communication. USB header is parsed by wireshark.

But some byte and SSL header are not parsed by wireshark. it just show me payload as "Leftover Capture Data"

alt text

So I decide to use Lua script for parsing "Leftover Capture Data" as 28-byte unknown protocol and SSL.

My Lua script is

    local ios_usb = Proto("iOS_USB", "iOS USB Protocol")
    local ios_temp = Proto("iOS", "iOS USB TEMP Protocol")
local msgtype  = "Unknown #1","ios.msgtype", ftypes.UINT32)
local memaddr  = "Unknown #2","ios.memaddr", ftypes.UINT32)
local memlen   = "Unknown #3", "ios.memlen",ftypes.UINT32)
local regdata  = "Unknown #4","ios.regdata", ftypes.UINT32)
local stopdata1 = "Unknown #5","ios.stopdata1", ftypes.UINT32)
local stopdata2 = "Unknown #6","ios.stopdata2", ftypes.UINT32)
local stopdata3 = "Unknown #7", "ios.stopdata3",ftypes.UINT32)

ios_usb.fields = {msgtype, memaddr, memlen, regdata, stopdata1, stopdata2, stopdata3}

local f_urb_type ="usb.urb_type")
local f_transfer_type ="usb.transfer_type")
local f_endpoint ="usb.endpoint_number.endpoint")

function ios_usb.dissector(tvbuf, pktinfo, root)
 local pktlen = tvbuf:reported_length_remaining()

 if pktlen < 28 then
    return pktlen

if pktlen == 28 then

    return 28

 local tree = root:add(ios_usb, tvbuf:range(0,pktlen))
 local transfer_type = tonumber(tostring(f_transfer_type))
 local ssl_dis =Dissector.get("ssl")

            pktinfo.cols.protocol =

            tree:add(msgtype, tvbuf:range(0,4))
            tree:add(memaddr, tvbuf:range(4,4))
            tree:add(memlen, tvbuf:range(8,4))
            tree:add(regdata, tvbuf:range(12,4))
            tree:add(stopdata1, tvbuf:range(16,4))
            tree:add(stopdata2, tvbuf:range(20,4))
            tree:add(stopdata3, tvbuf:range(24,4))

local newbuf = tvbuf:range(28,pktlen-28):tvb()
local first = tvbuf:range(28,1):uint()

if first == 0x16 or first == 0x17 then


    return pktlen

function ios_usb.init()

local usb_bulk_dissectors = DissectorTable.get("usb.bulk")
usb_bulk_dissectors:add(0xFF, ios_usb)


This script can parse SSL header successfully

I also extract Client Random and Master secret. And I put it in the Preferences -> Protocols -> SSL -> (Pre)master-Secret Log file

Even though I give key file for decrypting, I cannot get decrypted payload of SSL.

alt text

Is there any tips for decrypting ssl session using Lua ssl dissector?

Thank you!

asked 03 Oct ‘16, 23:05

yobob's gravatar image

accept rate: 0%

edited 04 Oct ‘16, 02:13


Wow for the idea. However, I’m afraid that to get a real solution, you’ll need to file a bug (category enhancement), because currently, part of ssl decryption configuration is to tell the ssl dissector what other dissector to use to handle the decrypted data, and the fields used as index to the table are IP address and tcp port.

As a temporary workaround I could imagine to use tshark to extract the payload from the URBs (-T fields -e usb.addr -e usb.capdata) and feed its output to a script which would provide fake TCP headers to the data - which, however, would also not be an easy task as you would have to properly imitate at least the seq and ack numbers so that the tcp dissector would be happy. The script could output a simple hexdump format which you would then feed to text2pcap or import it to Wireshark using File -> Import from Hex Dump.

(04 Oct ‘16, 02:26) sindy

An idea which didn’t come to my mind instantly would be to use Lua to create these fake TCP and IP headers during dissection (you’d have to create a new tvb containing the fake headers followed by the data extracted from the URB), and you would have to save the values for the headers as each frame may be dissected multiple times - they are dissected in sequence only once during loading or capture of the file.

(04 Oct ‘16, 03:05) sindy

Would it be easier to create UDP headers, and then you’d have DTLS?

(04 Oct ‘16, 03:13) grahamb ♦

I’m not sure. DTLS uses its own sequence numbering to ensure that the TLS PDUs are properly ordered, plus it uses an indicator of cipher state changes, so instead of generating TCP’s seq and ack values outside the original encrypted data, you’d have to take care about DTLS’s sequence_number and epoch in the middle of the encrypted data.

(04 Oct ‘16, 03:26) sindy

Ah, I’ve only looked at DTLS ever so briefly and obviously didn’t understand the intricacies.

(04 Oct ‘16, 03:43) grahamb ♦

Thank you for your comments. I will try to replace USB header to TCP dummy header. By the way, the Lua ssl dissector is different with the default ssl dissector of wireshark?

(05 Oct ‘16, 20:01) yobob

There is no such thing like “Lua SSL dissector” (unless you have written your own one but in such case the question would make no sense, right?). Lua dissectors can invoke C dissectors and vice versa.

Replacing USB header with a TCP dummy header is not exactly what I had in mind. A dissector normally acts on the actual bytes of a captured frame and from its point of view, these bytes are read-only. But any dissector can create additional bytes of data and ask a higher layer dissector to handle them as if they were part of the captured frame.

So what I’ve recommended was to create the IP and TCP header as a byte array, concatenate to it the payload extracted from the URB, and use the bytearray:tvb function to create a new tvb from it and call the existing IP dissector, giving it your new tvb as a target.

The IP header must be there too because the SSL dissector uses both IP address and port as keys to the table choosing the right dissector for the decrypted payload, and because you have to specify even data (i.e. no dissection, just display of the contents in hexadecimal) explicitly.

Myself I would use IP address to represent the USB host and 10.0.bus.device to represent the USB endpoint, so an URB from host to 2.1.4 would have as IP source and as IP destination, and vice versa. The server side TCP port should be set to a value to which no other dissector of TCP payload is linked by default, something like 33333, and you may link the ssl dissector to that TCP port already in your initialization code:


The client side port should be in the range from 40000 up.

As already written, the TCP header cannot be totally dummy because otherwise the TCP dissector would not invoke the higher layer dissector (in our case, the SSL one). I believe, though, that it is not necessary to simulate the SYN, SYN+ACK, ACK session establishment sequence.

(05 Oct ‘16, 22:29) sindy

One more point, as USB by nature uses distinct data endpoints for in and out directions even if they form up a bi-directional logical channel, the ssl dissector would not even know that the messages to one endpoint and the messages from the other one belong to the same conversation. To let the ssl dissector handle the conversation properly, the fake IP and TCP headers must use the same pair of IP:port tuples, properly oriented as source and destination depending on the URB direction. What my workaround suggestion ignores is that the USB device may theoretically use several pairs of data endpoints and that in such case, the only way to determine which IN endpoint works in tandem with which OUT endpoint would be to analyse the descriptors.

For the record, of course the clean way would be to file an enhancement “bug” asking for the ssl dissector to understand USB conversations directly, without the need to create fake IP and TCP headers, as stated in my first reaction. But that would require some investigation into the issue above, i.e. to verify and describe a method of determination which endpoints form up a bi-directional logical channel.

(07 Oct ‘16, 01:08) sindy
showing 5 of 8 show 3 more comments

One Answer:


For SSL/TLS decryption, a client and server side must be known identified since both sides contribute to the session secret via the nonces in their Hello messages (Client Random and Server Random). This client/server is determined automatically when using UDP/TCP, but for other protocols you (as the parent layer) must provide this information.

On the USB level, data packets go from the host to the device (for an OUT endpoint) or from the device to the host (for an IN endpoint). These endpoint numbers are not necessarily the same and in that case Wireshark sees two separate conversations:

2.1.5 <-> host
2.1.4 <-> host

Thus the SSL dissector is unable to understand that these two data streams are paired. According to the WSLUA documentation, fields like pinfo.src and pinfo.dst are actually writable, so you could put your fake "source" and "destination" addresses inside.

Note that these properties form a "conversation" (see find_or_create_conversation in epan/conversation.c):

  • pinfo.src / pinfo.dst
  • pinfo.port_type (PT_USB (12) in the case of USB)
  • pinfo.src_port / pinfo.dst_port

To ensure that the old, USB-specific conversations are not accidentally matched, chose source/destination addresses that are definitely different or pick any other port type.

The SSL dissector currently does not check the port type, so if you for example have HTTP, you could set a conversation like this (swap roles accordingly):

  • pinfo.src: CLIENT
  • pinfo.dst: SERVER
  • pinfo.port_type: PT_TCP (numeric value is 2, could probably pick any other value)
  • pinfo.src_port: 0 (choice does not matter)
  • pinfo.dst_port: 443

(If you pick port_type 0, be sure to use Wireshark 2.2.1 which fixed an issue that resulted in misdetection of the client/server side.)

If this still does not give the expected result, enable the SSL debug log. For example, if the log shows two different "ssl_session" pointer addresses, then you know that the conversation is messed up.

answered 07 Oct '16, 15:57

Lekensteyn's gravatar image

accept rate: 30%

edited 08 Oct '16, 08:21

Thank you for your comment.

As you told, I should have set pinfo.src_port and pinfo.dst_port to decrypt packets. I could get decrypted packets after that.

thank you again, Lekensteyn

(11 Oct '16, 21:55) yobob

@yobob If your question is answered, consider pressing accepting this answer by pressing the tick on the left. Thanks!

(16 Oct '16, 13:33) Lekensteyn