Dev @ Work

take care

Create a Wireshark dissector in Lua

with 29 comments


You have a custom protocol over TCP and would like to give your users the ability to visualize it in Wireshark? This post is for you. To create your dissector I recommend Wireshark’s Lua API and the embedded Lua interpreter. It is the easiest way to prototype dissectors, which for performance reasons may later be rewritten in C. At the time of writing I am still using Wireshark 1.2.1, but you might consider using the latest version.

Let us begin with some sample code.

Protocol dissector script in Lua

We use a chained dissector, it adds functionality to dissect packets of an existing protocol, such as packets destined to a particular tcp port. It receives only the payload part of the original protocol packet as the input buffer in the dissector function.

-- create myproto protocol and its fields
p_myproto = Proto ("myproto","My Protocol")
local f_command = ProtoField.uint16("myproto.command", "Command", base.HEX)
local f_data = ProtoField.string("myproto.data", "Data", FT_STRING)

p_myproto.fields = {f_command}

-- myproto dissector function
function p_myproto.dissector (buf, pkt, root)
  -- validate packet length is adequate, otherwise quit
  if buf:len() == 0 then return end
  pkt.cols.protocol = p_myproto.name

  -- create subtree for myproto
  subtree = root:add(p_myproto, buf(0))
  -- add protocol fields to subtree
  subtree:add(f_command, buf(0,2)):append_text(" [Command text]")

  -- description of payload
  subtree:append_text(", Command details here or in the tree below")
end

-- Initialization routine
function p_myproto.init()
end

-- register a chained dissector for port 8002
local tcp_dissector_table = DissectorTable.get("tcp.port")
dissector = tcp_dissector_table:get_dissector(8002)
  -- you can call dissector from function p_myproto.dissector above
  -- so that the previous dissector gets called
tcp_dissector_table:add(8002, p_myproto)

Running the Lua script in Wireshark

Here are the steps required to get the above code running. If your Wireshark version is 1.4 or better, skip step 3.

  1. Save the lua script above to any folder (e.g. c:\myproto) and call the file myproto.lua
  2. Open init.lua in the Wireshark installation directory for editing. You will need Admin privileges on Windows Vista and 7.
  3. Comment out the following line in init.lua (single line comments begin with --):
    disable_lua = true; do return end;
  4. Add the following lines to init.lua (at the very end):
    MYPROTO_SCRIPT_PATH="C:\\myproto\\"
    dofile(MYPROTO_SCRIPT_PATH.."myproto.lua")
  5. Change MYPROTO_SCRIPT_PATH to point to the folder where you saved the script in step 1
  6. Run Wireshark
  7. Load a capture file that has the packets of your custom protocol or start a live capture

Here’s a figure that shows the protocol dissector in action.

About these ads

Written by Devendra

September 27, 2010 at 3:43 pm

Posted in Lua, Wireshark

29 Responses

