Skip to content

Instantly share code, notes, and snippets.

@tmori3y2
Last active February 23, 2020 11:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmori3y2/ee8bafd0fcd18818378f8901d243cf9a to your computer and use it in GitHub Desktop.
Save tmori3y2/ee8bafd0fcd18818378f8901d243cf9a to your computer and use it in GitHub Desktop.
Wireshark Lua Sample

Wireshark Lua Sample

MyNBNS

What's NBNS ?

  • NBNS: NetBIOS Name Service
  • UDP port 137
  • The NBNS dissector is none "heuristic" one.

What's MyNBNS ?

  • This dissector creates the alternative protocol tree under the original one if the specific device vendor. (ex: Sony Mobile)
  • This dissector is developed as the "heuristic" and "chain" one for leaning LuaAPI.
  • The "heuristic" dissector is not called after none "heuristic" one (= original one).
  • Remove the original dissector from the "udp.port" dissector table and call it from this "heuristic" dissector.

How this dissector works ?

  • Get "udp.port" dissector table.
  • Get the original dissector from the dissector table.
  • Back up the original dissector.
  • Remove the original dissector from the dissector table.
  • Register this as the "heuristic" dissector.
  • If NBNS packet, call this dissector.
  • If the original exists, call the original dissector.
  • If OUI resolved address contains "SonyMobi", create the alternative protocol tree.
