mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 20:51:30 +00:00
Address rdp protocol parsing issues in rdp.lua and rdp-enum-ciphers.nse Closes #1611
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
#Nmap Changelog ($Id$); -*-text-*-
|
#Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE][GH#1611] Address two protocol parsing issues in rdp-enum-encryption and
|
||||||
|
the RDP nse library which broke scanning of Windows XP. Clarify protocol
|
||||||
|
types [Tom Sellers]
|
||||||
|
|
||||||
o [NSE][GH#1608] Script http-fileupload-exploiter failed to locate its resource
|
o [NSE][GH#1608] Script http-fileupload-exploiter failed to locate its resource
|
||||||
file unless executed from a specific working directory. [nnposter]
|
file unless executed from a specific working directory. [nnposter]
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,20 @@ local stdnse = require("stdnse")
|
|||||||
local string = require "string"
|
local string = require "string"
|
||||||
_ENV = stdnse.module("rdp", stdnse.seeall)
|
_ENV = stdnse.module("rdp", stdnse.seeall)
|
||||||
|
|
||||||
|
-- Server Core Data 2.2.1.4.2
|
||||||
|
PROTO_VERSION = {
|
||||||
|
[0x00080001] = " RDP 4.0 server",
|
||||||
|
[0x00080004] = " RDP 5.x, 6.x, 7.x, or 8.x server",
|
||||||
|
[0x00080005] = " RDP 10.0 server",
|
||||||
|
[0x00080006] = " RDP 10.1 server",
|
||||||
|
[0x00080007] = " RDP 10.2 server",
|
||||||
|
[0x00080008] = " RDP 10.3 server",
|
||||||
|
[0x00080009] = " RDP 10.4 server",
|
||||||
|
[0x0008000A] = " RDP 10.5 server",
|
||||||
|
[0x0008000B] = " RDP 10.6 server",
|
||||||
|
[0x0008000C] = " RDP 10.7 server",
|
||||||
|
}
|
||||||
|
|
||||||
Packet = {
|
Packet = {
|
||||||
|
|
||||||
TPKT = {
|
TPKT = {
|
||||||
@@ -57,8 +71,10 @@ Packet = {
|
|||||||
itut.length, itut.code, pos = string.unpack("BB", data)
|
itut.length, itut.code, pos = string.unpack("BB", data)
|
||||||
|
|
||||||
if ( itut.code == 0xF0 ) then
|
if ( itut.code == 0xF0 ) then
|
||||||
|
-- X.224 - Data TPDU (DT)
|
||||||
itut.eot, pos = string.unpack("B", data, pos)
|
itut.eot, pos = string.unpack("B", data, pos)
|
||||||
elseif ( itut.code == 0xD0 ) then
|
elseif ( itut.code == 0xD0 ) then
|
||||||
|
-- X.224 - Connection Confirm (CC)
|
||||||
itut.dstref, itut.srcref, itut.class, pos = string.unpack(">I2I2B", data, pos)
|
itut.dstref, itut.srcref, itut.class, pos = string.unpack(">I2I2B", data, pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -86,6 +102,38 @@ Packet = {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ConfCreateResponse = {
|
||||||
|
|
||||||
|
|
||||||
|
new = function(self, data)
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
return o
|
||||||
|
end,
|
||||||
|
|
||||||
|
parse = function(data)
|
||||||
|
local ccr = Packet.ConfCreateResponse:new()
|
||||||
|
local pos = 67
|
||||||
|
|
||||||
|
while data:len() > pos do
|
||||||
|
block_type, block_len = string.unpack("<I2I2", data, pos)
|
||||||
|
if block_type == 0x0c01 then
|
||||||
|
-- 2.2.1.42 Server Core Data - TS_UD_SC_CORE
|
||||||
|
proto_ver = string.unpack("<I4", data, pos + 4)
|
||||||
|
ccr.proto_version = ("RDP Protocol Version: %s"):format(PROTO_VERSION[proto_ver] or "Unknown")
|
||||||
|
elseif block_type == 0x0c02 then
|
||||||
|
-- 2.2.1.4.3 Server Security Data - TS_UD_SC_SEC1
|
||||||
|
ccr.enc_level = string.unpack("B", data, pos + 8)
|
||||||
|
ccr.enc_cipher= string.unpack("B", data, pos + 4)
|
||||||
|
end
|
||||||
|
pos = pos + block_len
|
||||||
|
end
|
||||||
|
|
||||||
|
return ccr
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Request = {
|
Request = {
|
||||||
@@ -258,6 +306,10 @@ Response = {
|
|||||||
|
|
||||||
cr.tpkt = Packet.TPKT.parse(data)
|
cr.tpkt = Packet.TPKT.parse(data)
|
||||||
cr.itut = Packet.ITUT.parse(cr.tpkt.data)
|
cr.itut = Packet.ITUT.parse(cr.tpkt.data)
|
||||||
|
if ( cr.itut.code == 0xF0 ) then
|
||||||
|
-- X.224 - Data TPDU (DT)
|
||||||
|
cr.ccr = Packet.ConfCreateResponse.parse(cr.itut.data)
|
||||||
|
end
|
||||||
return cr
|
return cr
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
@@ -333,6 +385,8 @@ Comm = {
|
|||||||
return true, Response.ConnectionConfirm.parse(data)
|
return true, Response.ConnectionConfirm.parse(data)
|
||||||
elseif ( itut_code == 0xF0 ) then
|
elseif ( itut_code == 0xF0 ) then
|
||||||
return true, Response.MCSConnectResponse.parse(data)
|
return true, Response.MCSConnectResponse.parse(data)
|
||||||
|
elseif itut_code ~= nil then
|
||||||
|
stdnse.debug1(("comm:exch - Unknown itut_code: %s"):format(itut_code))
|
||||||
end
|
end
|
||||||
return false, "Received unhandled packet"
|
return false, "Received unhandled packet"
|
||||||
end,
|
end,
|
||||||
|
|||||||
@@ -15,14 +15,18 @@ http://labs.mwrinfosecurity.com/tools/2009/01/12/rdp-cipher-checker/
|
|||||||
-- @output
|
-- @output
|
||||||
-- PORT STATE SERVICE
|
-- PORT STATE SERVICE
|
||||||
-- 3389/tcp open ms-wbt-server
|
-- 3389/tcp open ms-wbt-server
|
||||||
-- | rdp-enum-encryption:
|
|
||||||
-- | Security layer
|
-- | Security layer
|
||||||
-- | CredSSP: SUCCESS
|
-- | CredSSP (NLA): SUCCESS
|
||||||
|
-- | CredSSP with Early User Auth: SUCCESS
|
||||||
-- | Native RDP: SUCCESS
|
-- | Native RDP: SUCCESS
|
||||||
|
-- | RDSTLS: SUCCESS
|
||||||
-- | SSL: SUCCESS
|
-- | SSL: SUCCESS
|
||||||
-- | RDP Encryption level: High
|
-- | RDP Encryption level: High
|
||||||
|
-- | 40-bit RC4: SUCCESS
|
||||||
|
-- | 56-bit RC4: SUCCESS
|
||||||
-- | 128-bit RC4: SUCCESS
|
-- | 128-bit RC4: SUCCESS
|
||||||
-- |_ FIPS 140-1: SUCCESS
|
-- | FIPS 140-1: SUCCESS
|
||||||
|
-- |_ RDP Protocol Version: RDP 5.x, 6.x, 7.x, or 8.x server
|
||||||
--
|
--
|
||||||
|
|
||||||
author = "Patrik Karlsson"
|
author = "Patrik Karlsson"
|
||||||
@@ -46,7 +50,9 @@ local function enum_protocols(host, port)
|
|||||||
local PROTOCOLS = {
|
local PROTOCOLS = {
|
||||||
["Native RDP"] = 0,
|
["Native RDP"] = 0,
|
||||||
["SSL"] = 1,
|
["SSL"] = 1,
|
||||||
["CredSSP"] = 3
|
["CredSSP (NLA)"] = 3,
|
||||||
|
["RDSTLS"] = 4,
|
||||||
|
["CredSSP with Early User Auth"] = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
local ERRORS = {
|
local ERRORS = {
|
||||||
@@ -71,7 +77,9 @@ local function enum_protocols(host, port)
|
|||||||
return false, response
|
return false, response
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if response.itut.data ~= "" then
|
||||||
local success = string.unpack("B", response.itut.data)
|
local success = string.unpack("B", response.itut.data)
|
||||||
|
|
||||||
if ( success == 2 ) then
|
if ( success == 2 ) then
|
||||||
table.insert(res_proto, ("%s: SUCCESS"):format(k))
|
table.insert(res_proto, ("%s: SUCCESS"):format(k))
|
||||||
elseif ( nmap.debugging() > 0 ) then
|
elseif ( nmap.debugging() > 0 ) then
|
||||||
@@ -82,6 +90,12 @@ local function enum_protocols(host, port)
|
|||||||
table.insert(res_proto, ("%s: FAILED"):format(k))
|
table.insert(res_proto, ("%s: FAILED"):format(k))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
-- rdpNegData, which contains the negotiaion response or failure,
|
||||||
|
-- is optional. WinXP SP3 does not return this section which means
|
||||||
|
-- we can't tell if the protocol is accepted or not.
|
||||||
|
table.insert(res_proto, ("%s: Unknown"):format(k))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
table.sort(res_proto)
|
table.sort(res_proto)
|
||||||
return true, res_proto
|
return true, res_proto
|
||||||
@@ -105,6 +119,7 @@ local function enum_ciphers(host, port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
local res_ciphers = {}
|
local res_ciphers = {}
|
||||||
|
local proto_version
|
||||||
|
|
||||||
local function get_ordered_ciphers()
|
local function get_ordered_ciphers()
|
||||||
local i = 0
|
local i = 0
|
||||||
@@ -133,17 +148,19 @@ local function enum_ciphers(host, port)
|
|||||||
local status, response = comm:exch(msc)
|
local status, response = comm:exch(msc)
|
||||||
comm:close()
|
comm:close()
|
||||||
if ( status ) then
|
if ( status ) then
|
||||||
local enc_level = string.unpack("B", response.itut.data, 95 + 8)
|
if ( response.ccr and response.ccr.enc_cipher == v ) then
|
||||||
local enc_cipher= string.unpack("B", response.itut.data, 95 + 4)
|
|
||||||
if ( enc_cipher == v ) then
|
|
||||||
table.insert(res_ciphers, ("%s: SUCCESS"):format(k))
|
table.insert(res_ciphers, ("%s: SUCCESS"):format(k))
|
||||||
end
|
end
|
||||||
res_ciphers.name = ("RDP Encryption level: %s"):format(ENC_LEVELS[enc_level] or "Unknown")
|
res_ciphers.name = ("RDP Encryption level: %s"):format(ENC_LEVELS[response.ccr.enc_level] or "Unknown")
|
||||||
|
|
||||||
|
if response.ccr.proto_version then
|
||||||
|
proto_version = response.ccr.proto_version
|
||||||
|
end
|
||||||
elseif ( nmap.debugging() > 0 ) then
|
elseif ( nmap.debugging() > 0 ) then
|
||||||
table.insert(res_ciphers, ("%s: FAILURE"):format(k))
|
table.insert(res_ciphers, ("%s: FAILURE"):format(k))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true, res_ciphers
|
return true, res_ciphers, proto_version
|
||||||
end
|
end
|
||||||
|
|
||||||
action = function(host, port)
|
action = function(host, port)
|
||||||
@@ -154,12 +171,15 @@ action = function(host, port)
|
|||||||
return res_proto
|
return res_proto
|
||||||
end
|
end
|
||||||
|
|
||||||
local status, res_ciphers = enum_ciphers(host, port)
|
local status, res_ciphers, proto_version = enum_ciphers(host, port)
|
||||||
if ( not(status) ) then
|
if ( not(status) ) then
|
||||||
return res_ciphers
|
return res_ciphers
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(result, res_proto)
|
table.insert(result, res_proto)
|
||||||
table.insert(result, res_ciphers)
|
table.insert(result, res_ciphers)
|
||||||
|
if proto_version then
|
||||||
|
table.insert(result, proto_version)
|
||||||
|
end
|
||||||
return stdnse.format_output(true, result)
|
return stdnse.format_output(true, result)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user