fixed tcp read_chunk nad improved dissector

now it can read broken ACK responses
This commit is contained in:
Arturo Hernandez 2018-05-25 16:44:38 -04:00
parent 2af1d7d171
commit f1b9e0d656
3 changed files with 212 additions and 170 deletions

View File

@ -88,7 +88,10 @@ try:
print (conn) print (conn)
print ('') print ('')
print ('--- Get User ---') print ('--- Get User ---')
inicio = time.time()
users = conn.get_users() users = conn.get_users()
final = time.time()
print (' took {:.3f}[s]'.format(final - inicio))
max_uid = 0 max_uid = 0
prev = None prev = None
if not args.deleteuser: if not args.deleteuser:
@ -119,6 +122,7 @@ try:
#print '' #print ''
if args.adduser and user.uid == args.adduser: if args.adduser and user.uid == args.adduser:
prev = user prev = user
print (' took {:.3f}[s]'.format(final - inicio))
if args.adduser: if args.adduser:
uid = int(args.adduser) uid = int(args.adduser)
@ -167,7 +171,11 @@ try:
#conn.test_voice(10) #conn.test_voice(10)
if args.templates: if args.templates:
print ("Read Templates...") print ("Read Templates...")
inicio = time.time()
templates = conn.get_templates() templates = conn.get_templates()
final = time.time()
print (' took {:.3f}[s]'.format(final - inicio))
print ('now checking individually...')
for tem in templates: for tem in templates:
tem2 =conn.get_user_template(tem.uid,tem.fid) tem2 =conn.get_user_template(tem.uid,tem.fid)
if tem2 is None: if tem2 is None:
@ -177,13 +185,18 @@ try:
else: else:
print ("dif-1 %s" % tem) print ("dif-1 %s" % tem)
print ("dif-2 %s" % tem2) print ("dif-2 %s" % tem2)
print (' took {:.3f}[s]'.format(final - inicio))
if args.records: if args.records:
print ("Read Records...") print ("Read Records...")
inicio = time.time()
attendance = conn.get_attendance() attendance = conn.get_attendance()
final = time.time()
print (' took {:.3f}[s]'.format(final - inicio))
i = 0 i = 0
for att in attendance: for att in attendance:
i +=1 i +=1
print ("ATT {:>6}: uid:{:>3}, user_id:{:>8} t: {}, s:{}".format(i, att.uid, att.user_id, att.timestamp, att.status)) print ("ATT {:>6}: uid:{:>3}, user_id:{:>8} t: {}, s:{}".format(i, att.uid, att.user_id, att.timestamp, att.status))
print (' took {:.3f}[s]'.format(final - inicio))
print ('') print ('')
print ('--- sizes & capacity ---') print ('--- sizes & capacity ---')
conn.read_sizes() conn.read_sizes()

View File