Subscribe to comments with RSS.

  1. Hello, I am using ubuntu 11.10

    I followed your method along with if 0 and running_superuser then
    local disabled_lib = {}
    to make Lua work its still throwing out dofile disabled error.

    i am using 1.6.2 version

    ravi@ingram.in

    December 30, 2011 at 11:12 pm

    • Hi, please try

      if false and running_superuser then
          local disabled_lib = {}
      ...
      

      Devendra

      January 2, 2012 at 2:28 pm

  2. Hello,
    I am trying to isolate a custom protocol that comes in the data part of udp using Lua scripts in Wireshark. How can i recognize these with flag values of the custom headers that come sequncially after udp headers in udp’s data.
    Any Idea where there is a proper list of comands pertaining to wireshark-lua script writing.
    A big Thanx in Advance.

    I am using latest wireshark version.

    Edwin Abraham

    Edwin Abraham

    June 13, 2012 at 2:06 pm

    • Writing a dissector for UDP is very much like writing a dissector for TCP. You can register to dissect UDP packets with a particular port as follows

      local udp_dissector_table = DissectorTable.get("udp.port")
      dissector = udp_dissector_table:get_dissector(8002)
        -- you can call dissector from function p_myproto.dissector above
        -- so that the previous dissector gets called
      udp_dissector_table:add(8002, p_myproto)
      

      For help on Wireshark’s LUA API please refer to http://www.wireshark.org/docs/wsug_html_chunked/wsluarm.html. For Lua related information see the manual at http://www.lua.org/manual/5.1/manual.html.

      Devendra

      June 13, 2012 at 2:33 pm

      • Okay suppose I did this. How does Wireshark know that this is my custom protocol. Like where is the filter option there? Lets say I can check that this is my custom protocol with a flag. Anyway of getting the data part of udp and then compare it?
        and is there a way to tell wireshark to look at all my udp ports not just a specific one?

        Edwin Abraham

        June 14, 2012 at 12:35 am

      • Q. Okay suppose I did this. How does Wireshark know that this is my custom protocol.

        A. You create a new Proto object, that is how it knows.

        Q. Like where is the filter option there? Lets say I can check that this is my custom protocol with a flag.

        A. You specify the fields by setting the fields property of your Proto object. You can add fields dynamically from the dissector function of your Proto object by using the root parameter. Wireshark cannot filter based on those fields though. You don’t need any additional flags, you can filter packets based on the procotol name to begin with.

        Q. Anyway of getting the data part of udp and then compare it?

        A. You can use the buf object, a parameter of the dissector function, to get the data and do whatever you want with it.

        Q. …and is there a way to tell wireshark to look at all my udp ports not just a specific one?

        A. You can register your protocol dissector against as many ports as you wish. Just repeat the following several times with different port numbers

        dissector = udp_dissector_table:get_dissector(8002)
        udp_dissector_table:add(8002, p_myproto)
        

        Devendra

        June 14, 2012 at 8:46 am

  3. Thanx for the info firstly. One last question.

    The protocol I have to recognize is a udp packet where the data part of udp will act as headers for the rest of the data in the packet. Its a completely new packet and only way to Identify whether the udp that comes is of that custom protocol is a field that is 12th (unsigned long) from the udp headers. Now I defined all the names of the headers with uint32. But it still doesn’t understand that its myproto. I feel its because I haven’t asked it to recognize that. Now the only way it will recognize is by comparing the 12th uint32 data with some value.

    I understood the part of the udp ports , the protocol creation, but from the udp packet how will it know its my packet. For that what do I do? You said with the name of the protocol. But from where the packet?

    Edwin Abraham

    June 14, 2012 at 2:20 pm

    • You can do that with something like the following in the dissector function

      if buf(11):uint() == val then
      
        -- dissect
      
      else
        -- call the previous dissector and quit
        dissector:call(buf, pkt, root)
        return
      end
      

      Devendra

      June 14, 2012 at 2:44 pm

  4. That should fix the problem. Thanx a bunch.

    Edwin Abraham

    June 15, 2012 at 12:00 am

  5. [...] If you are not familiar with writing dissectors for Wireshark in Lua I recommend reading this post on that topic [...]

  6. Hello!
    Thanks you for yours tutor. I have a problem with my dissector, and i need yours help. After running LUA script, I want to count total packets that appear in myproto. So, i dont know how to do :|. Can u help me,pls?.
    Sorry my english is not good
    Thank

    toi_la_toi

    July 23, 2012 at 6:58 am

    • Hello! The dissector function is called once for each packet. You can maintain a global counter (defined outside the function) and increment it each time the dissector function is called, e.g.

      local count = 0
      ...
      function p_myproto.dissector (buf, pkt, root)
      ...
        count = count + 1
      ...
      end
      

      Devendra

      July 23, 2012 at 9:08 am

  7. Hi,
    I see the following error thrown while the Wireshark GUI loads:
    Lua: Error during loading:
    C:\Program Files\Wireshark\myproto.lua:1: unexpected symbol near ‘{‘

    I have copied the script as is and placed “myproto.lua” in folder where “init.lua” is located (c:\Program Files\Wireshark )and added

    dofile(“myproto.lua”) at the end .

    Request to please help solve the issue

    Santosh

    September 25, 2012 at 9:19 am

    • Hi Santosh. The code as posted should work. Check that you didn’t add any extra characters into the script by mistake. Please tell more about your environment – OS version, Wireshark version etc.

      Devendra

      September 25, 2012 at 9:26 am

      • Devendra,
        Thanks I actually posted it on a rtf file that had extra charecters appended before the actual script. I used notepad and its fine now and working.

        Thanks for the post as it is tailor made for my use.

        Wanted to know are there ways to convert the hex data in the payload and display it as a decimal value when we expand the subtree for the custom protocol.

        Ex. Subtree lists “Squence Number: 3886″ , for the value 0f2e in the payload.

        I use wireshark version 1.8.0 on Windows XP

        Thanks.

        Santosh

        September 26, 2012 at 2:43 am

      • Hi Santosh. The buf parameter of the dissector function is of type Tvb. You can obtain a TvbRange by doing something like buf(offset, 2). TvbRange has methods that return integer and other values. For your case you can use something like buf(offset, 2):uint(). Remember to change offset to the position in the buffer you want to read your value from. If the byte order of the data is little endian you can use le_uint. Follow the Wireshark Lua API link above for further details.

        Devendra

        September 26, 2012 at 5:03 am

  8. Thanks Devendra.
    I was able to get my requirement of the previous post however, facing the issue while adding new protocol fields.

    only buf(x,x) ; where x=0,1,2,3,4 are accepted

    i.e, for Ex.If I attempt subtree:add(f_command, buf(4,5)) or subtree:add(f_command, buf(5,5)),

    It fails with error thrown as, [Dissector bug, protocol KODRTPOTCP: proto.c:1115: failed assertion "DISSECTOR_ASSERT_NOT_REACHED"].

    Can you please let me know what could be the problem.

    Thanks.

    Santosh

    September 26, 2012 at 8:41 am

    • You are most certainly exceeding the bounds of the buffer. You should create a TvbRange like buf(offset, length). The second parameter is the length of the field, not the end index/offset.

      Devendra

      September 26, 2012 at 8:47 am

      • So we can confirm the Bounds of the buffer is been configured to read till 16bits? Is this a default value?

        Santosh

        September 26, 2012 at 9:35 am

      • It is intelligent enough to determine that the range has just 2 bytes (16 bits) and create an integer value from that. I hope that answers your question. If not, I don’t understand your question.

        Devendra

        September 26, 2012 at 9:49 am

  9. Yes it’s obvious. Missed it. Thanks.

    Also,
    I plan to use control structure (if/else) and depending upon the value of payload data decoded, append text to the subtree, but I am facing issue in the same.

    i.e,
    local f_cmd = ProtoField.uint32(“Koproto.cmd”, “Version”,base.DEC)

    The above command displays the Version in subtree (as 2) correctly but when I use it in if/else statement, it’s not able to resolve, i.e

    if f_cmd == 2 then
    subtree:add(f_cmd, buf(1,1)):append_text(” Version is 2″)
    else
    subtree:add(f_cmd, buf(1,1)):append_text(” Version is not 2″)
    end.

    This Is failing.

    Unfortunately cannot print the value of “f_cmd” to verify what it holds actually.

    Can you please let me know what could be the issue?

    Thanks.

    Santosh

    September 27, 2012 at 3:46 am

    • f_cmd is like a template, not the actual field. You can read the value directly from buf as TvbRange and using one of its methods, then use that value in the if statement.

      Devendra

      September 27, 2012 at 8:54 am

  10. Hi,
    Thanks for your reply.
    I face following error when I tried working with bitstring:

    Lua: Error during loading:
    error loading module ‘bitstring’ from file ‘C:\Program Files\Wireshark\bitstring.dll’:
    %1 is not a valid Win32 application.

    Can I know what could be the reason for the same?

    Followed following steps:
    1. Copy ‘bitstring.dll’ to your wireshark directory. This file provides ‘bitstring’ library for Lua.
    2. Copy ‘coap.lua’ to somewhere in your wireshark directory. For example, /plugins/coap/coap.lua.
    3. Open ‘init.lua’ in your wireshark root directory. Comment the line ‘disable_lua = true’ or change it to ‘disable_lua = false’.
    4. Add ‘dofile(“/plugins/coap/coap.lua”)’ at the end of the file(init.lua)

    Santosh

    September 27, 2012 at 12:32 pm

  11. Hi Devendra,
    I want to check total length of the buffer (Valid number of bytes to decode). How can I do it?

    GK

    April 17, 2013 at 6:11 am

    • Hi GK. Try buf:len().

      Devendra

      April 17, 2013 at 9:20 am

  12. [...] you are not familiar with writing dissectors for Wireshark in Lua I recommend reading this post [...]

  13. […] function still needs. If you are not familiar with writing dissectors for Wireshark in Lua, read this post […]

  14. I made a slight change to associate the dissector with port 80 because I have a test pcap with that traffic. At the bottom of the page in the screenshot shows a filterable field called myproto.command that links to 0x ebff. When I run this script it parses out the bytes but my bytes (2 bytes from traffic) show up as text. If this data is text then I cannot filter or use tshark command. Can you shed some light on this matter? I have tried a lot of different things and cannot get it to work:( Also, I am evaluating the lua script directly in wireshark via the evaluate option and then I refresh my test pcap.

    david

    November 4, 2013 at 12:43 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 51 other followers

%d bloggers like this: