From 95f9e2cf917afeac2b8113fe0e17c1abc57c36a8 Mon Sep 17 00:00:00 2001 From: tomsellers Date: Tue, 28 May 2019 23:01:21 +0000 Subject: [PATCH] Address rdp protocol parsing issues in rdp.lua and rdp-enum-ciphers.nse Closes #1611 --- CHANGELOG | 4 +++ nselib/rdp.lua | 54 ++++++++++++++++++++++++++++++ scripts/rdp-enum-encryption.nse | 58 ++++++++++++++++++++++----------- 3 files changed, 97 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2d14fe3e8..ad020e7dd 100644 --- a/CHANGELOG +++ b/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] diff --git a/nselib/rdp.lua b/nselib/rdp.lua index 32f098b57..9ec377a73 100644 --- a/nselib/rdp.lua +++ b/nselib/rdp.lua @@ -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 = { @@ -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 @@ -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(" 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) @@ -105,6 +119,7 @@ local function enum_ciphers(host, port) } local res_ciphers = {} + local proto_version local function get_ordered_ciphers() local i = 0 @@ -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) @@ -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