Wireshark Lua Dissector - How to set source and destination - lua

I'm working on a Wireshark Dissector in Lua.
I try to provide wireshark as much information about my custom protocol as possible to make use of the available analysis tools. Therefore I'm trying to set the correct source and destination address for my protocol.
My protocol can be on top of different other protocols such as UDP or IEEE 802.15.4. So it might even be that the package source/destination is already set (UDP).
However I want wireshark to show my addresses, so I tried the following:
myproto = Proto("myproto"), "My Protocol")
myproto_source = ProtoField.uint16("myproto.src", "Source Address", base.HEX)
myproto.fields = { myproto_source }
function myproto.dissector(buffer, pinfo, tree)
local subtree = tree:add(myproto, buffer(), "My Proto")
subtree:add(myproto_source, buffer(0,2)
-- does not work with error:
-- bad argument #1 to '?' (Address expected, got userdata)
pinfo.src = myproto_source
-- does work, but only adds text, wireshark tools rely on pinfo.src
pinfo.cols.src = tostring(buffer(0,2):uint())
end
udp_table = DissectorTable.get("udp.port")
udp_table:add( 12345, myproto )
wtap_encap_table = DissectorTable.get("wtap_encap")
wtap_encap_table:add(wtap["IEEE802_15_4"], myproto)
So is there maybe a datatype/class "address" that is necessary to set pinfo.src? Or is there a totally different way to set the packet information?
Thanks in advance!

pinfo.src takes an Address object (which is an IP address; not a 16-bit integer). Example usage:
pinfo.src = Address.ip('1.2.3.4')
Note that this only sets the text of the "Source" column shown in Wireshark. The underlying packet info cannot be modified, and the IP packet details will continue to show the actual IP address.

Just a suggestion - I'm not an LUA wiz:
pinfo:col.src = buffer(0,2):uint()
maybe??

Related

How to access TLS Version/ Checksum of packet in Wireshark Lua dissector?

I am new to Wireshark and its Lua API. I need to write a dissector that can capture packets on port 443, modify some of the contents and then send them over to the destination. I found a script here which I have modified according to my needs:
-- 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)
print ('packet captured')
-- validate packet length is adequate, otherwise quit
if buf:len() == 0 then return end
pkt.cols.protocol = p_myproto.name
local colss = pkt.cols
--pkt.cols.info:append(" " .. tostring(pkt.dst).." -> "..tostring(pkt.src))
print ("" .. tostring(pkt.dst))
print ("" .. tostring(pkt.src_port))
print ("" .. tostring(pkt.dst_port))
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(443)
-- you can call dissector from function p_myproto.dissector above
-- so that the previous dissector gets called
tcp_dissector_table:add(443, p_myproto)
I can access fields like dst, src, dst_port etc. The entire list is available here. But I cannot find any reference anywhere as to how I can access/modify the checksum of the packet, the selected cipher suites etc. I know they exist on the transport layer but I could not find any documentation that will allow me to access/modify these values.
What am I doing wrong? Any help in this regard will be appreciated!
Thanks!
You can access any field using a Field Extractor, and the entire list is not available on the LuaAPI/Pinfo wiki page as you referenced, but on the Wireshark Display Filter Reference page.
For example, if you want the TCP checksum, you can use:
fe_tcp_checksum = Field.new("tcp.checksum")
...
function p_myproto.dissector (buf, pkt, root)
...
f_tcp_checksum = fe_tcp_checksum().value
...
end
The Wireshark wiki provides more Lua/Examples.

Wireshark: display filters vs nested dissectors

