-
Notifications
You must be signed in to change notification settings - Fork 524
kernelCTF: add CVE-2023-4623_mitigation #309
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
Open
4ab48b3f1ded2472
wants to merge
1
commit into
google:master
Choose a base branch
from
4ab48b3f1ded2472:CVE-2023-4623_mitigation
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
100 changes: 100 additions & 0 deletions
100
pocs/linux/kernelctf/CVE-2023-4623_mitigation/docs/exploit.md
This file contains hidden or 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,100 @@ | ||
| ## Setup | ||
|
|
||
| To trigger the vulnerability we need to create following configuration on the loopback interface: | ||
|
|
||
| ``` | ||
| qdisc hfsc 1: dev lo root refcnt 2 default 10 | ||
| class hfsc 1: root | ||
| class hfsc 1:1 parent 1: rt m1 2Kbit d 8us m2 800bit | ||
| class hfsc 1:10 parent 1:1 ls m1 2Kbit d 8us m2 800bit | ||
| class hfsc 1:2 parent 1: ls m1 2Kbit d 8us m2 800bit | ||
| ``` | ||
|
|
||
| Classes marked as 'ls' are link-sharing (have HFSC_FSC flag set) | ||
|
|
||
| The last class is not required for the actual triggering, but will help with the exploitation, as explained below. | ||
|
|
||
| ## Triggering the vulnerability | ||
|
|
||
| The first step is to send a packet on the loopback interface. There are no filters, so the packet will be classified to the default 1:10 class and enqueued there. | ||
| This will cause the class 1:10 to be inserted into the vttree of 1:1 and class 1:1 to be inserted into the vttree of the root class. | ||
| Then hfsc_dequeue() will be called and will call update_vf() which will remove class 1:10 from vttree of 1:1, but will skip 1:1 (no HFSC_FSC) flag, so 1:1 will remain in the vttree of the root class. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please show the necessary parts of |
||
|
|
||
|
|
||
| The second step is to remove classes 1:10 and 1:1. | ||
| Their removal will trigger freeing of the associated qdisc objects (after an RCU delay). | ||
|
|
||
| We then reclaim the freed qdisc memory using a netlink allocation primitive. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which cache we're in? Please mention this in writeup. |
||
| When a message is sent on a netlink socket (or any socket for that matter) a buffer for the message data is allocated using kmalloc(). | ||
| This primitive has an advantage of not having any reserved space at the beginning, which is important to us because qdisc object looks like this: | ||
| ``` | ||
| struct Qdisc { | ||
| int (*enqueue)(struct sk_buff *, struct Qdisc *, struct sk_buff * *); /* 0 0x8 */ | ||
| struct sk_buff * (*dequeue)(struct Qdisc *); /* 0x8 0x8 */ | ||
| unsigned int flags; /* 0x10 0x4 */ | ||
| ... | ||
| ``` | ||
|
|
||
|
|
||
| We need to control the first 16 bytes to get easy code execution. | ||
|
|
||
| Next, we delete class 1:2 and add a new 1:10 class. | ||
|
|
||
| Then we send another packet. It will get enqueued to the newly created 1:10 class and hfsc_dequeue() will be called. | ||
| hfsc_dequeue() calls vttree_get_minvt() to select the class for the packet to be dequeued from. | ||
| vttree_get_minvt() traverses the vttree starting from the qdisc's root and will find a pointer to the old 1:10 class that was freed. | ||
| The contents of that memory were not changed and it still has a pointer to the old qdisc, which is now replaced by our fake object. | ||
|
|
||
| That's why we needed the 1:2 class to be deleted - without this step, the new 1:10 class would get the same memory as the previously freed 1:10, fixing the dangling pointer. | ||
|
|
||
| ## Getting RIP control | ||
|
|
||
| After vttree_get_min_vt() returns the pointer to the freed class, qdisc_dequeue_peeked() will be called with the pointer to our fake object and eventually ->dequeue() function pointer will be called. | ||
|
|
||
| ## Pivot to ROP | ||
|
|
||
| When ->dequeue() is called, RDI contains a pointer to the qdisc object, which is under our control. | ||
|
|
||
| Following gadgets are used to transfer control to our ROP: | ||
|
|
||
| ``` | ||
| mov rax, qword ptr [rdi] | ||
| mov rbx, rdi | ||
| call __x86_indirect_thunk_rax | ||
| ``` | ||
|
|
||
|
|
||
| ``` | ||
| lea rsi, [rbx + 0x48] | ||
| test eax, eax | ||
| jg 0xffffffff81204d3a | ||
| mov rax, qword ptr [rbx + 0x30] | ||
| lea rdi, [rsp + 8] | ||
| call __x86_indirect_thunk_rax | ||
| ``` | ||
|
|
||
|
|
||
| ``` | ||
| push rsi | ||
| jmp qword ptr [rsi + 0x66] | ||
| ``` | ||
|
|
||
| and finally | ||
|
|
||
| ``` | ||
| pop rsp | ||
| ret | ||
| ``` | ||
|
|
||
| ### Second pivot | ||
|
|
||
| At this point we have full ROP, but there is not much space left, because most of our 512 byte buffer is taken by the skb_shared_info placed at the end. | ||
|
|
||
| To solve this we choose an unused read/write area in the kernel and use copy_user_generic_string() to copy the second stage ROP from userspace to that area. | ||
| Then we use a `pop rsp ; ret` gadget to pivot there. | ||
|
|
||
| ## Privilege escalation | ||
|
|
||
| The second stage of the ROP does the standard commit_creds(init_cred); switch_task_namespaces(pid, init_nsproxy); sequence and returns to the userspace. | ||
|
|
||
|
|
||
26 changes: 26 additions & 0 deletions
26
pocs/linux/kernelctf/CVE-2023-4623_mitigation/docs/vulnerability.md
This file contains hidden or 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,26 @@ | ||
| ## Requirements to trigger the vulnerability | ||
|
|
||
| - CAP_NET_ADMIN in a namespace is required | ||
| - Kernel configuration: CONFIG_NET_SCH_HFSC | ||
| - User namespaces required: Yes | ||
|
|
||
| ## Commit which fixed the vulnerability | ||
|
|
||
| https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b3d26c5702c7d6c45456326e56d2ccf3f103e60f | ||
|
|
||
| ## Affected kernel versions | ||
|
|
||
| Introduced in 2.6.3. Fixed in 6.1.52 and other stable trees. | ||
|
|
||
| ## Affected component, subsystem | ||
|
|
||
| net/sched: sch_hfsc | ||
|
|
||
| ## Description | ||
|
|
||
| HFSC is a classful scheduler and its classes can be created with different flags affecting the scheduler behaviour. | ||
|
|
||
| When a packet is enqueued to a class with the HFSC_FSC (link-sharing enabled) flag, the class is inserted into the parent class tree in init_vf()/vttree_insert(). | ||
| Normally, the parent also has the HFSC_FSC flag and the class is removed from the parent in the update_vf()/vttree_remove() during packet dequeue operation. | ||
| However, if the parent has no link-sharing flag it is skipped in tree traversal in update_vf() and the child class is still referenced in the parent tree. | ||
| If an attacker deletes the child class a use-after-free condition can be triggered during enqueue/dequeue operations. |
9 changes: 9 additions & 0 deletions
9
pocs/linux/kernelctf/CVE-2023-4623_mitigation/exploit/mitigation-6.1/Makefile
This file contains hidden or 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 @@ | ||
| INCLUDES = -I/usr/include/libnl3 | ||
| LIBS = -L. -pthread -lnl-cli-3 -lnl-route-3 -lnl-3 -ldl | ||
| CFLAGS = -fomit-frame-pointer -static -fcf-protection=none | ||
|
|
||
| exploit: exploit.c | ||
| gcc -o $@ exploit.c $(INCLUDES) $(CFLAGS) $(LIBS) | ||
|
|
||
| prerequisites: | ||
| sudo apt-get install libnl-cli-3-dev libnl-route-3-dev |
Binary file added
BIN
+1.43 MB
pocs/linux/kernelctf/CVE-2023-4623_mitigation/exploit/mitigation-6.1/exploit
Binary file not shown.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's break this paragraph into steps, so it's easier to figure out what we're trying to achieve:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the suggestion above and confirm if it represents situation correctly. If it's not really good, please add necessary details.