code | #
# (C) Tenable Network Security, Inc.
#
include("compat.inc");
if (description)
{
script_id(18405);
script_version("1.31");
script_cvs_date("Date: 2018/08/01 17:36:15");
script_cve_id("CVE-2005-1794");
script_bugtraq_id(13818);
script_name(english:"Microsoft Windows Remote Desktop Protocol Server Man-in-the-Middle Weakness");
script_summary(english:"Determines if the remote terminal service is vulnerable to MIM attacks");
script_set_attribute(attribute:"synopsis", value:
"It may be possible to get access to the remote host.");
script_set_attribute(attribute:"description", value:
"The remote version of the Remote Desktop Protocol Server (Terminal
Service) is vulnerable to a man-in-the-middle (MiTM) attack. The RDP
client makes no effort to validate the identity of the server when
setting up encryption. An attacker with the ability to intercept
traffic from the RDP server can establish encryption with the client
and server without being detected. A MiTM attack of this nature would
allow the attacker to obtain any sensitive information transmitted,
including authentication credentials.
This flaw exists because the RDP server stores a hard-coded RSA
private key in the mstlsapi.dll library. Any local user with
access to this file (on any Windows system) can retrieve the
key and use it for this attack.");
script_set_attribute(attribute:"solution", value:
"
- Force the use of SSL as a transport layer for this service if
supported, or/and
- Select the 'Allow connections only from computers running Remote
Desktop with Network Level Authentication' setting if it is available.");
script_set_cvss_base_vector("CVSS2#AV:N/AC:H/Au:N/C:P/I:P/A:P");
script_set_cvss_temporal_vector("CVSS2#E:U/RL:OF/RC:C");
script_set_attribute(attribute:"exploitability_ease", value:"No known exploits are available");
script_set_attribute(attribute:"exploit_available", value:"false");
script_set_attribute(attribute:"see_also", value:"http://www.oxid.it/downloads/rdp-gbu.pdf" );
# https://cloudblogs.microsoft.com/enterprisemobility/2008/07/21/configuring-terminal-servers-for-server-authentication-to-prevent-man-in-the-middle-attacks/
script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?8033da0d" );
script_set_attribute(attribute:"see_also", value:"http://technet.microsoft.com/en-us/library/cc782610.aspx" );
script_set_attribute(attribute:"plugin_publication_date", value:"2005/06/01");
script_set_attribute(attribute:"vuln_publication_date", value:"2005/05/28");
script_set_attribute(attribute:"plugin_type", value:"remote");
script_set_attribute(attribute:"cpe",value:"cpe:/a:microsoft:remote_desktop_connection");
script_set_attribute(attribute:"cpe",value:"cpe:/a:microsoft:windows_terminal_services_using_rdp");
script_end_attributes();
script_category(ACT_GATHER_INFO);
script_copyright(english:"This script is Copyright (C) 2005-2018 and is owned by Tenable, Inc. or an Affiliate thereof.");
script_family(english:"Windows");
script_dependencies("windows_terminal_services.nasl");
if ( NASL_LEVEL >= 3000 )script_dependencies("os_fingerprint_rdp.nbin", "fips_rdp.nbin", "rdp_credssp_detect.nbin");
script_require_ports("Services/msrdp", 3389);
exit(0);
}
include("global_settings.inc");
include("misc_func.inc");
include("byte_func.inc");
include("dump.inc");
# this plugin works only if the Standard (legacy) RDP security protocol is enabled
port = get_service(svc:'msrdp', default:3389, exit_on_fail:TRUE);
rdp_legacy = get_kb_item('msrdp/'+port+'/security_protocol/rdp_legacy');
if(!isnull(rdp_legacy) && rdp_legacy == FALSE)
exit(0,'RDP security layer is not enabled for service listening on port '+port+'.\n' +
'This plugin only checks for security settings applicable to RDP security layer.\n' +
'It\'s possible that only Network Level Authentication or SSL/TLS is enabled.');
set_byte_order(BYTE_ORDER_LITTLE_ENDIAN);
function reverse (s)
{
local_var tmp, i;
tmp = NULL;
for (i=strlen(s)-1; i>=0;i--)
tmp += s[i];
return tmp;
}
# function iso_send_connection_request [iso.c]
req1 = raw_string ( 0x03, 0x00, 0x00, 0x24, 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x43, 0x6F, 0x6F, 0x6B, 0x69, 0x65, 0x3A, 0x20, 0x6D,
0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3D, 0x6E, 0x65,
0x73, 0x73, 0x75, 0x73, 0x0D, 0x0A );
resp = raw_string (0x03, 0x00, 0x00, 0x0B, 0x06, 0xD0, 0x00, 0x00, 0x12, 0x34, 0x00);
# function sec_out_mcs_data [secure.c]
req2 = raw_string (
0x03, 0x00, 0x01, 0x96, 0x02, 0xF0, 0x80, 0x7F, 0x65, 0x82, 0x01, 0x8A, 0x04, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01,
0xFF, 0x30, 0x20, 0x02, 0x02, 0x00, 0x22, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02,
0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0xFF, 0xFF, 0x02, 0x02, 0x00, 0x02, 0x30, 0x20, 0x02, 0x02, 0x00,
0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00,
0x01, 0x02, 0x02, 0x04, 0x20, 0x02, 0x02, 0x00, 0x02, 0x30, 0x20, 0x02, 0x02, 0xFF, 0xFF, 0x02, 0x02, 0xFC, 0x17, 0x02,
0x02, 0xFF, 0xFF, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0xFF, 0xFF, 0x02,
0x02, 0x00, 0x02, 0x04, 0x82, 0x01, 0x17, 0x00, 0x05, 0x00, 0x14, 0x7C, 0x00, 0x01, 0x81, 0x0E, 0x00, 0x08, 0x00, 0x10,
0x00, 0x01, 0xC0, 0x00, 0x44, 0x75, 0x63, 0x61, 0x81, 0x00, 0x01, 0xC0, 0xD4, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x04,
0x00, 0x03, 0x01, 0xCA, 0x03, 0xAA, 0x09, 0x04, 0x00, 0x00, 0x28, 0x0A, 0x00, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00,
0x61, 0x00, 0x62, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x73, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xCA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0xC0, 0x0C, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x0C, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x72, 0x64,
0x72, 0x00, 0xC0, 0xA0, 0x00, 0x00
);
last_err = NULL;
for (i = 0; i < 3; i++)
{
if(i > 0 ) sleep(1);
if(soc) close(soc);
soc = open_sock_tcp (port,transport: ENCAPS_IP);
if (!soc) { last_err = "Can't open a socket on port " + port + "."; continue;};
# send X.224 connection request
send (socket:soc, data:req1);
buf = recv (socket:soc, length:11, timeout:60);
# hosts configured with NLA or set Security Layer to SSL/TLS should not respond.
# this hosts are not vulnerable to MiTM
if(isnull(buf))
{
last_err = 'The service listening on port '+port+' did not respond to an X.224 connection request.';
continue;
}
if (resp >!< buf)
exit (1,'The service listening on port '+port+' returned an unexpected X.224 connection confirm.' );
# send MCS Connect Initial
send (socket:soc, data:req2);
buf = recv (socket:soc, length:4096, timeout:60);
if(isnull(buf))
{
last_err = 'The service listening on port '+port+' did not respond to a MCS Connect Initial request.';
continue;
}
if ("RSA1" >!< buf)
exit (1, 'Data received from the remote host does not appear to contain a public key.');
blob = strstr (buf, "RSA1");
# extract key_blob
first = strlen(buf) - strlen(blob) - 16;
# get public key length
pubkey_len = getdword(blob:blob, pos:8) / 8;
end = first + 0x24 + pubkey_len + 7;
if (strlen(buf) < end)
exit (1,'The public key received from the remote host appears to be invalid.');
public_key = substr (buf, first, end);
# extract sig
sig = substr (buf, end+5, strlen(buf)-9);
if(COMMAND_LINE)
{
dump(ddata:blob, dtitle:"blob");
dump(ddata:public_key, dtitle:"public_key");
dump(ddata:sig, dtitle:"signature");
}
sig = reverse(s:sig);
e = raw_string ( 0x5B,0x7B,0x88,0xC0 );
e = reverse (s:e);
n = raw_string (0x3D,0x3A,0x5E,0xBD,0x72,0x43,0x3E,0xC9,0x4D,0xBB,0xC1,0x1E,0x4A,0xBA,0x5F,0xCB,
0x3E,0x88,0x20,0x87,0xEF,0xF5,0xC1,0xE2,0xD7,0xB7,0x6B,0x9A,0xF2,0x52,0x45,0x95,
0xCE,0x63,0x65,0x6B,0x58,0x3A,0xFE,0xEF,0x7C,0xE7,0xBF,0xFE,0x3D,0xF6,0x5C,0x7D,
0x6C,0x5E,0x06,0x09,0x1A,0xF5,0x61,0xBB,0x20,0x93,0x09,0x5F,0x05,0x6D,0xEA,0x87 );
n = reverse (s:n);
# signature should be the same size of n
if(strlen(sig) != strlen(n))
exit(1, "The length of the public key signature is not 64 bytes.");
hash = MD5 (public_key);
decrypted = rsa_public_decrypt(sig:sig,e:e,n:n);
decrypted = reverse (s:decrypted);
if (!decrypted)
exit (1, "Failed to decrypt the signature of the public key.");
if(COMMAND_LINE)
{
dump(ddata:hash, dtitle:"hash");
dump(ddata:decrypted, dtitle:"decrypted");
}
if (hash >< decrypted)
{
security_warning(port);
exit(0);
}
else
exit(1, "Failed to verify the signature of the public key.");
}
if (last_err != NULL) exit(1, last_err);
|