-
Notifications
You must be signed in to change notification settings - Fork 417
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-52620_lts_cos_mitigation (#117)
* Add kernelCTF CVE-2023-52620_lts_cos_mitigation * update exploit * update exploit * change Makefile * update exploit.md exploit.c * update exploit.md --------- Co-authored-by: Mingi Cho <[email protected]>
- Loading branch information
Showing
19 changed files
with
3,985 additions
and
0 deletions.
There are no files selected for viewing
401 changes: 401 additions & 0 deletions
401
pocs/linux/kernelctf/CVE-2023-52620_lts_cos_mitigation/docs/exploit.md
Large diffs are not rendered by default.
Oops, something went wrong.
131 changes: 131 additions & 0 deletions
131
pocs/linux/kernelctf/CVE-2023-52620_lts_cos_mitigation/docs/novel-techniques.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,131 @@ | ||
# Novel Techniques | ||
|
||
## Bypassing kernelCTF SLAB Mitigation Using Page Allocator | ||
|
||
The mitigation kernel in the kernelCTF applies three mitigations to SLAB: `CONFIG_SLAB_VIRTUAL`, `CONFIG_KMALLOC_SPLIT_VARSIZE` and `CONFIG_RANDOM_KMALLOC_CACHES`. These mitigations are applied in the `kmalloc_slab` when allocating objects using `kmalloc` [2]. | ||
|
||
```c | ||
static __always_inline | ||
void *__do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller) | ||
{ | ||
struct kmem_cache *s; | ||
void *ret; | ||
|
||
if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) { | ||
ret = __kmalloc_large_node(size, flags, node); // [1] | ||
trace_kmalloc(caller, ret, size, | ||
PAGE_SIZE << get_order(size), flags, node); | ||
return ret; | ||
} | ||
|
||
s = kmalloc_slab(size, flags); // [2] | ||
|
||
if (unlikely(ZERO_OR_NULL_PTR(s))) | ||
return s; | ||
|
||
ret = __kmem_cache_alloc_node(s, flags, node, size, caller); | ||
ret = kasan_kmalloc(s, ret, size, flags); | ||
trace_kmalloc(caller, ret, size, s->size, flags, node); | ||
return ret; | ||
} | ||
|
||
void *__kmalloc_node(size_t size, gfp_t flags, int node) | ||
{ | ||
return __do_kmalloc_node(size, flags, node, _RET_IP_); | ||
} | ||
EXPORT_SYMBOL(__kmalloc_node); | ||
|
||
void *__kmalloc(size_t size, gfp_t flags) | ||
{ | ||
return __do_kmalloc_node(size, flags, NUMA_NO_NODE, _RET_IP_); | ||
} | ||
EXPORT_SYMBOL(__kmalloc); | ||
``` | ||
However, slab uses a maximum size of 0x2000 (8192), so when `kmalloc` allocates an object with a size larger than 0x2000, it uses the `__kmalloc_large_node` to allocate the object [1]. | ||
```c | ||
/* | ||
* To avoid unnecessary overhead, we pass through large allocation requests | ||
* directly to the page allocator. We use __GFP_COMP, because we will need to | ||
* know the allocation order to free the pages properly in kfree. | ||
*/ | ||
static void *__kmalloc_large_node(size_t size, gfp_t flags, int node) | ||
{ | ||
struct page *page; | ||
void *ptr = NULL; | ||
unsigned int order = get_order(size); | ||
if (unlikely(flags & GFP_SLAB_BUG_MASK)) | ||
flags = kmalloc_fix_flags(flags); | ||
flags |= __GFP_COMP; | ||
page = alloc_pages_node(node, flags, order); | ||
if (page) { | ||
ptr = page_address(page); | ||
mod_lruvec_page_state(page, NR_SLAB_UNRECLAIMABLE_B, | ||
PAGE_SIZE << order); | ||
} | ||
ptr = kasan_kmalloc_large(ptr, size, flags); | ||
/* As ptr might get tagged, call kmemleak hook after KASAN. */ | ||
kmemleak_alloc(ptr, size, 1, flags); | ||
kmsan_kmalloc_large(ptr, size, flags); | ||
return ptr; | ||
} | ||
``` | ||
|
||
In `__kmalloc_large_node`, memory is allocated directly from the `page allocator` without using SLAB for optimization. Therefore, the above three mitigations do not apply to objects allocated in `__kmalloc_large_node`. | ||
|
||
```c | ||
static struct nft_rule_blob *nf_tables_chain_alloc_rules(unsigned int size) | ||
{ | ||
struct nft_rule_blob *blob; | ||
|
||
/* size must include room for the last rule */ | ||
if (size < offsetof(struct nft_rule_dp, data)) | ||
return NULL; | ||
|
||
size += sizeof(struct nft_rule_blob) + sizeof(struct nft_rules_old); | ||
if (size > INT_MAX) | ||
return NULL; | ||
|
||
blob = kvmalloc(size, GFP_KERNEL_ACCOUNT); // [3] | ||
if (!blob) | ||
return NULL; | ||
|
||
blob->size = 0; | ||
nft_last_rule(blob, blob->data); | ||
|
||
return blob; | ||
} | ||
``` | ||
The exploit uses a blob object from `nft_chain`, which can be allocated to arbitrary size by the user in `nf_tables_chain_alloc_rules` [3]. Therefore, we can bypass the mitigation, allocate a blob object larger than 0x2000 and spray it using another larger than 0x2000 object. | ||
```c | ||
static int ____sys_sendmsg(struct socket *sock, struct msghdr *msg_sys, | ||
unsigned int flags, struct used_address *used_address, | ||
unsigned int allowed_msghdr_flags) | ||
{ | ||
... | ||
} else if (ctl_len) { | ||
BUILD_BUG_ON(sizeof(struct cmsghdr) != | ||
CMSG_ALIGN(sizeof(struct cmsghdr))); | ||
if (ctl_len > sizeof(ctl)) { | ||
ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); // [4] | ||
if (ctl_buf == NULL) | ||
goto out; | ||
} | ||
err = -EFAULT; | ||
if (copy_from_user(ctl_buf, msg_sys->msg_control_user, ctl_len)) | ||
goto out_freectl; | ||
msg_sys->msg_control = ctl_buf; | ||
msg_sys->msg_control_is_user = false; | ||
} | ||
... | ||
``` | ||
|
||
We used `ctl_buf` from `____sys_sendmsg` to spray the chain's blob object. Since `ctf_buf` also allows the user to allocate objects of arbitrary size, we were able to allocate a size larger than 0x2000 `[4]`. |
12 changes: 12 additions & 0 deletions
12
pocs/linux/kernelctf/CVE-2023-52620_lts_cos_mitigation/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,12 @@ | ||
- Requirements: | ||
- Capabilities: CAP_NET_ADMIN | ||
- Kernel configuration: CONFIG_NETFILTER, CONFIG_NF_TABLES | ||
- User namespaces required: Yes | ||
- Introduced by: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=761da2935d6e18d178582dbdf315a3a458555505 (netfilter: nf_tables: add set timeout API support) | ||
- Fixed by: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e26d3009efda338f19016df4175f354a9bd0a4ab (netfilter: nf_tables: disallow timeout for anonymous sets) | ||
- Affected Version: v4.1-rc1 - v6.4-rc7 | ||
- Affected Component: net/netfilter | ||
- Cause: Use-After-Free | ||
- Syscall to disable: disallow unprivileged username space | ||
- URL: https://cve.mitre.org/cgi-bin/cvename.cgi?name=2023-52620 | ||
- Description: In the Linux kernel, the following vulnerability has been resolved: netfilter: nf_tables: disallow timeout for anonymous sets Never used from userspace, disallow these parameters. |
37 changes: 37 additions & 0 deletions
37
pocs/linux/kernelctf/CVE-2023-52620_lts_cos_mitigation/exploit/cos-105-17412.294.34/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,37 @@ | ||
LIBMNL_DIR = $(realpath ./)/libmnl_build | ||
LIBNFTNL_DIR = $(realpath ./)/libnftnl_build | ||
|
||
exploit: | ||
gcc -o exploit exploit.c -L$(LIBNFTNL_DIR)/install/lib -L$(LIBMNL_DIR)/install/lib -lnftnl -lmnl -I$(LIBNFTNL_DIR)/libnftnl-1.2.5/include -I$(LIBMNL_DIR)/libmnl-1.0.5/include -static -s | ||
|
||
prerequisites: libmnl-build libnftnl-build | ||
|
||
libmnl-build : libmnl-download | ||
tar -C $(LIBMNL_DIR) -xvf $(LIBMNL_DIR)/libmnl-1.0.5.tar.bz2 | ||
cd $(LIBMNL_DIR)/libmnl-1.0.5 && ./configure --enable-static --prefix=`realpath ../install` | ||
cd $(LIBMNL_DIR)/libmnl-1.0.5 && make | ||
cd $(LIBMNL_DIR)/libmnl-1.0.5 && make install | ||
|
||
libnftnl-build : libmnl-build libnftnl-download | ||
tar -C $(LIBNFTNL_DIR) -xvf $(LIBNFTNL_DIR)/libnftnl-1.2.5.tar.xz | ||
cd $(LIBNFTNL_DIR)/libnftnl-1.2.5 && PKG_CONFIG_PATH=$(LIBMNL_DIR)/install/lib/pkgconfig ./configure --enable-static --prefix=`realpath ../install` | ||
cd $(LIBNFTNL_DIR)/libnftnl-1.2.5 && C_INCLUDE_PATH=$(C_INCLUDE_PATH):$(LIBMNL_DIR)/install/include LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(LIBMNL_DIR)/install/lib make | ||
cd $(LIBNFTNL_DIR)/libnftnl-1.2.5 && make install | ||
|
||
libmnl-download : | ||
mkdir $(LIBMNL_DIR) | ||
wget -P $(LIBMNL_DIR) https://netfilter.org/projects/libmnl/files/libmnl-1.0.5.tar.bz2 | ||
|
||
libnftnl-download : | ||
mkdir $(LIBNFTNL_DIR) | ||
wget -P $(LIBNFTNL_DIR) https://netfilter.org/projects/libnftnl/files/libnftnl-1.2.5.tar.xz | ||
|
||
run: | ||
./exploit | ||
./exploit | ||
./exploit | ||
|
||
clean: | ||
rm -rf $(LIBMNL_DIR) | ||
rm -rf $(LIBNFTNL_DIR) | ||
rm -f exploit |
Binary file added
BIN
+924 KB
pocs/linux/kernelctf/CVE-2023-52620_lts_cos_mitigation/exploit/cos-105-17412.294.34/exploit
Binary file not shown.
Oops, something went wrong.