From 71bfe5c700d52987e9272216fb362cf3a91267d3 Mon Sep 17 00:00:00 2001 From: kroosec Date: Fri, 13 Jul 2012 14:55:34 +0000 Subject: [PATCH] Added ospf library that was written by Patrik and added documentation and some bug fixes to it. --- CHANGELOG | 2 + nselib/ospf.lua | 283 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 285 insertions(+) create mode 100644 nselib/ospf.lua diff --git a/CHANGELOG b/CHANGELOG index 69597495d..568d5a827 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,6 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added ospf library which handles OSPFv2 packets. + [Patrik Karlsson] o [NSE] Fixed a false positive in http-vuln-cve2011-3192.nse, which detected Apache 2.2.22 as vulnerable. [Michael Meyer] diff --git a/nselib/ospf.lua b/nselib/ospf.lua new file mode 100644 index 000000000..fff2b31ce --- /dev/null +++ b/nselib/ospf.lua @@ -0,0 +1,283 @@ +--- +-- A minimalistic OSPF library, currently supporting IPv4 and the following +-- OSPF message types: HELLO +-- +-- The library consists of an OSPF class that contains code to handle OSPFv2 packets. +-- +-- @author "Patrik Karlsson " +-- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html + +local stdnse = require "stdnse" +local ipOps = require "ipOps" +local packet = require "packet" +_ENV = stdnse.module("ospf", stdnse.seeall) + +-- The OSPF class. +OSPF = { + + -- Message Type constants + Message = { + HELLO = 1, + DB_DESCRIPTION = 2, + LS_UPDATE = 4, + }, + + LSUpdate = { + + }, + + Header = { + size = 24, + new = function(self, type, area_id, router_id, auth_type, auth_data) + local o = { + ver = 2, + type = type, + length = 0, + router_id = router_id or 0, + area_id = area_id or 0, + chksum = 0, + auth_type = auth_type or 0, + auth_data = auth_data or {}, + } + setmetatable(o, self) + self.__index = self + return o + end, + + parse = function(data) + local header = OSPF.Header:new() + local pos + pos, header.ver, header.type, header.length = bin.unpack(">CCS", data) + assert( header.ver == 2, "Invalid OSPF version detected") + + pos, header.router_id, header.area_id, header.chksum, header.auth_type + = bin.unpack("ISS", data, pos) + + -- No authentication + if header.auth_type == 0x00 then + header.auth_data.password = nil + -- Clear text password + elseif header.auth_type == 0x01 then + pos, header.auth_data.password = bin.unpack(">A8", data, pos) + -- MD5 hash authentication + elseif header.auth_type == 0x02 then + _, header.auth_data.keyid = bin.unpack(">C", data, pos+2) + _, header.auth_data.length = bin.unpack(">C", data, pos+3) + _, header.auth_data.seq = bin.unpack(">C", data, pos+4) + _, header.auth_data.hash = bin.unpack(">H"..header.auth_data.length, data, header.length+1) + else + -- Shouldn't happen + stdnse.print_debug("Unknown authentication type " .. header.auth_type) + return nil + end + header.router_id = ipOps.fromdword(header.router_id) + return header + end, + + --- Sets the OSPF Area ID + -- @param areaid Area ID. + setAreaID = function(self, areaid) + self.area_id = (type(areaid) == "number") and areaid or ipOps.todword(areaid) + end, + + --- Sets the OSPF Router ID + -- @param router_id Router ID. + setRouterId = function(self, router_id) + self.router_id = ipOps.todword(router_id) + end, + + --- Sets the OSPF Packet length + -- @param length Packet length. + setLength = function(self, length) + self.length = self.size + length + end, + + __tostring = function(self) + local hdr = bin.pack(">CCS", self.ver, self.type, self.length ) + hdr = hdr .. bin.pack(">IISS", self.router_id, self.area_id, self.chksum, self.auth_type) + if self.auth_type == 0x01 then + hdr = hdr .. bin.pack(">A8", self.auth_data.password) + elseif self.auth_type == 0x02 then + hdr = hdr .. bin.pack(">A".. self.auth_data.length, self.auth_data.hash) + end + return hdr + end, + + }, + + Hello = { + new = function(self) + local o = { + header = OSPF.Header:new(OSPF.Message.HELLO), + options = 0x02, + prio = 0, + interval = 10, + router_dead_interval = 40 + } + setmetatable(o, self) + self.__index = self + return o + end, + + --- Adds a neighbor to the list of neighbors. + -- @param neighbor IP Address of the neighbor. + addNeighbor = function(self, neighbor) + table.insert(self.neighbors, bin.pack("ISCCIII", self.netmask, self.interval, self.options, self.prio, self.router_dead_interval, self.DR, self.BDR) + for _, n in ipairs(self.neighbors) do + data = data .. bin.pack("= hello.header.length, "OSPF packet too short") + pos, hello.netmask, hello.interval, hello.options, hello.prio, + hello.router_dead_interval, hello.DR, + hello.BDR = bin.unpack("SCCI", self.mtu, self.options, flags, self.sequence) + self.header:setLength(#data) + return tostring(self.header) .. data + end + local data = tostr() + self.header.chksum = packet.in_cksum(data:sub(1,16) .. data:sub(19)) + return tostr() + end, + + parse = function(data) + local desc = OSPF.DBDescription:new() + local pos = OSPF.Header.size + 1 + desc.header = OSPF.Header.parse(data) + assert( #data == desc.header.length, "OSPF packet too short") + + local flags = 0 + pos, desc.mtu, desc.options, flags, desc.sequence = bin.unpack(">SCCI", data, pos) + + desc.init = ( bit.band(flags, 4) == 4 ) + desc.more = ( bit.band(flags, 2) == 2 ) + desc.master = ( bit.band(flags, 1) == 1 ) + + if ( desc.init or not(desc.more) ) then + return desc + end + + return desc + end, + + }, + + Response = { + + parse = function(data) + local pos, ver, ospf_type = bin.unpack("CC", data) + if ( ospf_type == OSPF.Message.HELLO ) then + return OSPF.Hello.parse( data ) + elseif( ospf_type == OSPF.Message.DB_DESCRIPTION ) then + return OSPF.DBDescription.parse(data) + end + return + end, + + } +} + +return _ENV;