mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Support ATEN/Supermicro KVM VNC
This commit is contained in:
@@ -370,25 +370,57 @@ VNC = {
|
|||||||
return true
|
return true
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
handshake_aten = function(self, buffer)
|
||||||
|
-- buffer is 24 bytes, currently unused, no idea what it's for.
|
||||||
|
if #buffer ~= 24 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
self.aten = buffer
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
login_aten = function(self, username, password)
|
||||||
|
self.socket:send(username .. ("\0"):rep(24 - #username) .. password .. ("\0"):rep(24 - #password))
|
||||||
|
return self:check_auth_result()
|
||||||
|
end,
|
||||||
|
|
||||||
handshake_tight = function(self)
|
handshake_tight = function(self)
|
||||||
|
-- TightVNC security type
|
||||||
-- https://vncdotool.readthedocs.org/en/0.8.0/rfbproto.html#tight-security-type
|
-- https://vncdotool.readthedocs.org/en/0.8.0/rfbproto.html#tight-security-type
|
||||||
local status, buf = self.socket:receive_buf(match.numbytes(4), true)
|
-- Sometimes also ATEN KVM VNC:
|
||||||
|
-- https://github.com/thefloweringash/chicken-aten-ikvm
|
||||||
|
local status, buf = self.socket:receive_bytes(4)
|
||||||
if not status then
|
if not status then
|
||||||
return false, "Failed to get number of tunnels"
|
return false, "Failed to get number of tunnels"
|
||||||
end
|
end
|
||||||
|
-- If it's ATEN, it sends 24 bytes right away. Need to try parsing these
|
||||||
|
-- in case it's TightVNC instead, though.
|
||||||
|
local aten = #buf == 24 and buf
|
||||||
local pos, ntunnels = bin.unpack(">I", buf)
|
local pos, ntunnels = bin.unpack(">I", buf)
|
||||||
|
-- reasonable limits: ATEN might send a huge number here
|
||||||
|
if ntunnels > 0x10000 then
|
||||||
|
return self:handshake_aten(aten)
|
||||||
|
end
|
||||||
local tight = {
|
local tight = {
|
||||||
tunnels = {},
|
tunnels = {},
|
||||||
types = {}
|
types = {}
|
||||||
}
|
}
|
||||||
if ntunnels > 0 then
|
if ntunnels > 0 then
|
||||||
status, buf = self.socket:receive_buf(match.numbytes(16 * ntunnels), true)
|
local have = #buf - pos + 1
|
||||||
|
if have < 16 * ntunnels then
|
||||||
|
local newbuf
|
||||||
|
status, newbuf = self.socket:receive_bytes(16 * ntunnels - have)
|
||||||
if not status then
|
if not status then
|
||||||
|
if aten then
|
||||||
|
return self:handshake_aten(aten)
|
||||||
|
end
|
||||||
return false, "Failed to get list of tunnels"
|
return false, "Failed to get list of tunnels"
|
||||||
end
|
end
|
||||||
|
buf = buf .. newbuf
|
||||||
|
aten = false -- we must have read something beyond 24 bytes
|
||||||
|
end
|
||||||
|
|
||||||
local have_none_tunnel = false
|
local have_none_tunnel = false
|
||||||
pos = 1
|
|
||||||
for i=1, ntunnels do
|
for i=1, ntunnels do
|
||||||
local tunnel = {}
|
local tunnel = {}
|
||||||
pos, tunnel.code, tunnel.vendor, tunnel.signature = bin.unpack(">IA4A8", buf, pos)
|
pos, tunnel.code, tunnel.vendor, tunnel.signature = bin.unpack(">IA4A8", buf, pos)
|
||||||
@@ -398,6 +430,7 @@ VNC = {
|
|||||||
tight.tunnels[#tight.tunnels+1] = tunnel
|
tight.tunnels[#tight.tunnels+1] = tunnel
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- at this point, might still be ATEN with a first byte of 1, but chances are it's Tight
|
||||||
if have_none_tunnel then
|
if have_none_tunnel then
|
||||||
-- Try the "NOTUNNEL" tunnel, for simplicity, if it's available.
|
-- Try the "NOTUNNEL" tunnel, for simplicity, if it's available.
|
||||||
self.socket:send(bin.pack(">I", 0))
|
self.socket:send(bin.pack(">I", 0))
|
||||||
@@ -407,18 +440,40 @@ VNC = {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
status, buf = self.socket:receive_buf(match.numbytes(4), true)
|
local have = #buf - pos + 1
|
||||||
|
if have < 4 then
|
||||||
|
local newbuf
|
||||||
|
status, newbuf = self.socket:receive_bytes(4 - have)
|
||||||
if not status then
|
if not status then
|
||||||
|
if aten then
|
||||||
|
return self:handshake_aten(aten)
|
||||||
|
end
|
||||||
return false, "Failed to get number of Tight auth types"
|
return false, "Failed to get number of Tight auth types"
|
||||||
end
|
end
|
||||||
local pos, nauth = bin.unpack(">I", buf)
|
buf = buf .. newbuf
|
||||||
|
if #buf > 24 then aten = false end
|
||||||
|
end
|
||||||
|
local nauth
|
||||||
|
pos, nauth = bin.unpack(">I", buf, pos)
|
||||||
|
-- reasonable limits: ATEN might send a huge number here
|
||||||
|
if nauth > 0x10000 then
|
||||||
|
return self:handshake_aten(aten)
|
||||||
|
end
|
||||||
if nauth > 0 then
|
if nauth > 0 then
|
||||||
status, buf = self.socket:receive_buf(match.numbytes(16 * nauth), true)
|
have = #buf - pos + 1
|
||||||
|
if have < 16 * nauth then
|
||||||
|
local newbuf
|
||||||
|
status, newbuf = self.socket:receive_bytes(16 * nauth - have)
|
||||||
if not status then
|
if not status then
|
||||||
|
if aten then
|
||||||
|
return self:handshake_aten(aten)
|
||||||
|
end
|
||||||
return false, "Failed to get list of Tight auth types"
|
return false, "Failed to get list of Tight auth types"
|
||||||
end
|
end
|
||||||
|
buf = buf .. newbuf
|
||||||
|
if #buf > 24 then aten = false end
|
||||||
|
end
|
||||||
|
|
||||||
pos = 1
|
|
||||||
for i=1, nauth do
|
for i=1, nauth do
|
||||||
local auth = {}
|
local auth = {}
|
||||||
pos, auth.code, auth.vendor, auth.signature = bin.unpack(">IA4A8", buf, pos)
|
pos, auth.code, auth.vendor, auth.signature = bin.unpack(">IA4A8", buf, pos)
|
||||||
@@ -426,6 +481,11 @@ VNC = {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if aten and pos < 24 then
|
||||||
|
-- server sent 24 bytes but we could only parse some of them. Probably ATEN KVM
|
||||||
|
return self:handshake_aten(aten)
|
||||||
|
end
|
||||||
|
|
||||||
self.tight = tight
|
self.tight = tight
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -437,6 +497,10 @@ VNC = {
|
|||||||
return status, err
|
return status, err
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.aten then
|
||||||
|
return self:login_aten(username, password)
|
||||||
|
end
|
||||||
|
|
||||||
if #self.tight.types == 0 then
|
if #self.tight.types == 0 then
|
||||||
-- nothing further, no auth
|
-- nothing further, no auth
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -100,6 +100,9 @@ action = function(host, port)
|
|||||||
status, data = v:handshake_tight()
|
status, data = v:handshake_tight()
|
||||||
if not status then
|
if not status then
|
||||||
stdnse.debug1("Failed to handshake Tight: %s", data)
|
stdnse.debug1("Failed to handshake Tight: %s", data)
|
||||||
|
else
|
||||||
|
if v.aten then
|
||||||
|
result["Tight auth"] = "ATEN KVM VNC"
|
||||||
else
|
else
|
||||||
local mt = {
|
local mt = {
|
||||||
__tostring = function(t)
|
__tostring = function(t)
|
||||||
@@ -129,6 +132,7 @@ action = function(host, port)
|
|||||||
result["Tight auth subtypes"] = subtypes
|
result["Tight auth subtypes"] = subtypes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
-- Reset the connection for further tests
|
-- Reset the connection for further tests
|
||||||
v:disconnect()
|
v:disconnect()
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user