local my_pattrib = {
abbr = "my_nbns",
description = "My NetBIOS Name Service",
protocol = "NBNS/MyNBNS",
header_size = 12,
base_protocol = "udp",
dissector_table_name = "port",
port = 137,
vendor = "SonyMobi"
}
local function make_filter_name(protocol_prefix, field_name)
return protocol_prefix.."."..field_name
end
local my_proto = Proto(my_pattrib.abbr, my_pattrib.description)
my_proto.fields = {}
local flags_responses = {
[0] = "Message is a query",
[1] = "Message is a response"
}
local flags_opcodes = {
[0x0] = "Name query"
}
local flags_authoritatives= {
[1] = "Server is an authority for domain"
}
local flags_truncated = {
[0] = "Message is not truncated"
}
local flags_recursionDesired = {
[0] = "Don't do query recursively",
[1] = "Do query recursively"
}
local flags_recursionAvailable = {
[0] = "Server can't do recursive queries",
[1] = "Server can do recursive queries"
}
local flags_broadcast = {
[0] = "Not a broadcast packet",
[1] = "Broadcast packet"
}
local falags_replyCode = {
[0x0] = "No error",
[0x3] = "Requested name does not exist"
}
local my_proto_flags = {
-- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr])
-- treeitem:add([protofield], [tvbrange] = buffer(offset, size), [value], [label])
{name = "Response", abbr = "flags_response", type = ftypes.UINT16, offset = 15, size = 1, base = base.HEX, valuestring = flags_responses, mask = 0x8000},
{name = "Opcode", abbr = "flags_opcode", type = ftypes.UINT16, offset = 14, size = 4, base = base.HEX, valuestring = flags_opcodes, mask = 0x7800},
{name = "Authoritative", abbr = "flags_authoritative", type = ftypes.UINT16, offset = 10, size = 1, base = base.HEX, valuestring = flags_authoritatives, mask = 0x0400},
{name = "Truncated", abbr = "flags_truncated", type = ftypes.UINT16, offset = 9, size = 1, base = base.HEX, valuestring = flags_truncated, mask = 0x0200},
{name = "Recursion desired", abbr = "flags_recursionDesired",type = ftypes.UINT16, offset = 8, size = 1, base = base.HEX, valuestring = flags_recursionDesired, mask = 0x0100},
{name = "Recursion available", abbr = "flags_recursionAvailable",type = ftypes.UINT16, offset = 7, size = 1, base = base.HEX, valuestring = flags_recursionAvailable, mask = 0x0080},
{name = "Broadcast", abbr = "flags_broadcast", type = ftypes.UINT16, offset = 4, size = 1, base = base.HEX, valuestring = flags_broadcast, mask = 0x0010},
{name = "Reply code", abbr = "flags_replyCode", type = ftypes.UINT16, offset = 3, size = 4, base = base.HEX, valuestring = falags_replyCode, mask = 0x000F}
}
local my_proto_fields = {
-- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr])
-- treeitem:add([protofield], [tvbrange] = buffer(offset, size), [value], [label])
{name = "Transaction ID", abbr = "transaction_id", type = ftypes.UINT16, offset = 0, size = 2, base = base.HEX},
{name = "Flags", abbr = "flags", type = ftypes.UINT16, offset = 2, size = 2, base = base.HEX, flags = my_proto_flags},
{name = "Questions", abbr = "questions", type = ftypes.UINT16, offset = 4, size = 2, base = base.DEC},
{name = "Answer RRs", abbr = "answer_rrs", type = ftypes.UINT16, offset = 6, size = 2, base = base.DEC},
{name = "Authority RRs", abbr = "authority_rrs", type = ftypes.UINT16, offset = 8, size = 2, base = base.DEC},
{name = "Additional RRs", abbr = "additional_rrs", type = ftypes.UINT16, offset = 10, size = 2, base = base.DEC}
}
for index, fattrib in pairs(my_proto_fields) do
-- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr])
my_proto.fields[fattrib.abbr] = ProtoField.new(fattrib.name, my_pattrib.abbr.."."..fattrib.abbr, fattrib.type, fattrib.valuestring, fattrib.base, fattrib.mask)
if fattrib.flags ~= nil then
for index2, fattrib2 in pairs(fattrib.flags) do
-- ProtoField.new(name, abbr, type, [valuestring], [base], [mask], [descr])
my_proto.fields[fattrib2.abbr] = ProtoField.new(fattrib2.name, my_pattrib.abbr.."."..fattrib2.abbr, fattrib2.type, fattrib2.valuestring, fattrib2.base, fattrib2.mask)
end
end
end
-- nil after load other capture files if local.
original_proto_dissector = nil
local function heuristic_checker(buffer, pinfo, tree)
-- guard for port
if (pinfo.src_port ~= my_pattrib.port) and (pinfo.dst_port ~= my_pattrib.port) then
return false
end
-- guard for length
length = buffer:len()
if length < my_pattrib.header_size then
return false
end
-- call original dissector.
-- nil afetr "Reload lua plugins"
if original_proto_dissector ~= nil then
original_proto_dissector:call(buffer, pinfo, tree)
end
-- guard for vendor
local vendor_src = tostring(pinfo.dl_src)
local vendor_dst = tostring(pinfo.dl_dst)
if (vendor_src:find(my_pattrib.vendor) ~= 1) and (vendor_dst:find(my_pattrib.vendor) ~= 1) then
return false
end
-- both original and this dissector share same buffer, then call this dissector and seek buffer.
my_proto.dissector(buffer, pinfo, tree)
return true
end
function my_proto.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = my_pattrib.protocol
local subtree = tree:add(my_proto, buffer(), my_pattrib.description)
for index, fattrib in pairs(my_proto_fields) do
-- treeitem:add([protofield], [tvbrange] = buffer(offset, size), [value], [label])
local tvbrange = buffer(fattrib.offset, fattrib.size)
local item = subtree:add(my_proto.fields[fattrib.abbr], tvbrange)
if fattrib.flags ~= nil then
for index2, fattrib2 in pairs(fattrib.flags) do
-- treeitem:add([protofield], [tvbrange] = buffer(offset, size), [value], [label])
item:add(my_proto.fields[fattrib2.abbr], tvbrange)
end
end
end
return
end
-- register as "heuristic" dissector
my_proto:register_heuristic(my_pattrib.base_protocol, heuristic_checker)
function my_proto.init()
dissector_table_name = make_filter_name(my_pattrib.base_protocol, my_pattrib.dissector_table_name)
local dissector_table = DissectorTable.get(dissector_table_name)
if (dissector_table == nil) then
return
end
-- chain dissector
if original_proto_dissector == nil then
original_proto_dissector = dissector_table:get_dissector(my_pattrib.port)
-- nil afetr "Reload lua plugins"
if original_proto_dissector ~= nil then
-- remove the original dissector so that the "heuristic" dissector can be called
-- even if "Try heuristic sub-dissectors first" preference disabled.
dissector_table:remove(my_pattrib.port, original_proto_dissector)
end
end
end
@tmori3y2
Copy link
Author

My NBNS is developed as the "heuristic" and "chain" one for leaning LuaAPI.
Filtering by device vendor; Alternative protocol tree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment