-
Notifications
You must be signed in to change notification settings - Fork 411
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add kernelCTF CVE-2023-4244_lts (#88)
- Loading branch information
Showing
8 changed files
with
1,119 additions
and
0 deletions.
There are no files selected for viewing
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,51 @@ | ||
# CVE-2023-4244 | ||
|
||
## Triggering the vulnerability | ||
|
||
First we create a `nft_table`. We add a `nft_chain` called `c_victim` which will be our UaF target object. | ||
|
||
Then we add `nft_chain` called `c_primitive`, which hosts a rule that host an `nft_immediate` expression which has `NFT_JUMP` verdict that jumps to `c_victim`. At this moment, `c_victim->use = 1`. | ||
|
||
We then add a `nft_set` with GC enabled, and GC interval set to `1`. Then we add a catchall element to the set that has `NFT_JUMP` verdict that jumps to `c_victim` and timeout set to `1`. At this moment, `c_victim->use = 2`. | ||
|
||
In the same transaction with the new catchall element, we immediately call delete on the `nft_set`, which will call `nft_map_deactivate` to deactivate all elements and will not remove them from the linked list. At this moment, `c_victim->use = 1`. | ||
|
||
After this, GC will most likely kicks in before transaction release phase worker does its job. GC will call `deactivate` on the expired elements that are still in the linked list. The catchall element we added before surely would be expired at this moment. `c_victim->use = 0` now. | ||
|
||
Because `c_victim->use = 0`, now we can delete `c_victim` while still having a reference to it from the immediate expression in a rule in `c_primitive` chain, thus achieving UaF condition. | ||
|
||
The vulnerable object is of type `nft_chain` which is in `kmalloc-cg-128` cache. | ||
|
||
## Leaking data from kernel memory | ||
|
||
After triggering the UaF, we have a dangling pointer to the freed `nft_chain` from a `nft_immediate` expression. | ||
|
||
We can use `DUMP` request on the rule hosting the expression to read a NULL-terminated string pointed to by `name` field of the `nft_chain` that the expression holds reference to. | ||
|
||
We will use heap spray to reclaim the freed `nft_chain` and control `name` field to leak kernel base and kernel heap. | ||
|
||
## Leaking kernel base address | ||
|
||
We trigger the UaF, then spray fake `nft_chain` objects using `nft_rule` objects. | ||
|
||
For each `nft_rule` we create, we add 9 `nft_notrack` expressions to the `nft_rule` so `nft_chain->name` will overlap with `ops` field of an expression, which is `nft_notrack_ops`. | ||
|
||
When we read from `name` field of the fake `nft_chain`, we will retrieve address of `nft_notrack_eval` function in the kernel, because `ops->eval` is the first field of `nft_notrack_ops` and it points to `nft_notrack_eval`. | ||
|
||
Most of the time the address will not contain NULL bytes so we can leak kernel base address. | ||
|
||
## Leaking kernel heap address | ||
|
||
First we trigger the UaF. For each spray iteration: | ||
|
||
- Create a `nft_set` | ||
- Create a `nft_rule`, add 5 `nft_notrack` expressions and 1 `nft_lookup` expression that binds to the `nft_set` we just created before, so `nft_chain->name` will overlap with `nft_lookup->binding.list.next` of `nft_lookup` expression, which points to the `nft_set`. This rule fits in `kmalloc-cg-128` cache and can be used to reclaim the freed `nft_chain` | ||
- If we only add one binding to the set, when leaking we will read the content of `nft_set->bindings.next`, which points to the lookup expression. So we add another binding to the linked list to leak `&nft_set->bindings` instead. We have to do this with a seperate `nft_rule because adding another lookup object to the same rule above will make the rule bigger than 128 bytes, which is the kmalloc cache that nft_chain objects belong to | ||
|
||
After spraying, we try to leak the address of `&nft_set->bindings`. Sometimes it will fail due to NULL bytes so we have to try the whole process again. | ||
|
||
## RIP control and getting root shell | ||
|
||
We delete all the `nft_set` we created before, then use Cross cache attack to reclaim the whole page that has been returned back to the page allocator. We will store a fake `nft_rule`, JOP gadget for stack pivot and ROP chain which do `commit_creds(prepare_kernel_cred(0))`, `switch_task_namespaces(find_task_by_vpid(1), init_nsproxy)` then jump to KPTI trampoline to get back to userland. The fake `nft_rule` will host a fake `nft_expr` that has a fake `nft_expr_ops` that has `validate` function points to a JOP gadget. | ||
|
||
After setting up, we trigger the vulnerability again, spray fake `nft_chain` that has `rules.next` points to the fake rule we just set up in kernel heap, then trigger `validate` on the immediate expression holding the dangling pointer to the freed `nft_chain`. It will call `validate` on the fake chain we just sprayed, recursively call `validate` on the fake rule then `validate` on the fake expression, trigger the JOP gadget, pivot the stack and trigger the ROP chain, then spawn a root shell when getting back to userland. |
44 changes: 44 additions & 0 deletions
44
pocs/linux/kernelctf/CVE-2023-4244_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,44 @@ | ||
# CVE-2023-4244 | ||
|
||
In nftables we can create sets with timeout for elements. The sets will do GC after a controllable period. Normally if an element is manually released, the busy mark is set so GC won't catch them. | ||
|
||
However in commit `628bd3e49cba1c066228e23d71a852c23e26da73` (netfilter: nf_tables: drop map element references from preparation phase), new functions (`nft_map_*deactivate`) were introduced. | ||
|
||
These functions do the same job as (`nft_setelem_*deactivate`) functions in order to release references to external objects (chain, obj) when deleting the set, but with fewer checks and operations. | ||
|
||
They lack calls to `nft_set_elem_mark_busy` in order to tell GC not to catch the deactivated elements, so it is possible to trigger double deactivation of elements by calling `nft_map_*deactivate` then let GC do its job (which will deactivate expired elements) before the release phase of the transaction (where GC job will be stopped). | ||
|
||
## Requirements to trigger the vulnerability | ||
|
||
|Capabilities|Kernel configuration|Are user namespaces needed?| | ||
|---|---|---| | ||
|CAP_NET_ADMIN|CONFIG_NF_TABLES|Yes| | ||
|
||
## Commit which introduced the vulnerability | ||
|
||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=628bd3e49cba1c066228e23d71a852c23e26da73 | ||
|
||
## Commit which fixed the vulnerability | ||
|
||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3e91b0ebd994635df2346353322ac51ce84ce6d8 | ||
|
||
## Affected kernel versions | ||
|
||
- 6.5-rc1 - 6.5-rc5 | ||
- 6.4 - 6.4.10 | ||
- 6.3.10 - 6.3.13 | ||
- 6.1.36 - 6.1.55 | ||
- 5.15.121 - 5.15.133 | ||
- 5.10.188 - 5.10.197 | ||
|
||
## Affected component, subsystem | ||
|
||
netfilter/nf_tables | ||
|
||
## Cause | ||
|
||
Use-after-free | ||
|
||
## Which syscalls or syscall parameters are needed to be blocked to prevent triggering the vulnerability? | ||
|
||
Disable the ability to communicate with nf_tables subsystem under unprivileged user namespace, or prevent creation of unprivileged user namespace. |
9 changes: 9 additions & 0 deletions
9
pocs/linux/kernelctf/CVE-2023-4244_lts/exploit/lts-6.1.36/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 @@ | ||
CFLAGS=-std=gnu17 -Wall -O0 -Ldeps/lib -lnftnl -lmnl -Ideps/include -static | ||
|
||
.PHONY: exploit | ||
|
||
exploit: | ||
tar -xzf deps.tar.gz && $(CC) -o exploit exploit.c $(CFLAGS) && rm -rf deps | ||
|
||
clean: | ||
rm -rf exploit && rm -rf deps |
Binary file not shown.
Binary file not shown.
Oops, something went wrong.