A Wireshark Lua Dissector for Fixed Field Length Protocols

Published: 2024-06-03
Last Updated: 2024-06-04 19:17:34 UTC
by Didier Stevens (Version: 1)
0 comment(s)

I developed a Wireshark dissector in Lua to parse binary protocols (over TCP) that are composed of fields with fixed lengths. I got this idea while taking a SANS ICS training: for protocol reversing, it would be useful to have a dissector where I can configure the fields (length, type, name, ...).

As an example, I'm using a packet capture of a demo protocol for firmware upload (didactic).

The format of the protocol data unit (PDU) looks like this:

  • Byte 1: the function of the PDU (0x10 start upload, 0x11 upload, 0x12 end upload)
  • Byte 2: the direction (0 from client to server, 1 from server to client)
  • Byte 3 and 4: a PDU counter for uploads, it's a little-endian integer
  • Byte 5 and 6: the length of the uploaded data, it's a little-endian integer
  • Bytes 7 and following: the uploaded data

Command-line arguments are provided to configure the Lua dissector to parse this traffic:

"c:\Program Files\Wireshark\Wireshark.exe" -X lua_script:fl-dissector.lua -X lua_script1:port:50500 -X lua_script1:protocolname:firmware -X lua_script1:fieldlengths:1:B,1:B,2:L,2:L -X lua_script1:fieldnames:Function,Direction,Counter,DataLength,Data capture-firmware-upload.pcapng

"-X lua_script:fl-dissector.lua" loads dissector fl-dissector.lua in Wireshark.

"-X lua_script1:port:50500" provides a port:50500 option value to the dissector. This specifies the TCP port (50500) of the traffic that should be dissected.

"-X lua_script1:protocolname:firmware" specifies the name of the protocol.

"-X lua_script1:fieldlengths:1:B,1:B,2:L,2:L" specifies the field lengths: 1 byte, 1 byte, 2 bytes and 2 bytes. The 2 bytes fields are little-endian integers (:L).

"-X lua_script1:fieldnames:Function,Direction,Counter,DataLength,Data" specifies the names of the fields.

Configured like this, the protocol "firmware" is added to Wireshark and used for dissecting traffic over TCP port 50500:

Once the dissector is defined, it can be used to filter traffic. For example, in the above screenshot, I use display filter "firmware" to limit the view to this firmware protocol.

I can even use tshark to extract the uploaded firmware. For this, I switch to tshark:

"c:\Program Files\Wireshark\tshark.exe" -X lua_script:fl-dissector.lua -X lua_script1:protocolname:firmware -X lua_script1:port:50500 -X lua_script1:fieldlengths:1,1,2,2 -X lua_script1:fieldnames:Function,Direction,Counter,DataLength,Data -r capture-firmware-upload.pcapng -Y "(firmware.Function == 0x11) && (firmware.Direction == 0)" -e firmware.Data -Tfields

The arguments for the dissector are the same. I use a display filter (-Y "(firmware.Function == 0x11) && (firmware.Direction == 0)") to filter for PDUs that upload the firmware (function == 0x11) to the server (direction == 0). I configure tshark to just output the value of field data as hexadecimal (-e firmware.Data -Tfields). This is the result:

Next, I convert this hexadecimal data to binary with my tool hex-to-bin.py, and use another tool (file-magic.py) to try to identify the uploaded data:

It is a ZIP file, this can be confirmed with my zipdump.py tool:

I created this packet capture file of a firmware upload to an IoT device for didactic purposes, e.g., to explain a process of reverse engineering a binary network protocol.

If you want to know more about this, take a look at my blog post "Reversing A Network Protocol" and YouTube video "Reversing A Network Protocol".

YouTube Video

Didier Stevens
Senior handler

0 comment(s)
ISC Stormcast For Monday, June 3rd, 2024 https://isc.sans.edu/podcastdetail/9006


Diary Archives