I have an application that sends JSON objects over AMQP, and I want to inspect the network traffic with Wireshark. The AMQP dissector gives the payload as a series of bytes in the field amqp.payload, but I'd like to extract and filter on specific fields in the JSON object, so I'm trying to write a plugin in Lua for that.
Wireshark already has a dissector for JSON, so I was hoping to piggy-back on that, and not have to deal with JSON parsing myself.
Here is my code:
local amqp_json_p = Proto("amqp_json", "AMQP JSON payload")
local amqp_json_result = ProtoField.string("amqp_json.result", "Result")
amqp_json_p.fields = { amqp_json_result }
register_postdissector(amqp_json_p)
local amqp_payload_f = Field.new("amqp.payload")
local json_dissector = Dissector.get("json")
local json_member_f = Field.new("json.member")
local json_string_f = Field.new("json.value.string")
function amqp_json_p.dissector(tvb, pinfo, tree)
local amqp_payload = amqp_payload_f()
if amqp_payload then
local payload_tvbrange = amqp_payload.range
if payload_tvbrange:range(0,1):string() == "{" then
json_dissector(payload_tvbrange:tvb(), pinfo, tree)
-- So far so good. Let's look at what the JSON dissector came up with.
local members = { json_member_f() }
local strings = { json_string_f() }
local subtree = tree:add(amqp_json_p)
for k, member in pairs(members) do
if member.display == 'result' then
for _, s in ipairs(strings) do
-- Find the string value inside this member
if not (s < member) and (s <= member) then
subtree:add(amqp_json_result, s.range)
break
end
end
end
end
end
end
end
(To start with, I'm just looking at the result field, and the payload I'm testing with is {"result":"ok"}.)
It gets me halfway there. The following shows up in the packet dissection, whereas without my plugin I only get the AMQP section:
Advanced Message Queueing Protocol
Type: Content body (3)
Channel: 1
Length: 15
Payload: 7b22726573756c74223a226f6b227d
JavaScript Object Notation
Object
Member Key: result
String value: ok
Key: result
AMQP JSON payload
Result: "ok"
Now I want to be able to use these new fields as display filters, and also to add them as columns in Wireshark. The following work for both:
json (shows up as Yes when added as a column)
json.value.string (I can also filter with json.value.string == "ok")
amqp_json
But amqp_json.result doesn't work: if I use it as a display filter, Wireshark doesn't show any packets, and if I use it as a column, the column is empty.
Why does it behave differently for json.value.string and amqp_json.result? And how can I achieve what I want? (It seems like I do need a custom dissector, as with json.value.string I can only filter on any member having a certain value, not necessarily result.)
I found a thread on the wireshark-dev mailing list ("Lua post-dissector not getting field values", 2009-09-17, 2009-09-22, 2009-09-23), that points to the interesting_hfids hash table, but it seems like the code has changed a lot since then.
If you'd like to try this, here is my PCAP file, base64-encoded, containing a single packet:
1MOyoQIABAAAAAAAAAAAAAAABAAAAAAAjBi1WfYOCgBjAAAAYwAAAB4AAABgBMEqADcGQA
AAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAB/tcWKO232y46mkSqgBgxtgA/AAAB
AQgKRjDNvkYwzb4DAAEAAAAPeyJyZXN1bHQiOiJvayJ9zg==
Decode with base64 -d (on Linux) or base64 -D (on OSX).
It turns out I shouldn't have tried to compare the display property of the json.member field. Sometimes it gets set by the JSON dissector, and sometimes it just stays as Member.
The proper solution would involve checking the value of the json.key field, but since the key I'm looking for presumably would never get escaped, I can get away with looking for the string literal in the range property of the member field.
So instead of:
if member.display == 'result' then
I have:
if member.range:range(1, 6):string() == 'result' then
and now both filtering and columns work.

How to get wireshark heuristic dissector work?

I'm writting a lua script as wireshark(1.12.4) plugin to dissect my private protocols,I can get it work as normal dissector,which binding a certain port(such as 80) to DissectorTable "tcp.port".The pseudo-code as follows:
local my_pro = Proto("MyPro","My Protocol")
local my_pro_field_1 = ProtoField.uint16("MyPro.filed_1","Field 1",base.HEX)
local my_pro_field_2 = ProtoField.uint16("MyPro.filed_2","Field 2",base.HEX)
my_pro.fields = {my_pro_field_1,my_pro_field_2}
local data_dis = Dissector.get("data")
function my_pro.dissector(buf,pkt,root)
if (buf(0,2):uint() ~= 1 or buf(2,2):uint() ~= 1) then
data_dis:call(buf,pkt,root)
return false
end
pkt.cols.protocol = "My Protocol"
local tree = root:add(my_pro,buf(0,buf:len()))
tree:add_le(my_pro_field_1,buf(0,2))
tree:add_le(my_pro_field_2,buf(2,2))
return true
end
local tcp_encap_table = DissectorTable.get("tcp.port")
tcp_encap_table:add(80,my_pro)
The problem is:
What if My protocol is not running on a certain port,as I don't want to modify the port above every time,I actually want the dissector to be wise enough to dynamically identify some kind of pattern and do the right dissecting then.
I've searched out there's a so called "heuristic" dissector,I add codes below to test but I could't get it work.
local function my_heur_dissector(buf,pkt,root)
local ret = my_pro.dissector(buf,pkt,root)
if (not ret) then
return false
end
pkt.conversation = my_pro
return true
end
my_pro:register_heuristic("tcp",my_heur_dissector)
When I change the port,the packets're not parsed as my protocol,so I have to use "Decode as" menu.
So,how can I get the heuristic dissector work base on my code?Have I missed something?
BTW,the answer with code is appreciated.
Sadly, if you need a heuristic dissector (HD) it cannot be done in a plugin manner, and you need to write a new HD.
https://github.com/wireshark/wireshark/blob/master/doc/README.heuristic
(Yes, it has been over 2 years, but if some future-googler finds it...)

How can I get a wireshark Lua dissector protocol preferences to save and persist when I close wireshark?

