-
Notifications
You must be signed in to change notification settings - Fork 411
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-52620_lts_cos_mitigation #117
base: master
Are you sure you want to change the base?
Conversation
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.
Hey!
Thank you for your submission!
I've reviewed the submission, both the writeup and the code was very clear and readable, I consider this a high quality submission, congratulations!
I still requested few changes for extra details and some explanations - please see them below.
There should be 36 comments (don't worry, some of them are same just repeated for the 3 exploits), please make sure you open all comments as the Github UI only shows 10 comments by default.
}; | ||
``` | ||
|
||
When the vulnerability is triggered, the reference counter of `nft_chain` is decremented twice. Therefore, we used `immediate expr` to create a dangling pointer referencing this victim `nft_chain`. After binding `immediate expr` to the victim `nft_chain`, the dangling pointer is created by triggering the vulnerability to free the victim chain. The name of the freed chain can then be read through `immediate expr`. We spray `nft_expr` (`kmalloc-cg-16`) and `nft_rule` (`kmalloc-cg-96`) to the freed `chain->name` to read `nft_expr->ops` and `nft_rule->list` to get the kernel text address and heap address of `kmalloc-cg-96`. |
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 mention that immediate expr
is internally stored as a struct nft_expr
with the data
field containing a nft_immediate_expr
and the mentioned nft_chain
is reachable via nft_immediate_expr.data.verdict.chain
.
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.
I updated the description as you mentioned.
|
||
read(sock, buffer, 4); | ||
|
||
sleep(3); |
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 comment here what are you waiting for. Mention the name of the kernel function(s) you are waiting for to be ran and/or which objects to be freed.
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.
I removed it because it is unnecessary sleep.
err(1, "mnl_socket_send"); | ||
} | ||
|
||
usleep(10*1000); |
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 comment here what are you waiting for. Mention the name of the kernel function(s) you are waiting for to be ran and/or which objects to be freed.
|
||
del_chain(trig_chain_name); | ||
|
||
usleep(300*1000); |
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 comment here what are you waiting for. Mention the name of the kernel function(s) you are waiting for to be ran and/or which objects to be freed.
err(1, "mnl_socket_send"); | ||
} | ||
|
||
usleep(10*1000); |
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 comment here what are you waiting for. Mention the name of the kernel function(s) you are waiting for to be ran and/or which objects to be freed.
|
||
# Post-RIP | ||
|
||
The ROP payload is stored in `chain->blob_gen_0` allocated in `kmalloc-cg-192` and the leaked heap address allocated in `kmalloc-cg-96`. |
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.
Mention here that on COS kmalloc-cg-192
contains the fake chain->blob_gen_0
aka struct nft_rule_blob
including the fake struct nft_expr
with the ops
pointer pointing to the leaked kmalloc-cg-96
address and then the first part of the ROP chain. Also detail that kmalloc-cg-96
contains the fake struct nft_expr_ops
stored at the beginning and then the second part of the ROP chain.
Mention that where RBX
points to when eval()
is called. I think on LTS it points to the fake struct nft_expr
(so to kmalloc-cg-192
+ 0x08
), while on COS it seems to be pointing to kmalloc-cg-192
+ 0x00
.
Also detail the differences between the ROP chains on LTS and COS (as they are different).
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.
I updated the description as you mentioned.
int i = 0; | ||
|
||
// expr->ops->eval() | ||
data[i++] = kbase + PUSH_RBX_POP_RSP; |
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.
Rename PUSH_RBX_POP_RSP
to PUSH_RBX_POP_RBP_RSP
as it is important that we are jumping to rbx+0x08
(== nft_expr+0x08
== rop_chain_192+0x18
) here, not to rbx+0x00
.
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.
I renamed PUSH_RBX_POP_RSP
to PUSH_RBX_POP_RSP_RBP
because RSP
is popped first.
}; | ||
``` | ||
|
||
When the vulnerability is triggered, the freed `chain->blob_gen_0` can be accessed via `immediate expr`. |
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.
If I understand correctly you are keeping the freed nft_chain
in the freelist and its content is not overwritten, so the nft_chain.blob_gen_0
pointer still points to the freed nft_rule_blob
structure which can be reallocated by spraying structures into the right cache. Is this assumption correct? First it was not clear if you spray nft_rule_blob
or nft_chain
.
If it is, then please explain these details here.
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.
Yes, your understanding is right. I added an explanation as follows.
When the vulnerability is triggered, the freed chain->blob_gen_0
can be accessed via immediate expr
. We leave the chain freed and spray an object to create a fake blob in blob_gen_0
.
data[0] = kmalloc_192; | ||
data[1] = 0; | ||
|
||
spray_table(data, KMALLOC_32_SIZE); |
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.
Comment here what you are overwriting here in kmalloc-32-cg
and which step created that structure (add a comment to the step where you are creating that structure that this structure will get into kmalloc-32-cg
).
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.
I added a comment that it creates a fake nft_chain.rules_gen_0
.
} | ||
``` | ||
|
||
`chain->blob_gen_0` is used in `nft_do_chain`, and `expr->ops->eval` is called to evaluate the expression in `expr_call_ops_eval`. We set the ops of the fake expr to the leaked heap address (LTS, COS) or CPU entry area (mitigation) to control the RIP. For LTS and COS kernel, the fake blob object with the fake expr is allocated in `kmalloc-cg-192`. For mitigation kernel, we allocate the fake blob object larger than 0x2000 to use page allocator. |
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.
Make a comment somewhere why you chose kmalloc-cg-192
, if I understand correctly, you could've chosen different cache too.
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.
I added the details why I selected that slab cache.
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.
Sorry, one additional question about triggering the vuln.
} | ||
``` | ||
|
||
Then, when the gc is executed in `nft_set_commit_update`, `nft_trans_gc_catchall_sync` calls `nft_setelem_data_deactivate` to deactivate the objects mapped to the set element. As a result, the `nft_chain` or `nft_object` mapped to the set element can be deactivated twice. |
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.
Can you comment here more about how the reference counter changes of the nft_chain
object?
Let's consider the chain_leak
: you use for the immediate
expr, so the ref. counter becomes 1, then you set up the anonymous set and the lookup expression for the chain (ref count becomes 2), and then you wait for the timeout (ref count becomes 1) and then how the lookup expression is destroyed? Is it during the del_chain
call?
If yes, then the ref count becomes 0 at this point but the immediate
expr is still referencing the nft_chain
object?
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.
The set element in the victim set that the lookup expr is binding to, not the lookup expr, is referencing the chain. If the gc is executed while deleting the lookup expr (deleting the lookup expr deactivates the bound set if it is an anonymous set), the set element will be deactivated twice, decreasing the reference count of the victim chain to twice.
I added a description about this to the exploit.md
.
b2e2b9f
to
43a5a81
Compare
Hello, Thank you for reviewing my report and considering it as a high quality report. I've updated the write-up base on your comments. Please check it. Thanks |
No description provided.