1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
local math = require "math"
local nmap = require "nmap"
local packet = require "packet"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"
description = [[
Discovers servers supporting the ATA over Ethernet protocol. ATA over Ethernet
is an ethernet protocol developed by the Brantley Coile Company and allows for
simple, high-performance access to SATA drives over Ethernet.
Discovery is performed by sending a Query Config Request to the Ethernet
broadcast address with all bits set in the major and minor fields of the
header.
]]
---
-- @usage
-- nmap --script broadcast-ataoe-discover -e <interface>
--
-- @output
-- Pre-scan script results:
-- | broadcast-ataoe-discover:
-- |_ Server: 08:00:27:12:34:56; Version: 1; Major: 0; Minor: 1
--
author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"broadcast", "safe"}
prerule = function() return true end
-- The minimalistic ATAoE interface
ATAoE = {
-- Supported commands
Cmd = {
QUERY_CONFIG_INFORMATION = 1,
},
Header = {
-- creates a new Header instance
new = function(self, cmd, tag)
local o = {
version = 1,
flags = 0,
major = 0xffff,
minor = 0xff,
error = 0,
cmd = ATAoE.Cmd.QUERY_CONFIG_INFORMATION,
tag = tag or math.random(0,0xffffffff),
}
setmetatable(o, self)
self.__index = self
return o
end,
-- parses a raw string of data and creates a new Header instance
-- @return header new instance of header
parse = function(data)
local header = ATAoE.Header:new()
local pos, verflags
verflags, header.error,
header.major, header.minor,
header.cmd, header.tag, pos = string.unpack(">BBI2BBI4", data)
header.version = verflags >> 4
header.flags = verflags & 0x0F
return header
end,
-- return configuration info request as string
__tostring = function(self)
assert(self.tag, "No tag was specified in Config Info Request")
local verflags = self.version << 4
return string.pack(">BBI2BBI4", verflags, self.error, self.major, self.minor, self.cmd, self.tag)
end,
},
-- The Configuration Info Request
ConfigInfoRequest = {
new = function(self, tag)
local o = {
header = ATAoE.Header:new(ATAoE.Cmd.QUERY_CONFIG_INFORMATION, tag)
}
setmetatable(o, self)
self.__index = self
return o
end,
__tostring = function(self)
return tostring(self.header)
end,
}
}
-- Send a Config Info Request to the ethernet broadcast address
-- @param iface table as returned by nmap.get_interface_info()
local function sendConfigInfoRequest(iface)
local ETHER_BROADCAST, P_ATAOE = "ff:ff:ff:ff:ff:ff", 0x88a2
local req = ATAoE.ConfigInfoRequest:new()
local tag = req.tag
local p = packet.Frame:new()
p.mac_src = iface.mac
p.mac_dst = packet.mactobin(ETHER_BROADCAST)
p.ether_type = string.pack(">I2", P_ATAOE)
p.buf = tostring(req)
p:build_ether_frame()
local dnet = nmap.new_dnet()
dnet:ethernet_open(iface.device)
dnet:ethernet_send(p.frame_buf)
dnet:ethernet_close()
end
action = function()
local iname = nmap.get_interface()
if ( not(iname) ) then
stdnse.verbose1("No interface supplied, use -e")
return
end
if ( not(nmap.is_privileged()) ) then
stdnse.verbose1("not running for lack of privileges")
return
end
local iface = nmap.get_interface_info(iname)
if ( not(iface) ) then
return stdnse.format_output(false, "Failed to retrieve interface information")
end
local pcap = nmap.new_socket()
pcap:set_timeout(5000)
pcap:pcap_open(iface.device, 1500, true, "ether proto 0x88a2 && !ether src " .. stdnse.format_mac(iface.mac))
sendConfigInfoRequest(iface)
local result = {}
repeat
local status, len, l2_data, l3_data = pcap:pcap_receive()
if ( status ) then
local header = ATAoE.Header.parse(l3_data)
local f = packet.Frame:new(l2_data)
f:ether_parse()
local str = ("Server: %s; Version: %d; Major: %d; Minor: %d"):format(
stdnse.format_mac(f.mac_src),
header.version,
header.major,
header.minor)
table.insert(result, str)
end
until( not(status) )
pcap:pcap_close()
if ( #result > 0 ) then
return stdnse.format_output(true, result)
end
end
|