So I have written what I can only refer to as an Awesome dissector. It doesn't do much, yet it boosts my work efficiency greatly.
My only problem is that I exposed a few preferences, and they won't stick through wireshark close/start.
I.E. :
Prerequisite : Lua script must be in plugins dir...
Open wireshark, Edit > Preferences > Protocol > http.queryparameters...
Set Param1 Value to "aaa", click OK. (It will affect dissection properly.)
Close wireshark, Start again, the value is again something else.
My dissector :
-- Written by Eitam Doodai
-- trivial postdissector example
-- declare some Fields to be read
full_uri_from_request = Field.new("http.request.full_uri")
-- declare our (pseudo) protocol
http_query_params_proto = Proto("http.query_parameters","HTTP Query Parameters Postdissector")
-- create the fields for our "protocol"
query_param1 = ProtoField.string("http.query_parameters.param1","PARAM1")
query_param2 = ProtoField.string("http.query_parameters.param2","PARAM2")
query_param3 = ProtoField.string("http.query_parameters.param3","PARAM3")
-- add the field to the protocol
http_query_params_proto.fields = {query_param1}
http_query_params_proto.fields = {query_param2}
http_query_params_proto.fields = {query_param3}
-- Add prefs
local p1 = http_query_params_proto.prefs
p1.value1 = Pref.string ("Param1 Value", "123", "Param key to extract")
p1.value2 = Pref.string ("Param2 Value", "456", "Param key to extract")
p1.value3 = Pref.string ("Param3 Value", "789", "Param key to extract")
-- create a function to "postdissect" each frame
function http_query_params_proto.dissector(buffer,pinfo,tree)
-- obtain the current values the protocol fields
local full_uri_value = full_uri_from_request()
if full_uri_value then
local value = tostring(full_uri_value)
local subtree = tree:add(http_query_params_proto,"Query Param1")
local subtree = tree:add(http_query_params_proto,"Query Param2")
local subtree = tree:add(http_query_params_proto,"Query Param3")
_, _, query_param1_str = string.find(value,p1.value1 .. "=([^&]+)")
_, _, query_param2_str = string.find(value,p1.value2 .. "=([^&]+)")
_, _, query_param3_str = string.find(value,p1.value3 .. "=([^&]+)")
if query_param1_str then
subtree:add(query_param1,query_param1_str)
end
if query_param2_str then
subtree:add(query_param2,query_param2_str)
end
if query_param3_str then
subtree:add(query_param3,query_param3_str)
end
end
end
-- register our protocol as a postdissector
register_postdissector(http_query_params_proto)
If you have a console open and start wireshark from the command line, after you change one of your http.query_parameters.param settings, save it and close wireshark, and restart it, you'll see something like:
...preferences line 1829: No such preference "http.query_parameters.value2" (applying your preferences once should remove this warning)
And that's a problem: wireshark prints that out for preferences it finds in the saved preference file that it doesn't understand/know-about.
Edit: do NOT open a bug about this. The problem is you used a Protocol name that already exists with preferences: "http". In other words, since you're basically naming the preferences http.query..., wireshark thinks it should belong to the http protocol module, but the real http module doesn't know anything about it, so wireshark prints that error the next time it tries reading from the preferences file.
Long story short: change the name of your Proto and fields and so on, to not collide with a real protocol name.

Wireshark Dissector in Lua

First of all, I'm new to Lua altogether, and this is my first attempt at writing a wireshark dissector.
My protocol is straightforward - a 2 byte length field, followed by a string of that length.
When I run the code through the Lua console, everything works as expected.
When the code is added to the Wireshark plugins directory, I get the error
Lua Error: [string "C:\Users...\AppData\Roaming\Wireshark..."]:15: calling 'add' on bad self (number expected, got string)
Line 15 corresponds is the t:add(f_text... line.
Can anyone explain the discrepancy between the execution methods?
do
local p_multi = Proto("aggregator","Aggregator");
local f_len = ProtoField.int16("aggregator.length","Length",base.DEC)
local f_text = ProtoField.string("aggregator.text","Text")
p_multi.fields = { f_len, f_text }
local data_dis = Dissector.get("data")
function p_multi.dissector(buf,pkt,root)
pkt.cols.protocol = "Aggregator"
local len = buf(0,2):int()
local t = root:add(p_multi,buf(0,len+2))
t:add(f_len,buf(0,2),"Length: " .. buf(0,2):int())
t:add(f_text,buf(2,len),"Text: " .. buf(2,len):string())
end
local tcp_encap_table = DissectorTable.get("tcp.port")
tcp_encap_table:add(4321,p_multi)
end
Your dissector code is very close to correct, but you're doing extra work that the interface won't accept. If you change your dissector function like so,
function p_multi.dissector(buf,pkt,root)
pkt.cols.protocol = "Aggregator"
local len = buf(0,2):int()
local t = root:add(p_multi,buf(0,len+2))
t:add(f_len,buf(0,2)) --let Wireshark do the hard work
t:add(f_text,buf(2,len)) --you've already defined their labels etc.
end
you'll get the desired behavior. The labels "Text" and "Length" are already defined for your fields, so there is no need to provide them again on lines 15 and 16.

Resources