@ -910,7 +910,7 @@ class ZK(object):
return False return False
uid = users[0].uid uid = users[0].uid
for _retries in range(3): for _retries in range(3):
command = 88 # comando secreto!!! command = 88 # comando secreto!!! GET_USER_TEMPLATE
command_string = pack('hb', uid, temp_id) command_string = pack('hb', uid, temp_id)
response_size = 1024 + 8 response_size = 1024 + 8
cmd_response = self.__send_command(command, command_string, response_size) cmd_response = self.__send_command(command, command_string, response_size)
@ -946,7 +946,7 @@ class ZK(object):
print ("Incorrect tcp packet") print ("Incorrect tcp packet")
return None return None
recieved = len(data_recv) recieved = len(data_recv)
if self.verbose: print ("recieved {}, size {} rec {}".format(recieved, size, data_recv.encode('hex'))) if self.verbose: print ("recieved {}, size {} rec {}".format(recieved, size, data_recv.encode('hex'))) #todo python3
tcp_length = unpack('HHI', data_recv[:8])[2] #bytes+8 tcp_length = unpack('HHI', data_recv[:8])[2] #bytes+8
if tcp_length < (bytes + 8): if tcp_length < (bytes + 8):
if self.verbose: print ("request chunk too big!") if self.verbose: print ("request chunk too big!")
@ -1328,7 +1328,7 @@ class ZK(object):
if tcp_length < (size + 8): if tcp_length < (size + 8):
if self.verbose: print ("request chunk too big!") if self.verbose: print ("request chunk too big!")
response = unpack('HHHH', data_recv[8:16])[0] response = unpack('HHHH', data_recv[8:16])[0]
if recieved >= (size + 32): #complete if recieved >= (size + 32): #complete with ACK_OK included
if response == const.CMD_DATA: if response == const.CMD_DATA:
resp = data_recv[16 : size + 16] # no ack? resp = data_recv[16 : size + 16] # no ack?
if self.verbose: print ("resp complete len", len(resp)) if self.verbose: print ("resp complete len", len(resp))
@ -1337,20 +1337,26 @@ class ZK(object):
if self.verbose: print("broken packet!!! {}".format(response)) if self.verbose: print("broken packet!!! {}".format(response))
return None #broken return None #broken
else: # incomplete else: # incomplete
if self.verbose: print ("try incomplete") if self.verbose: print ("try incomplete (actual valid {})".format(recieved-16))
data.append(data_recv[16:]) # w/o tcp and header data.append(data_recv[16 : size+ 16 ]) # w/o DATA tcp and header
size -= recieved-16 size -= recieved-16 # w/o DATA tcp and header
broken_header = b""
if size < 0: #broken ack header?
broken_header = data_recv[size:]
if self.verbose: print ("broken", (broken_header).encode('hex')) #TODO python3
while size>0: #jic while size>0: #jic
if self.verbose: print ("still need {}".format(size))
data_recv = self.__sock.recv(size) #ideal limit? data_recv = self.__sock.recv(size) #ideal limit?
recieved = len(data_recv) recieved = len(data_recv)
if self.verbose: print ("partial recv {}".format(recieved)) if self.verbose: print ("partial recv {}".format(recieved))
data.append(data_recv) # w/o tcp and header data.append(data_recv) # w/o tcp and header
size -= recieved size -= recieved
#get cmd_ack_ok #get cmd_ack_ok
data_recv = self.__sock.recv(16) data_recv = broken_header + self.__sock.recv(16)
#could be broken #could be broken
if len(data_recv) < 16: if len(data_recv) < 16:
print ("trying to complete broken ACK") print ("trying to complete broken ACK %s /16" % len(data_recv))
if self.verbose: print (data_recv.encode('hex')) #todo python3
data_recv += self.__sock.recv(16 - len(data_recv)) #TODO: CHECK HERE_! data_recv += self.__sock.recv(16 - len(data_recv)) #TODO: CHECK HERE_!
if not self.__test_tcp_top(data_recv): if not self.__test_tcp_top(data_recv):
if self.verbose: print ("invalid tcp ACK OK") if self.verbose: print ("invalid tcp ACK OK")

59
zk6.lua
View File

