156 lines
5.2 KiB
Lua
156 lines
5.2 KiB
Lua
msgpack=require("e3pf-mp")
|
|
|
|
epf_protocol = Proto("e3pf", "e3team Protocol Framework")
|
|
|
|
packet_length = ProtoField.uint64("e3pf.packet_length", "Packet Length", base.DEC)
|
|
packet_id = ProtoField.uint8("e3pf.packet_id", "Packet ID", base.DEC)
|
|
|
|
-- Message: ClientHello
|
|
ch_protocol_version = ProtoField.uint32("e3pf.client_hello.protocol_version", "Protocol Version", base.DEC)
|
|
ch_client_random = ProtoField.string("e3pf.client_hello.client_random", "Client Random")
|
|
-- Client certificate: is a subtree
|
|
ch_client_x25519 = ProtoField.string("e3pf.client_hello.client_x25519", "Client X25519 Public Key")
|
|
|
|
-- Message: ServerHello
|
|
sh_protocol_version = ProtoField.uint32("e3pf.server_hello.protocol_version", "Protocol Version", base.DEC)
|
|
-- Server Certificate: is a subtree
|
|
sh_server_random = ProtoField.string("e3pf.server_hello.server_random", "Server Random")
|
|
sh_server_x25519 = ProtoField.string("e3pf.server_hello.server_x25519", "Server X25519 Public Key")
|
|
|
|
-- Struct: Certificate
|
|
-- Details: is a subtree
|
|
c_fingerprint = ProtoField.string("e3pf.certificate.fingerprint", "Fingerprint")
|
|
c_signature = ProtoField.string("e3pf.certificate.signature", "Signature")
|
|
|
|
-- Struct: Certificate.Details
|
|
c_d_name = ProtoField.string("e3pf.certificate.details.name", "Name")
|
|
c_d_not_before = ProtoField.string("e3pf.certificate.details.not_before", "Not Before")
|
|
c_d_not_after = ProtoField.string("e3pf.certificate.details.not_after", "Not After")
|
|
c_d_public_key = ProtoField.string("e3pf.certificate.details.public_key", "Public Key")
|
|
c_d_issuer_public_key = ProtoField.string("e3pf.certificate.details.issuer_public_key", "Issuer Public Key")
|
|
-- TODO: Claims
|
|
|
|
epf_protocol.fields = { packet_length, packet_id, ch_protocol_version, ch_client_random, ch_client_x25519, c_fingerprint, c_signature, c_d_name, c_d_not_before, c_d_not_after, c_d_public_key, c_d_issuer_public_key, sh_protocol_version, sh_server_random, sh_server_x25519 }
|
|
|
|
function dump(o)
|
|
if type(o) == 'table' then
|
|
local s = '{ '
|
|
for k,v in pairs(o) do
|
|
if type(k) ~= 'number' then k = '"'..k..'"' end
|
|
s = s .. '['..k..'] = ' .. dump(v) .. ','
|
|
end
|
|
return s .. '} '
|
|
else
|
|
return tostring(o)
|
|
end
|
|
end
|
|
|
|
function id_to_name(id)
|
|
if id == 1 then return "ClientHello"
|
|
elseif id == 2 then return "ServerHello"
|
|
elseif id == 3 then return "HandshakeFinished"
|
|
elseif id == 4 then return "ApplicationData"
|
|
end
|
|
end
|
|
|
|
local function table_to_hex(ctable)
|
|
local sb=''
|
|
for _, value in pairs(ctable) do
|
|
sb=sb .. string.format("%x", value)
|
|
end
|
|
return sb
|
|
end
|
|
|
|
local function cert_to_tree(rtree, name, ctable, buffer)
|
|
local rrtree = rtree:add(epf_protocol, buffer(), name)
|
|
|
|
local tree = rrtree:add(epf_protocol, buffer(), "Details")
|
|
|
|
local details = ctable[1]
|
|
|
|
tree:add(c_d_name, details[1])
|
|
tree:add(c_d_not_before, tostring(details[2]))
|
|
tree:add(c_d_not_after, tostring(details[3]))
|
|
tree:add(c_d_public_key, table_to_hex(details[4]))
|
|
tree:add(c_d_issuer_public_key, table_to_hex(details[5]))
|
|
|
|
rrtree:add(c_fingerprint, ctable[2])
|
|
rrtree:add(c_signature, table_to_hex(ctable[3]))
|
|
end
|
|
|
|
function epf_protocol.dissector(buffer, pinfo, tree)
|
|
length = buffer:len()
|
|
if length == 0 then return end
|
|
|
|
pinfo.cols.protocol = epf_protocol.name
|
|
|
|
local subtree = tree:add(epf_protocol, buffer(), "e3team Protocol Framework Data")
|
|
local dtree = subtree:add(epf_protocol, buffer(), "Packet Data")
|
|
|
|
local packet_length_flag = tonumber(buffer(0,8):le_uint64())
|
|
|
|
subtree:add_le(packet_length, buffer(0, 8))
|
|
|
|
local data = buffer(8, packet_length_flag)
|
|
|
|
local msgpack_data=''
|
|
local bytes_message = data:bytes()
|
|
for i=0, (bytes_message:len()-1) do
|
|
value=bytes_message:get_index(i)
|
|
msgpack_data=msgpack_data .. string.char(value)
|
|
end
|
|
|
|
local message_unpacked = msgpack.unpack(msgpack_data)
|
|
|
|
subtree:add(packet_id, message_unpacked[1]):append_text(" (" .. id_to_name(message_unpacked[1]) .. ")")
|
|
|
|
local packet_bytes = message_unpacked[2]
|
|
local packet_data=''
|
|
for _, value in pairs(packet_bytes) do
|
|
packet_data=packet_data .. string.char(value)
|
|
end
|
|
|
|
local packet = msgpack.unpack(packet_data)
|
|
|
|
if message_unpacked[1] == 1 then
|
|
-- CLIENT HELLO
|
|
dtree:add(ch_protocol_version, packet[1])
|
|
dtree:add(ch_client_random, table_to_hex(packet[2]))
|
|
dtree:add(ch_client_x25519, table_to_hex(packet[4]))
|
|
elseif message_unpacked[1] == 2 then
|
|
-- SERVER HELLO
|
|
dtree:add(sh_protocol_version, packet[1])
|
|
cert_to_tree(dtree, "Server Certificate", packet[2], buffer)
|
|
dtree:add(sh_server_random, table_to_hex(packet[3]))
|
|
dtree:add(sh_server_x25519, table_to_hex(packet[4]))
|
|
end
|
|
end
|
|
|
|
local function heuristic_checker(buffer, pinfo, tree)
|
|
length = buffer:len()
|
|
if length < 12 then return false end
|
|
|
|
local header_start_flag = buffer(8,1):uint()
|
|
|
|
if header_start_flag ~= 0x92 then return false end
|
|
|
|
local packet_length_flag = buffer(0,8):le_uint64()
|
|
|
|
local packet_length = length - 8
|
|
|
|
if tostring(packet_length) ~= tostring(packet_length_flag) then return false end
|
|
|
|
local packet_id = buffer(9,1):uint()
|
|
|
|
print("packet " .. packet_id)
|
|
|
|
if packet_id == 0x01 or packet_id == 0x02 or packet_id == 0x03 or packet_id == 0x04 then
|
|
epf_protocol.dissector(buffer, pinfo, tree)
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
epf_protocol:register_heuristic("tcp", heuristic_checker)
|