diff --git a/nselib/data/packetdecoders.lua b/nselib/data/packetdecoders.lua index 486f6ec88..919cd3d71 100644 --- a/nselib/data/packetdecoders.lua +++ b/nselib/data/packetdecoders.lua @@ -187,8 +187,8 @@ Decoders = { }, - -- EIGRP Query & Update - ['020[13]....00000000'] = { + -- EIGRP Update + ['0201....0000'] = { new = function(self) local o = { dups = {} } @@ -204,548 +204,500 @@ Decoders = { if ( p.ip_p ~= 88 ) then return end local data = layer3:sub(p.ip_data_offset + 1) - + + local eigrp = require("eigrp") + local route_type, proto_name -- Extract the EIGRP header - local pos, ver, opcode, checksum, flags, seq, ack, asnum = bin.unpack(">CCSiiii", data) + local response = eigrp.EIGRP.parse(data) - local route_type, size, nexthop, delay, bandwidth, temp, mtu, orig_router, orig_as, arbtag - local hop_count, reliability, load, reserved, mask - local destination - - -- Iterate over the routes - while ( pos < #data ) do - -- Get the route type as the packet construction varies - pos,route_type = bin.unpack(">S", data, pos) - - if ( route_type == 258 ) then - route_type = 'internal' - pos, size, nexthop, delay, bandwidth, temp, mtu = bin.unpack(">SiiiCS", data, pos) - pos, hop_count, reliability, load, reserved, mask = bin.unpack(">CCCSC", data, pos) + if response then + -- Iterate over tlv tables + for _, tlv in pairs(response.tlvs) do + if eigrp.EIGRP.isRoutingTLV(tlv.type) then - local oct1, oct2, oct3, oct4 = 0, 0, 0, 0 - -- unneeded address octets are left out of the packets, lets fill in the gaps - if ( size == 29 ) then - -- mask 25 or above - pos, oct1, oct2, oct3, oct4 = bin.unpack(">CCCC", data, pos) - elseif ( size == 28 ) then - pos, oct1, oct2, oct3 = bin.unpack(">CCC", data, pos) - elseif ( size == 27 ) then - pos, oct1, oct2 = bin.unpack(">CC", data, pos) - elseif ( size == 26 ) then - pos, oct1 = bin.unpack(">C", data, pos) + if ( not(self.results) ) then + self.results = tab.new(7) + tab.addrow(self.results, 'Sender IP', 'AS#', 'Route Type', 'Destination', 'Next hop', 'Ext Protocol', 'Orig Router ID') + end + if tlv.type == 0x102 then + route_type = "Internal" + elseif tlv.type == 0x103 then + route_type = "External" + for name, value in pairs(eigrp.EXT_PROTO) do + if value == tlv.eproto then + proto_name = name + break + end end - - destination = oct1 .. '.' .. oct2 .. '.' .. oct3 .. '.' .. oct4 .. "/" .. mask - orig_router = 'n/a' - elseif ( route_type == 259 ) then - -- external route, from a different routing protocol - pos, size, nexthop = bin.unpack(">Si", data, pos) - local orig_rtr_oct1, orig_rtr_oct2, orig_rtr_oct3, orig_rtr_oct4, ext_proto_id, ext_metric - pos, orig_rtr_oct1, orig_rtr_oct2, orig_rtr_oct3, orig_rtr_oct4 = bin.unpack(">CCCC", data, pos) - orig_router = orig_rtr_oct1 .. '.' .. orig_rtr_oct2 .. '.' .. orig_rtr_oct3 .. '.' .. orig_rtr_oct4 - pos, orig_as, arbtag, ext_metric = bin.unpack(">iii", data, pos) - pos, reserved, ext_proto_id, flags, delay, bandwidth = bin.unpack(">SCCii", data, pos) - pos, temp, mtu, hop_count, reliability, load, reserved, mask = bin.unpack(">CSCCCSC", data, pos) - - local oct1, oct2, oct3, oct4 = 0, 0, 0, 0 - -- unneeded address octets are left out of the packets, lets fill in the gaps - if ( size == 49 ) then - -- mask 25 or above - pos, oct1, oct2, oct3, oct4 = bin.unpack(">CCCC", data, pos) - elseif ( size == 48 ) then - pos, oct1, oct2, oct3 = bin.unpack(">CCC", data, pos) - elseif ( size == 47 ) then - pos, oct1, oct2 = bin.unpack(">CC", data, pos) - elseif ( size == 46 ) then - pos, oct1 = bin.unpack(">C", data, pos) - end - - destination = oct1 .. '.' .. oct2 .. '.' .. oct3 .. '.' .. oct4 .. "/" .. mask - - local Proto_Types = { - [1] = 'external (IGRP)', - [2] = 'external (EIGRP)', - [3] = 'external (static)', - [4] = 'external (RIP)', - [6] = 'external (OSPF)', - [9] = 'external (RIP)' - } - - route_type = Proto_Types[ext_proto_id] - end - - if ( not(self.results) ) then - self.results = tab.new(9) - tab.addrow(self.results, 'sender ip', 'AS#', 'route type', 'destination', 'hop', 'bandwidth', 'delay', 'seq','orig router') - end - - - if (delay == -1) then delay = 'unreachable' end - - if ( not(self.dups[("%s:%s:s:%s"):format(p.ip_src,asnum,destination,seq)]) ) then + end + if ( not(self.dups[("%s:%s:s:%s"):format(p.ip_src, response.as, tlv.type, tlv.dst)]) ) then if ( target.ALLOW_NEW_TARGETS ) then target.add(p.ip_src) end - self.dups[("%s:%s:%s:%s"):format(p.ip_src,asnum,destination,seq)] = true - tab.addrow( self.results, p.ip_src, asnum, route_type, destination, hop_count, bandwidth, delay, seq, orig_router ) + self.dups[("%s:%s:%s:%s"):format(p.ip_src, response.as, tlv.type, tlv.dst)] = true + tab.addrow( self.results, p.ip_src, response.as, route_type, tlv.dst, tlv.nexth, proto_name or 'X', tlv.orouterid or 'X') + end end + end end - end, - - getResults = function(self) return { name = "EIGRP Query", (self.results and tab.dump(self.results) or "") } end, - }, - - ['0205....00000000'] = { + end, + getResults = function(self) return { name = "EIGRP Update", (self.results and tab.dump(self.results) or "") } end, + }, - new = function(self) + ['0205....0000'] = { + + new = function(self) local o = { dups = {} } setmetatable(o, self) - self.__index = self + self.__index = self return o - end, + end, + + process = function(self, layer3) - process = function(self, layer3) - local p = packet.Packet:new( layer3, #layer3 ) -- EIGRP is IP protocol 88 (0x58), so verify this if ( p.ip_p ~= 88 ) then return end - + local data = layer3:sub(p.ip_data_offset + 1) + + local eigrp = require("eigrp") -- Extract the EIGRP header - local pos, ver, opcode, checksum, flags, seq, ack, asnum = bin.unpack(">CCSiiii", data) - - -- Skip the parameters for now. - pos = pos + 10 - - local holdtime, software, size, ios_major, ios_minor, eigrp_major, eigrp_minor - pos, holdtime, software, size, ios_major, ios_minor, eigrp_major, eigrp_minor = bin.unpack(">SSSCCCC", data, pos) - - if ( not(self.results) ) then + local response = eigrp.EIGRP.parse(data) + -- See if Software version TLV is included + local swvertlv + for num, tlv in pairs(response.tlvs) do + if tlv.type == eigrp.TLV.SWVER then + swvertlv = num + end + end + if swvertlv then + if ( not(self.results) ) then self.results = tab.new(5) - tab.addrow(self.results, 'sender ip', 'AS number', 'hold time', 'EIGRP version', 'IOS version') - end - - if ( not(self.dups[("%s:%s"):format(p.ip_src,asnum)]) ) then + tab.addrow(self.results, 'Sender IP', 'AS number', 'EIGRP version', 'IOS version') + end + + if ( not(self.dups[("%s:%s"):format(p.ip_src,response.as)]) ) then if ( target.ALLOW_NEW_TARGETS ) then target.add(p.ip_src) end - self.dups[("%s:%s"):format(p.ip_src,asnum)] = true - tab.addrow( self.results, p.ip_src, asnum, holdtime, eigrp_major .. '.' .. eigrp_minor, ios_major .. '.' .. ios_minor ) - end - - end, - - getResults = function(self) return { name = "EIGRP Hello", (self.results and tab.dump(self.results) or "") } end, - }, - - -- OSPF - ['0201'] = { -- OSPFv2 Hello packet + self.dups[("%s:%s"):format(p.ip_src,response.as)] = true + tab.addrow( self.results, p.ip_src, response.as, response.tlvs[swvertlv].majv .. '.' .. response.tlvs[swvertlv].minv, response.tlvs[swvertlv].majtlv .. '.' .. response.tlvs[swvertlv].mintlv) + end + end + end, + + getResults = function(self) return { name = "EIGRP Hello", (self.results and tab.dump(self.results) or "") } end, + }, + + -- OSPF + ['02010'] = { -- OSPFv2 Hello packet new = function(self) - local o = { dups = {} } - setmetatable(o, self) - self.__index = self - return o + local o = { dups = {} } + setmetatable(o, self) + self.__index = self + return o end, process = function(self, layer3) - local p = packet.Packet:new( layer3, #layer3 ) - -- IP Protocol is 89 for OSPF - if p.ip_p ~= 89 then return end + local p = packet.Packet:new( layer3, #layer3 ) + -- IP Protocol is 89 for OSPF + if p.ip_p ~= 89 then return end - local ospf = require("ospf") - - local data = layer3:sub(p.ip_data_offset + 1) - local header = ospf.OSPF.Header.parse(data) - if header then - if not(self.results) then - self.results = tab.new(5) - tab.addrow(self.results, 'Source IP', 'Router ID', 'Area ID', 'Auth Type', 'Password') - end - local srcip = p.ip_src - local areaid = header.area_id - local routerid = header.router_id - local authtype = header.auth_type - local authdata - -- Format authentication type and data - if header.auth_type == 0 then - authtype = "None" - authdata = '' - elseif header.auth_type == 1 then - authtype = "Password" - authdata = header.auth_data.password - elseif header.auth_type == 2 then - authtype = "OSPF MD5" - authdata = "" -- Not really helpful, as the MD5 - -- is applied to the whole packet+password - else - -- Error - stdnse.print_debug("Unknown OSPF auth type %d", header.auth_type) - return - end + local ospf = require("ospf") - if ( not(self.dups[("%s:%s"):format(routerid,areaid)]) ) then - if ( target.ALLOW_NEW_TARGETS ) then target.add(routerid) end - self.dups[("%s:%s"):format(routerid,areaid)] = true - tab.addrow( self.results, srcip, routerid, areaid, authtype, authdata) - end + local data = layer3:sub(p.ip_data_offset + 1) + local header = ospf.OSPF.Header.parse(data) + if header then + if not(self.results) then + self.results = tab.new(5) + tab.addrow(self.results, 'Source IP', 'Router ID', 'Area ID', 'Auth Type', 'Password') + end + local srcip = p.ip_src + local areaid = header.area_id + local routerid = header.router_id + local authtype = header.auth_type + local authdata + -- Format authentication type and data + if header.auth_type == 0 then + authtype = "None" + authdata = '' + elseif header.auth_type == 1 then + authtype = "Password" + authdata = header.auth_data.password + elseif header.auth_type == 2 then + authtype = "OSPF MD5" + authdata = "" -- Not really helpful, as the MD5 + -- is applied to the whole packet+password else - return nil + -- Error + stdnse.print_debug("Unknown OSPF auth type %d", header.auth_type) + return end - + + if ( not(self.dups[("%s:%s"):format(routerid,areaid)]) ) then + if ( target.ALLOW_NEW_TARGETS ) then target.add(routerid) end + self.dups[("%s:%s"):format(routerid,areaid)] = true + tab.addrow( self.results, srcip, routerid, areaid, authtype, authdata) + end + else + return nil + end + end, - + getResults = function(self) return { name = "OSPF Hello", (self.results and tab.dump(self.results) or "") } end, + }, }, - }, - - udp = { - - -- DHCP - [68] = { + + udp = { + + -- DHCP + [68] = { new = function(self) - local o = { dups = {} } - setmetatable(o, self) - self.__index = self - return o + local o = { dups = {} } + setmetatable(o, self) + self.__index = self + return o end, - + getOption = function(options, name) - for _, v in ipairs(options) do - if ( v.name == name ) then - if ( type(v.value) == "table" ) then - return stdnse.strjoin(", ", v.value) - else - return v.value - end - end + for _, v in ipairs(options) do + if ( v.name == name ) then + if ( type(v.value) == "table" ) then + return stdnse.strjoin(", ", v.value) + else + return v.value + end end + end end, - + process = function(self, layer3) - local dhcp = require("dhcp") - local p = packet.Packet:new( layer3, #layer3 ) - local data = layer3:sub(p.udp_offset + 9) - - -- the dhcp.parse function isn't optimal for doing - -- this, but it will do for now. First, we need to - -- extract the xid as the parse function checks that it - -- was the same as in the request, which we didn't do. - local pos, msgtype, _, _, _, xid = bin.unpack(" 0 ) then - name = dresp.questions[1].dname - elseif ( dresp.answers and #dresp.answers > 0 ) then - name = dresp.answers[1].dname - end - - if ( not(name) ) then return end - + --- Squeezebox Discovery + [3483] = { + + new = function(self) + local o = { dups = {} } + setmetatable(o, self) + self.__index = self + return o + end, + + process = function(self, layer3) + local p = packet.Packet:new( layer3, #layer3 ) + local data = layer3:sub(p.udp_offset + 9) + + if ( data:match("^eIPAD") ) then if ( not(self.results) ) then - self.results = tab.new(2) - tab.addrow( self.results, 'ip', 'query' ) + self.results = tab.new(1) + tab.addrow( self.results, 'ip' ) end - - -- check for duplicates - if ( not(self.dups[("%s:%s"):format(p.ip_src, name)]) ) then - tab.addrow( self.results, p.ip_src, name ) - self.dups[("%s:%s"):format(p.ip_src, name)] = true - if ( target.ALLOW_NEW_TARGETS ) then target.add(p.ip_src) end + + if ( not(self.dups[p.ip_src]) ) then + tab.addrow( self.results, p.ip_src ) + self.dups[p.ip_src] = true + if ( target.ALLOW_NEW_TARGETS ) then target.add(p.ip_src) end end + end + + end, + + getResults = function(self) return { name = "Squeezebox Discovery", (self.results and tab.dump(self.results) or "") } end, + + }, + + -- Multicast DNS/BonJour/ZeroConf + [5353] = { + + new = function(self) + local o = { dups = {} } + setmetatable(o, self) + self.__index = self + return o + end, + + process = function(self, layer3) + local dns = require('dns') + local bin = require('bin') + + local p = packet.Packet:new( layer3, #layer3 ) + local data = layer3:sub(p.udp_offset + 9) + + local dresp = dns.decode(data) + local name + + if ( dresp.questions and #dresp.questions > 0 ) then + name = dresp.questions[1].dname + elseif ( dresp.answers and #dresp.answers > 0 ) then + name = dresp.answers[1].dname + end + + if ( not(name) ) then return end + + if ( not(self.results) ) then + self.results = tab.new(2) + tab.addrow( self.results, 'ip', 'query' ) + end + + -- check for duplicates + if ( not(self.dups[("%s:%s"):format(p.ip_src, name)]) ) then + tab.addrow( self.results, p.ip_src, name ) + self.dups[("%s:%s"):format(p.ip_src, name)] = true + if ( target.ALLOW_NEW_TARGETS ) then target.add(p.ip_src) end + end end, getResults = function(self) return { name = "MDNS", (self.results and tab.dump(self.results) or "") } end, - }, - - --- Spotify - [57621] = { - + }, + + --- Spotify + [57621] = { + new = function(self) - local o = { dups = {} } - setmetatable(o, self) - self.__index = self - return o + local o = { dups = {} } + setmetatable(o, self) + self.__index = self + return o end, - + process = function(self, layer3) - local p = packet.Packet:new( layer3, #layer3 ) - local data = layer3:sub(p.udp_offset + 9) - - if ( data:match("^SpotUdp") ) then - if ( not(self.results) ) then - self.results = tab.new(1) - tab.addrow( self.results, 'ip' ) - end - - if ( not(self.dups[p.ip_src]) ) then - tab.addrow( self.results, p.ip_src ) - self.dups[p.ip_src] = true - if ( target.ALLOW_NEW_TARGETS ) then target.add(p.ip_src) end - end + local p = packet.Packet:new( layer3, #layer3 ) + local data = layer3:sub(p.udp_offset + 9) + + if ( data:match("^SpotUdp") ) then + if ( not(self.results) ) then + self.results = tab.new(1) + tab.addrow( self.results, 'ip' ) end - + + if ( not(self.dups[p.ip_src]) ) then + tab.addrow( self.results, p.ip_src ) + self.dups[p.ip_src] = true + if ( target.ALLOW_NEW_TARGETS ) then target.add(p.ip_src) end + end + end + end, - + getResults = function(self) return { name = "Spotify", (self.results and tab.dump(self.results) or "") } end, - + + } + } - - } -} + }