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-2023-3776 (cos & mitigation) #49

Merged
merged 16 commits into from
Jan 11, 2024

Conversation

d4em0n
Copy link
Contributor

@d4em0n d4em0n commented Sep 8, 2023

No description provided.

@d4em0n d4em0n changed the title Add kernelCTF CVE-2023-3776 Add kernelCTF CVE-2023-3776 (cos & mitigation) Sep 8, 2023
@d4em0n
Copy link
Contributor Author

d4em0n commented Nov 14, 2023

@koczkatamas we fix the comments already

Copy link
Collaborator

@koczkatamas koczkatamas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! I've made a few change request. Please take a look at the individual comments and make the changes accordingly. Thank you!

char *core = (void *)mmap((void *)0xa00000, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
strcpy(core, "|/proc/%P/fd/666"); // put payload string into known address which will used by ebpf shellcode

int sp = socket(0x10ul, 3ul, 0xc); // later use this socket to spray struct ctnetlink_filter
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use enum names instead of values (AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

0x0000000100000000, 0x0001000000010010,
0x0000000000000000};

size_t payment[] = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a more expressive variable name, for example netlink_filter_payload as there are multiple payloads are used in the exploit and it's easier to confuse them with eachother.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

0x0000000000000000};

size_t payment[] = {
0x0201010100000024, 0x0000000000000000, 0x0008000800000000, 0x0015000858df0300, 0x00feffff};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make a comment here how you generated this payload. Optionally if there is a documentation to this structure format, it can be added as well.

It seems IIUC that you are using CTA_MARK (0x08) and CTA_MARK_MASK (0x15) attributes to set ctnetlink_filter.mark field (at offset 0x60) to 0xfffffe000003df58 (with two uint32 writes).

Relevant pahole -EC ctnetlink_filter mitigation-6.1-v2/vmlinux:

struct ctnetlink_filter {
...
        struct ctnetlink_filter_u32 {
                /* typedef u32 -> __u32 */ unsigned int       val;                       /*    96     4 */
                /* typedef u32 -> __u32 */ unsigned int       mask;                      /*   100     4 */
        } mark; /*    96     8 */
...
};

Please add comment where the offset (0x60) and address (0xfffffe000003df58) comes from.

Relevant comment from the other exploit:

/* Try to overwrite struct drr_class's qdisc at offset 0x60 */
/* That address is at CPU#1 cpu_entry_area's entry_stack_page (stack address) while it try to push r15 in function error_entry*/
*(size_t*)&payload[0x60] = 0xfffffe000003df58;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


filter = kzalloc(sizeof(*filter), GFP_KERNEL);
...
err = ctnetlink_parse_zone(cda[CTA_ZONE], &filter->zone);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems (see my other ctnetlink_filter comment), that the payload is stored at offset 0x60 which is the mark field which comes from CTA_MARK and CTA_MARK_MASK and not CTA_ZONE or CTA_FILTER.

If the above is correct, then please update the writeup to correctly reference the relevant code path
(otherwise it is misleading):

	err = ctnetlink_filter_parse_mark(&filter->mark, cda);
	if (err)
		goto err_filter;

Please also mention that this technique requires CONFIG_NF_CONNTRACK_MARK (+CONFIG_NETFILTER_ADVANCED + CONFIG_NETFILTER) and allows 8-byte overwrite at offset 0x60.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Collaborator

@koczkatamas koczkatamas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! Thanks for the changes! Meanwhile I asked 3 additional questions (see below), please take a quick look, but otherwise looks good! Thanks!

```

#### For Mitigation instance
Because CONFIG_KMALLOC_SPLIT_VARSIZE is enable, we need to find a struct we can spray in kmalloc-128 fixed cache. We found out `struct ctnetlink_filter` is in the right cache. We can spray it and put payload.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you choose to use different method for LTS / COS too? This seems to be easier, wouldn't this work for LTS / COS too? Was this method discovered later?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I think it should work for COS too. it was discovered later. The thing is, this object is immediately freed in the same allocation path it will make somewhat unreliable than the sendmsg spray, but this is enough to overwrite the field that we want.

When packet sent to the network, it will enqueue to the network scheduler. If the packet match to our filter, then it will return our freed qdisc class.
Qdisc class object contain qdisc object which used to enqueue packets to the respective network interface via function pointer.

Snippet code if we use drr_class as target object as target object.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you choose to use drr_class and not one of the other "class" options?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the making of this exploit, we can choose another "class" with another size that fits into some fixed size objects for spray control, we found ctnetlink_filter in fixed size cache that fits with drr_class's size.

int n = 0x800;
setsockopt(sfd[i][1], SOL_SOCKET, SO_SNDBUF, (char *)&n, sizeof(n));
setsockopt(sfd[i][0], SOL_SOCKET, SO_RCVBUF, (char *)&n, sizeof(n));
write(sfd[i][1], buf, 0x1000);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this write call? What would happen differently if you don't make this call? Would the exploit still work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to make socket send buffer is full, so the kernel will sleep in the 2nd sendmsg call after it allocates spray object from msg control data.
https://elixir.bootlin.com/linux/latest/source/net/unix/af_unix.c#L1953

Copy link
Collaborator

@koczkatamas koczkatamas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks!

@koczkatamas koczkatamas merged commit 8342ff4 into google:master Jan 11, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants