xorl %eax, %eax

Archive for the ‘vulnerabilities’ Category

CVE-2017-17450: Linux kernel nfnl_osf security bypass

leave a comment »

This vulnerability is identical to CVE-2017-17448. It was reported by Kevin Cernekee and it affects the OSF nsfnetlink helper in the same way as CVE-2017-17448 affected the connection tracking helper of NetFilter. Basically, the lack of “CAP_NET_ADMIN” capability checks means that any unprivileged user can execute commands like the following to create or delete namespaces and also obtaining “CAP_NET_ADMIN” capability in the created ones.

    vpnns -- nfnl_osf -f /tmp/pf.os
    vpnns -- nfnl_osf -f /tmp/pf.os -d

Similarly to CVE-2017-17448, the fix was to add the missing checks in the add and remove functions as you can see below.

diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c
index 36e14b1..a34f314 100644
--- a/net/netfilter/xt_osf.c
+++ b/net/netfilter/xt_osf.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 
+#include <linux/capability.h>
 #include <linux/if.h>
 #include <linux/inetdevice.h>
 #include <linux/ip.h>
@@ -70,6 +71,9 @@ static int xt_osf_add_callback(struct net *net, struct sock *ctnl,
 	struct xt_osf_finger *kf = NULL, *sf;
 	int err = 0;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!osf_attrs[OSF_ATTR_FINGER])
 		return -EINVAL;
 
@@ -115,6 +119,9 @@ static int xt_osf_remove_callback(struct net *net, struct sock *ctnl,
 	struct xt_osf_finger *sf;
 	int err = -ENOENT;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!osf_attrs[OSF_ATTR_FINGER])
 		return -EINVAL;

Written by xorl

December 10, 2017 at 13:53

Posted in vulnerabilities

CVE-2017-17448: Linux kernel cthelper security bypass

leave a comment »

This is a vulnerability reported by Kevin Cernekee on 3 December 2017 and it affects nfnl_cthelper of NeFilter. The nfnl_cthelper is a connection tracking helper for the user-space and its code resides in net/netfilter/nfnetlink_cthelper.c. What Kevin Cernekee noticed is that nfnetlink_rcv() (located at net/netfilter/nfnetlink.c) checks if the caller has the “CAP_NET_ADMIN” permission capability but there is a design flaw.

static void nfnetlink_rcv(struct sk_buff *skb)
{
   ...
	if (!netlink_net_capable(skb, CAP_NET_ADMIN)) {
		netlink_ack(skb, nlh, -EPERM, NULL);
		return;
	}
   ...
}

This code checks for the “CAP_NET_ADMIN” capability only in the namespace that owns the “skb” socket. On the other hand, the nfnl_cthelper is a user-space helper that is shared by all network namespaces. Since there are no “CAP_NET_ADMIN” capability checks in nfnl_cthelper it means that an unprivileged user can create namespaces, bypassing the “CAP_NET_ADMIN” capability check. Kevin Cernekee’s patch for this vulnerability was to add the missing capability checks on the “new”, “get”, and “del” functions of this helper. You can see the patch here.

diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index 41628b393673..d33ce6d5ebce 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -17,6 +17,7 @@ 
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/errno.h>
+#include <linux/capability.h>
 #include <net/netlink.h>
 #include <net/sock.h>
 