@ -13,10 +13,6 @@
-- --
-- OVERVIEW: -- OVERVIEW:
-- This script creates an dissector for the UDP protocol on ZK products. -- This script creates an dissector for the UDP protocol on ZK products.
-- to the DNS protocol. That's OK. The goal isn't to fully dissect DNS properly - Wireshark already has a good
-- DNS dissector built-in. We don't need another one. We also have other example Lua scripts, but I don't think
-- they do a good job of explaining things, and the nice thing about this one is getting capture files to
-- run it against is trivial. (plus I uploaded one)
-- --
-- HOW TO RUN THIS SCRIPT: -- HOW TO RUN THIS SCRIPT:
-- Wireshark and Tshark support multiple ways of loading Lua scripts: through a dofile() call in init.lua, -- Wireshark and Tshark support multiple ways of loading Lua scripts: through a dofile() call in init.lua,
@ -179,6 +175,7 @@ local rcomands = {
[75] = "CMD_DOORSTATE_RRQ", [75] = "CMD_DOORSTATE_RRQ",
[76] = "CMD_WRITE_MIFARE", [76] = "CMD_WRITE_MIFARE",
[78] = "CMD_EMPTY_MIFARE", [78] = "CMD_EMPTY_MIFARE",
[88] = "_CMD_GET_USER_TEMPLATE",
[201] = "CMD_GET_TIME", [201] = "CMD_GET_TIME",
[202] = "CMD_SET_TIME", [202] = "CMD_SET_TIME",
[500] = "CMD_REG_EVENT", [500] = "CMD_REG_EVENT",
@ -450,33 +447,54 @@ function zk.dissector(tvbuf, pktinfo, root)
tree:add_le(pf_sesion_id, tvbuf:range(4,2)) tree:add_le(pf_sesion_id, tvbuf:range(4,2))
tree:add_le(pf_reply_id, tvbuf:range(6,2)) tree:add_le(pf_reply_id, tvbuf:range(6,2))
local command = tvbuf:range(0,2):le_uint() local command = tvbuf:range(0,2):le_uint()
if rcomands[command] ~= nil then
--pktinfo.cols.info:set(rcomands[command])
pktinfo.cols.info = string.sub(rcomands[command], 5)
else
--pktinfo.cols.info:set("CMD:" .. tostring(command))
pktinfo.cols.info = "CMD:" .. tostring(command)
end
if pktlen > ZK_HDR_LEN then if pktlen > ZK_HDR_LEN then
remain = pktlen - ZK_HDR_LEN -- TODO: no funciona el prevCommand, remain = pktlen - ZK_HDR_LEN -- TODO: no funciona el prevCommand,
if (command == 1102) then if (command == 1102) then --CMD_AUTH
tree:add_le(pf_commkey, tvbuf:range(8,4)) tree:add_le(pf_commkey, tvbuf:range(8,4))
elseif (command == 1500) then elseif (command == 1500) then --CMD_PREPARE_DATA
tree:add_le(pf_size, tvbuf:range(8,4)) tree:add_le(pf_size, tvbuf:range(8,4))
pktinfo.cols.info = tostring(pktinfo.cols.info) .. " - " .. tvbuf:range(8,4):le_uint() .. " Bytes"
if remain > 8 then if remain > 8 then
tree:add_le(pf_psize, tvbuf:range(12,4)) tree:add_le(pf_psize, tvbuf:range(12,4))
end end
elseif (command == 12) or (command == 11) then elseif (command == 12) or (command == 11) then --CMD_OPTIONS_RRQ CMD_OPTIONS_WRQ
tree:add(pf_string, tvbuf:range(8,remain)) tree:add(pf_string, tvbuf:range(8,remain))
elseif (command == 18) then pktinfo.cols.info = tostring(pktinfo.cols.info) .. " - " .. tvbuf:range(8,remain):string()
elseif (command == 18) then -- CMD_DELETE_USER
tree:add_le(pf_uid, tvbuf(8,2)) tree:add_le(pf_uid, tvbuf(8,2))
elseif (command == 1503) then pktinfo.cols.info = tostring(pktinfo.cols.info) .. " UID: " .. tvbuf:range(8,2):le_uint()
elseif (command == 88) then -- CMD_get_user_Template
tree:add_le(pf_uid, tvbuf(8,2))
tree:add_le(pf_pbfill0, tvbuf(10,1))
pktinfo.cols.info = tostring(pktinfo.cols.info) .. " UID: " .. tvbuf:range(8,2):le_uint()
elseif (command == 1503) then -- CMD_PREPARE_BUFFER
tree:add(pf_pbfill, tvbuf:range(8,1)) tree:add(pf_pbfill, tvbuf:range(8,1))
tree:add_le(pf_pbcmd, tvbuf:range(9,2)) tree:add_le(pf_pbcmd, tvbuf:range(9,2))
tree:add_le(pf_pbarg, tvbuf:range(11,8)) tree:add_le(pf_pbarg, tvbuf:range(11,8))
elseif (command == 1504) then pktinfo.cols.info = tostring(pktinfo.cols.info) .. " - " .. rcomands[tvbuf:range(9,2):le_uint()]
elseif (command == 1504) then --CMD_READ_BUFFER
tree:add_le(pf_start, tvbuf:range(8,4)) tree:add_le(pf_start, tvbuf:range(8,4))
tree:add_le(pf_size, tvbuf:range(12,4)) tree:add_le(pf_size, tvbuf:range(12,4))
elseif (prevCommand == 1503) then pktinfo.cols.info = tostring(pktinfo.cols.info) .. " [" .. tvbuf:range(8,4):le_uint() .. "] -> " .. tvbuf:range(12,4):le_uint()
elseif (command == 1501) then --CMD_DATA
pktinfo.cols.info = tostring(pktinfo.cols.info) .. " " .. (remain) .. " Bytes"
tree:add(pf_string, tvbuf:range(8,remain))
elseif (prevCommand == 1503) then -- CMD_PREPARE_BUFFER OK!
tree:add_le(pf_pbfill0, tvbuf:range(8,1)) tree:add_le(pf_pbfill0, tvbuf:range(8,1))
tree:add_le(pf_size, tvbuf:range(9,4)) tree:add_le(pf_size, tvbuf:range(9,4))
tree:add_le(pf_psize, tvbuf:range(13,4)) tree:add_le(pf_psize, tvbuf:range(13,4))
tree:add_le(pf_pbfree, tvbuf:range(17,4)) tree:add_le(pf_pbfree, tvbuf:range(17,4))
elseif (prevCommand == 12) or (prevCommand == 11) or (prevCommand == 1100) then pktinfo.cols.info = tostring(pktinfo.cols.info) .. " BUFFER [" .. tvbuf:range(9,4):le_uint() .. "] (" .. tvbuf:range(13,4):le_uint() .. ")"
elseif (prevCommand == 12) or (prevCommand == 11) or (prevCommand == 1100) then --CMD_OPTIONS_RRQ CMD_OPTIONS_WRQ OK
tree:add(pf_string, tvbuf:range(8,remain)) tree:add(pf_string, tvbuf:range(8,remain))
pktinfo.cols.info = tostring(pktinfo.cols.info) .. " RESP " .. tvbuf:range(8,remain):string()
elseif (prevCommand == 201) or (prevCommand == 202) then elseif (prevCommand == 201) or (prevCommand == 202) then
local ts = tvbuf:range(8,4):le_uint() local ts = tvbuf:range(8,4):le_uint()
tree:add_le(pf_time, tvbuf:range(8,4)) tree:add_le(pf_time, tvbuf:range(8,4))
@ -512,11 +530,7 @@ function zk.dissector(tvbuf, pktinfo, root)
end end
end end
dprint2("zk.dissector returning",pktlen) dprint2("zk.dissector returning",pktlen)
if rcomands[command] ~= nil then
pktinfo.cols.info:set(rcomands[command])
else
pktinfo.cols.info:set("CMD:" .. tostring(command))
end
prevCommand = command prevCommand = command
-- tell wireshark how much of tvbuff we dissected -- tell wireshark how much of tvbuff we dissected
return pktlen return pktlen
@ -547,11 +561,16 @@ function zk_tcp.dissector(tvbuf, pktinfo, root)
dprint("packet length",pktlen,"too short") dprint("packet length",pktlen,"too short")
return return
end end
-- tell wireshark how much of tvbuff we dissected
dprint2("zk_tcp.dissector returning", pktlen) dprint2("zk_tcp.dissector returning", pktlen)
local machine1 = tvbuf:range(0,2):le_uint()
local machine2 = tvbuf:range(2,2):le_uint()
if (machine1 == 20560) and (machine2 == 32130) then
local tcp_length = tvbuf:range(4,4):le_uint64()
tree:add_le(pf_machine1, tvbuf:range(0,2)) tree:add_le(pf_machine1, tvbuf:range(0,2))
tree:add_le(pf_machine2, tvbuf:range(2,2)) tree:add_le(pf_machine2, tvbuf:range(2,2))
tree:add_le(pf_length, tvbuf:range(4,4)) tree:add_le(pf_length, tvbuf:range(4,4))
-- tell wireshark how much of tvbuff we dissected
if pktlen > ZK_HDR_LEN then if pktlen > ZK_HDR_LEN then
remain = pktlen - ZK_HDR_LEN remain = pktlen - ZK_HDR_LEN
-- zk_tree = tree:add(zk, tvbuf:range(8, remain)) -- zk_tree = tree:add(zk, tvbuf:range(8, remain))
@ -559,6 +578,10 @@ function zk_tcp.dissector(tvbuf, pktinfo, root)
end end
-- set the protocol column to show our protocol name -- set the protocol column to show our protocol name
pktinfo.cols.protocol:set("ZK8") pktinfo.cols.protocol:set("ZK8")
else
pktinfo.cols.protocol:set("ZK8")
pktinfo.cols.info:set("--- data " .. pktlen .. " Bytes")
end
return pktlen return pktlen
end end