Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address exception and decoding issue in rdp-enum-encryption #1611

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG
@@ -1,5 +1,9 @@
#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
file unless executed from a specific working directory. [nnposter]

Expand Down
54 changes: 54 additions & 0 deletions nselib/rdp.lua
Expand Up @@ -12,6 +12,20 @@ local stdnse = require("stdnse")
local string = require "string"
_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 = {

TPKT = {
Expand Down Expand Up @@ -57,8 +71,10 @@ Packet = {
itut.length, itut.code, pos = string.unpack("BB", data)

if ( itut.code == 0xF0 ) then
-- X.224 - Data TPDU (DT)
itut.eot, pos = string.unpack("B", data, pos)
elseif ( itut.code == 0xD0 ) then
-- X.224 - Connection Confirm (CC)
itut.dstref, itut.srcref, itut.class, pos = string.unpack(">I2I2B", data, pos)
end

Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -258,6 +306,10 @@ Response = {

cr.tpkt = Packet.TPKT.parse(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
end
}
Expand Down Expand Up @@ -333,6 +385,8 @@ Comm = {
return true, Response.ConnectionConfirm.parse(data)
elseif ( itut_code == 0xF0 ) then
return true, Response.MCSConnectResponse.parse(data)
elseif itut_code ~= nil then
stdnse.debug1(("comm:exch - Unknown itut_code: %s"):format(itut_code))
end
return false, "Received unhandled packet"
end,
Expand Down
58 changes: 39 additions & 19 deletions scripts/rdp-enum-encryption.nse
Expand Up @@ -15,14 +15,18 @@ http://labs.mwrinfosecurity.com/tools/2009/01/12/rdp-cipher-checker/
-- @output
-- PORT STATE SERVICE
-- 3389/tcp open ms-wbt-server
-- | rdp-enum-encryption:
-- | Security layer
-- | CredSSP: SUCCESS
-- | CredSSP (NLA): SUCCESS
-- | CredSSP with Early User Auth: SUCCESS
-- | Native RDP: SUCCESS
-- | RDSTLS: SUCCESS
-- | SSL: SUCCESS
-- | RDP Encryption level: High
-- | 40-bit RC4: SUCCESS
-- | 56-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"
Expand All @@ -46,7 +50,9 @@ local function enum_protocols(host, port)
local PROTOCOLS = {
["Native RDP"] = 0,
["SSL"] = 1,
["CredSSP"] = 3
["CredSSP (NLA)"] = 3,
["RDSTLS"] = 4,
["CredSSP with Early User Auth"] = 8
}

local ERRORS = {
Expand All @@ -71,16 +77,24 @@ local function enum_protocols(host, port)
return false, response
end

local success = string.unpack("B", response.itut.data)
if ( success == 2 ) then
table.insert(res_proto, ("%s: SUCCESS"):format(k))
elseif ( nmap.debugging() > 0 ) then
local err = string.unpack("B", response.itut.data, 5)
if ( err > 0 ) then
table.insert(res_proto, ("%s: FAILED (%s)"):format(k, ERRORS[err] or "Unknown"))
else
table.insert(res_proto, ("%s: FAILED"):format(k))
if response.itut.data ~= "" then
local success = string.unpack("B", response.itut.data)

if ( success == 2 ) then
table.insert(res_proto, ("%s: SUCCESS"):format(k))
elseif ( nmap.debugging() > 0 ) then
local err = string.unpack("B", response.itut.data, 5)
if ( err > 0 ) then
table.insert(res_proto, ("%s: FAILED (%s)"):format(k, ERRORS[err] or "Unknown"))
else
table.insert(res_proto, ("%s: FAILED"):format(k))
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
table.sort(res_proto)
Expand All @@ -105,6 +119,7 @@ local function enum_ciphers(host, port)
}

local res_ciphers = {}
local proto_version

local function get_ordered_ciphers()
local i = 0
Expand Down Expand Up @@ -133,17 +148,19 @@ local function enum_ciphers(host, port)
local status, response = comm:exch(msc)
comm:close()
if ( status ) then
local enc_level = string.unpack("B", response.itut.data, 95 + 8)
local enc_cipher= string.unpack("B", response.itut.data, 95 + 4)
if ( enc_cipher == v ) then
if ( response.ccr and response.ccr.enc_cipher == v ) then
table.insert(res_ciphers, ("%s: SUCCESS"):format(k))
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
table.insert(res_ciphers, ("%s: FAILURE"):format(k))
end
end
return true, res_ciphers
return true, res_ciphers, proto_version
end

action = function(host, port)
Expand All @@ -154,12 +171,15 @@ action = function(host, port)
return res_proto
end

local status, res_ciphers = enum_ciphers(host, port)
local status, res_ciphers, proto_version = enum_ciphers(host, port)
if ( not(status) ) then
return res_ciphers
end

table.insert(result, res_proto)
table.insert(result, res_ciphers)
if proto_version then
table.insert(result, proto_version)
end
return stdnse.format_output(true, result)
end