@@ -407,6 +408,9 @@  static int nfnl_cthelper_new(struct net *net, struct sock *nfnl,
 	struct nfnl_cthelper *nlcth;
 	int ret = 0;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
 		return -EINVAL;
 
@@ -611,6 +615,9 @@  static int nfnl_cthelper_get(struct net *net, struct sock *nfnl,
 	struct nfnl_cthelper *nlcth;
 	bool tuple_set = false;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (nlh->nlmsg_flags & NLM_F_DUMP) {
 		struct netlink_dump_control c = {
 			.dump = nfnl_cthelper_dump_table,
@@ -678,6 +685,9 @@  static int nfnl_cthelper_del(struct net *net, struct sock *nfnl,
 	struct nfnl_cthelper *nlcth, *n;
 	int j = 0, ret;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (tb[NFCTH_NAME])
 		helper_name = nla_data(tb[NFCTH_NAME]);

Written by xorl

December 10, 2017 at 13:46

Posted in vulnerabilities

CVE-2017-17085: Wireshark CIP Safety dissector integer overflow

leave a comment »

On 30 November 2017 Wireshark released their WNPA-SEC-2017-49 security advisory. The security advisory describes a vulnerability in the CIP Safety protocol dissector which is identified as DoS. The vulnerability was discovered by “Buildbot Builder” via fuzzing and the trigger PoC PCAP is available online (fuzz-2017-11-28-28119.pcap). The vulnerable code is in epan/dissectors/packet-cipsafety.c and you can see the exact code path below.

/* packet-cipsafety.c
 * Routines for CIP (Common Industrial Protocol) Safety dissection
 * CIP Safety Home: www.odva.org
   ...
 */
   ...
static void
dissect_cip_safety_data( proto_tree *tree, proto_item *item, tvbuff_t *tvb, int item_length, packet_info *pinfo)
{
   int base_length, io_data_size;
   gboolean multicast = (((pntoh32(pinfo->dst.data)) & 0xf0000000) == 0xe0000000);
   ...
   /* compute the base packet length to determine what is actual I/O data */
   base_length = multicast ? 12 : 6;
   ...
      case CIP_SAFETY_EXTENDED_FORMAT:
         if (item_length-base_length <= 2)
         {
   ...
            proto_tree_add_item(tree, hf_cipsafety_crc_s5_0, tvb, item_length-base_length+1, 1, ENC_LITTLE_ENDIAN);
            proto_tree_add_item(tree, hf_cipsafety_crc_s5_1, tvb, item_length-base_length+2, 1, ENC_LITTLE_ENDIAN);
            proto_tree_add_item(tree, hf_cipsafety_timestamp, tvb, item_length-base_length+3, 2, ENC_LITTLE_ENDIAN);
            proto_tree_add_item(tree, hf_cipsafety_crc_s5_2, tvb, item_length-base_length+5, 1, ENC_LITTLE_ENDIAN);
   ...
}

As you can see from the above code snippet, dissect_cip_safety_data() retrieves a signed integer (item_length) as an argument. Later on, it calculates “base_length”. Then, if the packet is CIP Safety in extended format it will do the comparison that you see above. If “item_length” results in a negative value it will enter the ‘if’ clause and try to invoke proto_tree_add_item() with a negative length variable. The latter will try to copy a large amounts (specifically equal to “item_length”) of data leading to a segmentation fault due to memory corruption. Below you can see the patch that Pascal Quantin developed to fix this vulnerability.

     /* compute the base packet length to determine what is actual I/O data */
     base_length = multicast ? 12 : 6;
	 
+    if (item_length <= base_length) {
+       expert_add_info(pinfo, item, &ei_mal_io);
+       return;
+    }
+

The above ensures that “item_length” will never be smaller than “base_length” to enter the dissection code. This should catch cases of “item_length” being negative.

Written by xorl

December 10, 2017 at 13:28

Posted in vulnerabilities

CVE-2017-15868: Linux kernel l2cap BNEP privilege escalation

leave a comment »

The Linux kernel project patched a vulnerability discovered by Al Viro in the BNEP (Bluetooth Network Encapsulation Protocol) implementation of the Linux Bluetooth stack (BlueZ). The code for this is located at net/bluetooth/bnep/core.c and specifically in bnep_add_connection() that you see below.

int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
{
	struct net_device *dev;
	struct bnep_session *s, *ss;
	u8 dst[ETH_ALEN], src[ETH_ALEN];
	int err;

	BT_DBG("");

	baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
	baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);
   ...
}

The above is not immediately noticeable but “sock” is user derived and it is never verified until it’s used by baswap() to set the source and destination channels. You can see how l2cap_pi() macro is defined in include/net/bluetooth/l2cap.h header file here.

/* ----- L2CAP socket info ----- */
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)

And below is baswap() function which is available in net/bluetooth/lib.c source code file.

void baswap(bdaddr_t *dst, bdaddr_t *src)
{
	unsigned char *d = (unsigned char *) dst;
	unsigned char *s = (unsigned char *) src;
	unsigned int i;

	for (i = 0; i < 6; i++)
		d[i] = s[5 - i];
}

The above means that a malicious user can set an invalid “socK” pointer which can point to malicious callback functions that can be exploited to result in privilege escalation. The patch was to ensure that before “sock” is used it is checked by l2cap_is_socket() function as you can see in the following patch. If the check fails it will return “EBADFD” (File descriptor in bad state).

diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 85bcc21..ce82722d 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -533,6 +533,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
 
 	BT_DBG("");
 
+	if (!l2cap_is_socket(sock))
+		return -EBADFD;
+
 	baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
 	baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);

To better understand this check you can see l2cap_is_socket() routine as defined in net/bluetooth/l2cap_sock.c below. What it does is ensuring that “sock” is not NULL and that “sock->ops” callback functions point to the “l2cap_sock_ops” structure.

bool l2cap_is_socket(struct socket *sock)
{
	return sock && sock->ops == &l2cap_sock_ops;
}
EXPORT_SYMBOL(l2cap_is_socket);

The vulnerable code is reachable via BNEPCONNADD IOCTL command. You can see the exact code path that leads to bnep_add_connection() below. As you can see there is no check on the socket that is passed from the user-space to the kernel via copy_from_user() function.

static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
   ...
	switch (cmd) {
	case BNEPCONNADD:
   ...
		if (copy_from_user(&ca, argp, sizeof(ca)))
			return -EFAULT;

		nsock = sockfd_lookup(ca.sock, &err);
   ...
		ca.device[sizeof(ca.device)-1] = 0;

		err = bnep_add_connection(&ca, nsock);
   ...
}

Written by xorl

December 7, 2017 at 22:40

Posted in vulnerabilities

CVE-2017-3735: OpenSSL X.509 IPAddressFamily out-of-bounds read

leave a comment »

On 28 August 2017 the OpenSSL project released a security advisory security that affected all versions since 2006. The vulnerability was discovered by OSS-Fuzz fuzzer and it was fixed by Rich Salz of the OpenSSL development team. The vulnerable code was in crypto/x509v3/v3_addr.c in the function you see below.

/*
 * Extract the AFI from an IPAddressFamily.
 */
unsigned int X509v3_addr_get_afi(const IPAddressFamily *f)
{
    return ((f != NULL &&
             f->addressFamily != NULL && f->addressFamily->data != NULL)
            ? ((f->addressFamily->data[0] << 8) | (f->addressFamily->data[1]))
            : 0);
}

As its name suggests, this routine is designed to extract the AFI (Address Family Identifier) from the IP “addressFamily” element from a X.509 certificate. You can see how this structure is defined in include/openssl/x509v3.h header file below.

typedef struct IPAddressFamily_st {
    ASN1_OCTET_STRING *addressFamily;
    IPAddressChoice *ipAddressChoice;
} IPAddressFamily;

If we check back the code from X509v3_addr_get_afi() we will see that when it’s not returning zero it does the following. Check if “f” is not NULL, check if “f->addressFamily” is not NULL, check if “f->addressFamily->data” is not NULL and then return the AFI based on the data in “f->addressFamily->data[0]” and “f->addressFamily->data[1]”. This seems to have been catching all of the cases but it actually misses one. What if the length of the ASN.1 octet is only one byte? In this case the access to “f->addressFamily->data[1]” will result in an out-of-bounds read by one byte. Below you can see the patch that adds another check which ensures that the “f->addressFamily->length” is not less than two.

@@ -84,10 +84,12 @@ static int length_from_afi(const unsigned afi)
  */
 unsigned int X509v3_addr_get_afi(const IPAddressFamily *f)
 {
-    return ((f != NULL &&
-             f->addressFamily != NULL && f->addressFamily->data != NULL)
-            ? ((f->addressFamily->data[0] << 8) | (f->addressFamily->data[1]))
-            : 0);
+    if (f == NULL
+            || f->addressFamily == NULL
+            || f->addressFamily->data == NULL
+            || f->addressFamily->length < 2)
+        return 0;
+    return (f->addressFamily->data[0] << 8) | f->addressFamily->data[1];
 }

This can be triggered via a X.509 certificate with IPAddressFamily extension having a malformed AFI (Address Family Identifier). The result of is most likely an erroneous certificate.

Written by xorl

December 4, 2017 at 22:50

Posted in vulnerabilities