mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Add openflow-info.nse. Closes #711
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
#Nmap Changelog ($Id$); -*-text-*-
|
#Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE][GH#711] New script openflow-info gathers preferred and supported
|
||||||
|
protocol versions from OpenFlow devices [Jay Smith, Mak Kolybabi]
|
||||||
|
|
||||||
o New UDP payloads:
|
o New UDP payloads:
|
||||||
+ [GH#1279] TS3INIT1 for UDP 3389 [colcrunch]
|
+ [GH#1279] TS3INIT1 for UDP 3389 [colcrunch]
|
||||||
+ [GH#1895] DTLS for UDP 3391 (RD Gateway) [Arnim Rupp]
|
+ [GH#1895] DTLS for UDP 3391 (RD Gateway) [Arnim Rupp]
|
||||||
|
|||||||
@@ -2363,8 +2363,14 @@ match oftp m|^\x10\0\0\x17IODETTE FTP READY \r$| p/ODETTE File Transfer Protocol
|
|||||||
match oo-defrag m|^\x99\0\0\0\x01\0\0\0\x03\0\0\0\xb9\x08\0\0\x02\0\0\0\x01\0\0\0\0\0\0\0N\x06\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\n\x0b\0\0\0\xe8\xff\x01\0\x95\x8a\x01\0\0\0\0\0\0\0\0\0\x12\0\0\0 o\0\0\x13\0\0\0p\0\0\0\xf5\x01\0\0\x8c\x02\0\0\x1c\x01\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0gM1\x06\0\0\0\0\x01\0\0\0gM1\x06\0\0\0\0\x98\xadm\t\0\0\0\0\x02\0\0\0\xff\xfa\x9e\x0f\0\0\0\0\0\xff\r\x06\0\0\0\0\x99\0\0\0\x01\0\0\0\x03\0\0\0\xb9\x08\0\0\x02\0\0\0\x01\0\0\0\0\0\0\0N\x06\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x04\x0b\0\0\0\xe8\xff\x01\0\x95\x8a\x01\0\0\0\0\0\0\0\0\0\x12\0\0\0!o\0\0\x13\0\0\0p\0\0\0\xf5\x01\0\0\x8c\x02\0\0\x1c\x01\0\0\0\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0gM1\x06\0\0\0\0\x01\0\0\0gM1\x06\0\0\0\0\x98\xadm\t\0\0\0\0\x02\0\0\0\xff\xfa\x9e\x0f\0\0\0\0\0\xff\r\x06\0\0\0\0\x99\0\0\0\x01\0\0\0\x03\0\0\0\xb9\x08\0\0\x02\0\0\0\x01\0\0\0\0\0\0\0o\x0e\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\n\x0b\0\0\0\xe8\xff\x01\0\x95\x8a\x01\0\0\0\0\0\0\0\0\0\x12\0\0\0 o\0\0\x13\0\0\0p\0\0\0\xf5\x01\0\0\x8c\x02\0\0\x1c\x01\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0gM1\x06\0\0\0\0\x01\0\0\0gM1\x06\0\0\0\0\x98\xadm\t\0\0\0\0\x02\0\0\0\xff\xfa\x9e\x0f\0\0\0\0\0\xff\r\x06\0\0\0\x006\x01\0\0\x01\0\0\0\x03\0\0\0\x07\x08\0\0\x02\0\0\0\x07\x052Q\0\0L\^\x03\0\0\0\0\0\xa2\x88\0\0\0\0\0\0\xd9\xe6\x03\0\0\0\0\0\xb9\x02\0\0\0\0\0\0\x0e\x0b\0\0\0\0\0\0\)\xb8\x02\0\0\0\0\0\xed\x07\x95\?\0\0C\xad/\+i\0t\r\0\0\0\0\0\0{{\x16\x05\0\0\0\0\0\0\0\0\xd0\0\0\0((?:[^\0]\0)+)\0\x006\x01\0\0\x01\0\0\0\x03\0\0\0\x07\x08\0\0\x02\0\0\0\x07\x052Q\0\0L\^\x03\0\0\0\0\0\xa2\x88\0\0\0\0\0\0\xd9\xe6\x03\0\0\0\0\0\xb9\x02\0\0\0\0\0\0\x0e\x0b\0\0\0\0\0\0\)\xb8\x02\0\0\0\0\0\xed\x07\x95\?\0\0C\xad/\+i\0t\r\0\0\0\0\0\0{{\x16\x05\0$|s p/O&O Defrag Professional/ v/15/ i/path: $P(1)/
|
match oo-defrag m|^\x99\0\0\0\x01\0\0\0\x03\0\0\0\xb9\x08\0\0\x02\0\0\0\x01\0\0\0\0\0\0\0N\x06\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\n\x0b\0\0\0\xe8\xff\x01\0\x95\x8a\x01\0\0\0\0\0\0\0\0\0\x12\0\0\0 o\0\0\x13\0\0\0p\0\0\0\xf5\x01\0\0\x8c\x02\0\0\x1c\x01\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0gM1\x06\0\0\0\0\x01\0\0\0gM1\x06\0\0\0\0\x98\xadm\t\0\0\0\0\x02\0\0\0\xff\xfa\x9e\x0f\0\0\0\0\0\xff\r\x06\0\0\0\0\x99\0\0\0\x01\0\0\0\x03\0\0\0\xb9\x08\0\0\x02\0\0\0\x01\0\0\0\0\0\0\0N\x06\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\x04\x0b\0\0\0\xe8\xff\x01\0\x95\x8a\x01\0\0\0\0\0\0\0\0\0\x12\0\0\0!o\0\0\x13\0\0\0p\0\0\0\xf5\x01\0\0\x8c\x02\0\0\x1c\x01\0\0\0\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0gM1\x06\0\0\0\0\x01\0\0\0gM1\x06\0\0\0\0\x98\xadm\t\0\0\0\0\x02\0\0\0\xff\xfa\x9e\x0f\0\0\0\0\0\xff\r\x06\0\0\0\0\x99\0\0\0\x01\0\0\0\x03\0\0\0\xb9\x08\0\0\x02\0\0\0\x01\0\0\0\0\0\0\0o\x0e\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\n\x0b\0\0\0\xe8\xff\x01\0\x95\x8a\x01\0\0\0\0\0\0\0\0\0\x12\0\0\0 o\0\0\x13\0\0\0p\0\0\0\xf5\x01\0\0\x8c\x02\0\0\x1c\x01\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0gM1\x06\0\0\0\0\x01\0\0\0gM1\x06\0\0\0\0\x98\xadm\t\0\0\0\0\x02\0\0\0\xff\xfa\x9e\x0f\0\0\0\0\0\xff\r\x06\0\0\0\x006\x01\0\0\x01\0\0\0\x03\0\0\0\x07\x08\0\0\x02\0\0\0\x07\x052Q\0\0L\^\x03\0\0\0\0\0\xa2\x88\0\0\0\0\0\0\xd9\xe6\x03\0\0\0\0\0\xb9\x02\0\0\0\0\0\0\x0e\x0b\0\0\0\0\0\0\)\xb8\x02\0\0\0\0\0\xed\x07\x95\?\0\0C\xad/\+i\0t\r\0\0\0\0\0\0{{\x16\x05\0\0\0\0\0\0\0\0\xd0\0\0\0((?:[^\0]\0)+)\0\x006\x01\0\0\x01\0\0\0\x03\0\0\0\x07\x08\0\0\x02\0\0\0\x07\x052Q\0\0L\^\x03\0\0\0\0\0\xa2\x88\0\0\0\0\0\0\xd9\xe6\x03\0\0\0\0\0\xb9\x02\0\0\0\0\0\0\x0e\x0b\0\0\0\0\0\0\)\xb8\x02\0\0\0\0\0\xed\x07\x95\?\0\0C\xad/\+i\0t\r\0\0\0\0\0\0{{\x16\x05\0$|s p/O&O Defrag Professional/ v/15/ i/path: $P(1)/
|
||||||
|
|
||||||
# https://wiki.wireshark.org/OpenFlow
|
# https://wiki.wireshark.org/OpenFlow
|
||||||
# 4-byte TXID is random in OpenDaylight, sequential in POX
|
# 4-byte TXID is random in OpenDaylight, sequential in POX, and decrementing from 0xFFFFFFFF in floodlight.
|
||||||
softmatch openflow m|^\x01\0\0\x08....$| i/OpenFlow 1.0/
|
# An extension may or may not be sent, account for both cases.
|
||||||
|
match openflow m|^\x06\0\0(?:\x10....\0\x01\0)?\x08....$|s p/OpenFlow/ v/1.5.x/
|
||||||
|
match openflow m|^\x05\0\0(?:\x10....\0\x01\0)?\x08....$|s p/OpenFlow/ v/1.4.x/
|
||||||
|
match openflow m|^\x04\0\0(?:\x10....\0\x01\0)?\x08....$|s p/OpenFlow/ v/1.3.x/
|
||||||
|
match openflow m|^\x03\0\0(?:\x10....\0\x01\0)?\x08....$|s p/OpenFlow/ v/1.2/
|
||||||
|
match openflow m|^\x02\0\0(?:\x10....\0\x01\0)?\x08....$|s p/OpenFlow/ v/1.1/
|
||||||
|
match openflow m|^\x01\0\0(?:\x10....\0\x01\0)?\x08....$|s p/OpenFlow/ v/1.0/
|
||||||
|
|
||||||
match openfpc m|^OFPC READY\n$| p/OpenFPC packet capture/
|
match openfpc m|^OFPC READY\n$| p/OpenFPC packet capture/
|
||||||
|
|
||||||
|
|||||||
205
scripts/openflow-info.nse
Normal file
205
scripts/openflow-info.nse
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
local comm = require "comm"
|
||||||
|
local shortport = require "shortport"
|
||||||
|
local stdnse = require "stdnse"
|
||||||
|
local string = require "string"
|
||||||
|
local match = require "match"
|
||||||
|
local table = require "table"
|
||||||
|
|
||||||
|
description = [[
|
||||||
|
Queries OpenFlow controllers for information. Newer versions of the OpenFlow
|
||||||
|
protocol (1.3 and greater) will return a list of all protocol versions supported
|
||||||
|
by the controller. Versions prior to 1.3 only return their own version number.
|
||||||
|
|
||||||
|
For additional information:
|
||||||
|
* https://www.opennetworking.org/images/stories/downloads/sdn-resources/onf-specifications/openflow/openflow-switch-v1.5.0.noipr.pdf
|
||||||
|
]]
|
||||||
|
|
||||||
|
---
|
||||||
|
-- @usage nmap -p 6633,6653 --script openflow-info <target>
|
||||||
|
-- @output
|
||||||
|
-- PORT STATE SERVICE REASON
|
||||||
|
-- 6653/tcp open openflow
|
||||||
|
-- | openflow-info:
|
||||||
|
-- | OpenFlow Running Version: 1.5.X
|
||||||
|
-- | OpenFlow Versions Supported:
|
||||||
|
-- | 1.0
|
||||||
|
-- | 1.1
|
||||||
|
-- | 1.2
|
||||||
|
-- | 1.3.X
|
||||||
|
-- | 1.4.X
|
||||||
|
-- |_ 1.5.X
|
||||||
|
|
||||||
|
author = {"Jay Smith", "Mak Kolybabi <mak@kolybabi.com>"}
|
||||||
|
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
||||||
|
categories = {"default", "safe"}
|
||||||
|
|
||||||
|
-- OpenFlow versions released:
|
||||||
|
-- 0x01 = 1.0
|
||||||
|
-- 0x02 = 1.1
|
||||||
|
-- 0x03 = 1.2
|
||||||
|
-- 0x04 = 1.3.X
|
||||||
|
-- 0x05 = 1.4.X
|
||||||
|
-- 0x06 = 1.5.X
|
||||||
|
-- The bits in the version bitmap are indexed by the ofp version number of the
|
||||||
|
-- protocol. If the bit identified by the number of left bitshift equal
|
||||||
|
-- to a ofp version number is set, this OpenFlow version is supported.
|
||||||
|
local openflow_versions = {
|
||||||
|
[0x02] = "1.0",
|
||||||
|
[0x04] = "1.1",
|
||||||
|
[0x08] = "1.2",
|
||||||
|
[0x10] = "1.3.X",
|
||||||
|
[0x20] = "1.4.X",
|
||||||
|
[0x40] = "1.5.X"
|
||||||
|
}
|
||||||
|
|
||||||
|
local OPENFLOW_HEADER_SIZE = 8
|
||||||
|
local OFPT_HELLO = 0
|
||||||
|
local OFPHET_VERSIONBITMAP = 1
|
||||||
|
|
||||||
|
portrule = shortport.version_port_or_service({6633, 6653}, "openflow", "tcp")
|
||||||
|
|
||||||
|
receive_message = function(host, port)
|
||||||
|
local hello = string.pack(
|
||||||
|
">I1 I1 I2 I4",
|
||||||
|
0x04,
|
||||||
|
OFPT_HELLO,
|
||||||
|
OPENFLOW_HEADER_SIZE,
|
||||||
|
0xFFFFFFFF
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Handshake Info:
|
||||||
|
-- Versions 1.3.1 and later say hello with a bitmap of versions supported
|
||||||
|
-- Earlier versions either say hello without the bitmap.
|
||||||
|
-- Some implementations are shy and don't make the first move, so we'll say
|
||||||
|
-- hello first. We'll pretend to be a switch using version 1.0 of the protocol
|
||||||
|
local socket, response = comm.tryssl(host, port, hello, {bytes = OPENFLOW_HEADER_SIZE})
|
||||||
|
if not socket then
|
||||||
|
stdnse.debug1("Failed to connect to service: %s", response)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if #response < OPENFLOW_HEADER_SIZE then
|
||||||
|
socket:close()
|
||||||
|
stdnse.debug1("Initial packet received was %d bytes, need >= %d bytes.", #response, OPENFLOW_HEADER_SIZE)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The first byte is the protocol version number being used. So long as that
|
||||||
|
-- number is less than the currently-published versions, then we can be
|
||||||
|
-- confident in our parsing of the packet.
|
||||||
|
local pos = 1
|
||||||
|
local message = {}
|
||||||
|
local message_version, pos = string.unpack(">I1", response, 1)
|
||||||
|
if message_version > 0x06 then
|
||||||
|
socket:close()
|
||||||
|
stdnse.debug1("Initial packet received had unrecognized version %d.", message_version)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
message.version = message_version
|
||||||
|
|
||||||
|
-- The second byte is the packet type.
|
||||||
|
local message_type, pos = string.unpack(">I1", response, pos)
|
||||||
|
message.type = message_type
|
||||||
|
|
||||||
|
-- The fourth and fifth bytes are the length of the entire message, including
|
||||||
|
-- the header and length itself.
|
||||||
|
local message_length, pos = string.unpack(">I2", response, pos)
|
||||||
|
if message_length < OPENFLOW_HEADER_SIZE then
|
||||||
|
socket:close()
|
||||||
|
stdnse.debug1("Response declares length as %d bytes, need >= %d bytes.", message_length, OPENFLOW_HEADER_SIZE)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
message.length = message_length
|
||||||
|
|
||||||
|
-- The remainder of the header contains the ID.
|
||||||
|
local message_id, pos = string.unpack(">I4", response, pos)
|
||||||
|
message.id = message_id
|
||||||
|
|
||||||
|
-- All remaining data from the response, up until the message length, is the body.
|
||||||
|
assert(pos == OPENFLOW_HEADER_SIZE + 1)
|
||||||
|
message.body = response:sub(pos, message_length)
|
||||||
|
|
||||||
|
-- If we have the whole packet, pass it up the call stack.
|
||||||
|
if message_length <= #response then
|
||||||
|
socket:close()
|
||||||
|
return message
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If message length is larger than the data we already have, receive the
|
||||||
|
-- remainder of the packet.
|
||||||
|
local missing_bytes = message_length - #response
|
||||||
|
local status, body = socket:receive_buf(match.numbytes(missing_bytes), true)
|
||||||
|
if not status then
|
||||||
|
socket:close()
|
||||||
|
stdnse.debug1("Failed to receive missing %d bytes of response: %s", missing_bytes, body)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
message.body = (response .. body):sub(pos, message_length)
|
||||||
|
|
||||||
|
return message
|
||||||
|
end
|
||||||
|
|
||||||
|
retrieve_version_bitmap = function(message)
|
||||||
|
-- HELLO message structure:
|
||||||
|
-- /* OFPT_HELLO. This message includes zero or more hello elements having
|
||||||
|
-- * variable size. Unknown elements types must be ignored/skipped, to allow
|
||||||
|
-- * for future extensions. */
|
||||||
|
-- struct ofp_hello {
|
||||||
|
-- struct ofp_header header;
|
||||||
|
-- /* Hello element list */
|
||||||
|
-- struct ofp_hello_elem_header elements[0]; /* List of elements - 0 or more */
|
||||||
|
-- };
|
||||||
|
-- The HELLO message may contain zero or more hello elements. One of these
|
||||||
|
-- hello elements may be of the type OFPHET_VERSIONBITMAP. We must search
|
||||||
|
-- through elements until we find OFPHET_VERSIONBITMAP.
|
||||||
|
-- Note: As of version 1.5, OFPHET_VERSIONBITMAP is the only standard hello element type.
|
||||||
|
-- However, we can not assume that this will be the case for long.
|
||||||
|
local pos = 1
|
||||||
|
local body = message.body
|
||||||
|
while pos + 4 < #body - 1 do
|
||||||
|
local element_length, element_type
|
||||||
|
element_type, element_length, pos = string.unpack(">I2 I2", body, pos)
|
||||||
|
if pos + element_length < #body then
|
||||||
|
stdnse.debug1("Ran out of data parsing element type %d at position %d.", element_type, pos)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if element_type == OFPHET_VERSIONBITMAP then
|
||||||
|
return string.unpack(">I4", body, pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
pos = pos + element_length - 4
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
action = function(host, port)
|
||||||
|
local output = stdnse.output_table()
|
||||||
|
|
||||||
|
local message = receive_message(host, port)
|
||||||
|
if not message then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
output["OpenFlow Version Running"] = openflow_versions[2 ^ message.version]
|
||||||
|
if message.type ~= OFPT_HELLO then
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
local version_bitmap = retrieve_version_bitmap(message)
|
||||||
|
if not version_bitmap then
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
local supported_versions = {}
|
||||||
|
for mask, version in pairs(openflow_versions) do
|
||||||
|
if mask & version_bitmap then
|
||||||
|
table.insert(supported_versions, version)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort(supported_versions)
|
||||||
|
output["OpenFlow Versions Supported"] = supported_versions
|
||||||
|
|
||||||
|
return output
|
||||||
|
end
|
||||||
@@ -407,6 +407,7 @@ Entry { filename = "ntp-monlist.nse", categories = { "discovery", "intrusive", }
|
|||||||
Entry { filename = "omp2-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "omp2-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "omp2-enum-targets.nse", categories = { "discovery", "safe", } }
|
Entry { filename = "omp2-enum-targets.nse", categories = { "discovery", "safe", } }
|
||||||
Entry { filename = "omron-info.nse", categories = { "discovery", "version", } }
|
Entry { filename = "omron-info.nse", categories = { "discovery", "version", } }
|
||||||
|
Entry { filename = "openflow-info.nse", categories = { "default", "safe", } }
|
||||||
Entry { filename = "openlookup-info.nse", categories = { "default", "discovery", "safe", "version", } }
|
Entry { filename = "openlookup-info.nse", categories = { "default", "discovery", "safe", "version", } }
|
||||||
Entry { filename = "openvas-otp-brute.nse", categories = { "brute", "intrusive", } }
|
Entry { filename = "openvas-otp-brute.nse", categories = { "brute", "intrusive", } }
|
||||||
Entry { filename = "openwebnet-discovery.nse", categories = { "discovery", "safe", } }
|
Entry { filename = "openwebnet-discovery.nse", categories = { "discovery", "safe", } }
|
||||||
|
|||||||
Reference in New Issue
Block a user