I have the following program:
$ cat cat.c
#include <err.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
char buf[32];
if(argc == 1) {
errx(1, "please specify an argument.");
}
sprintf(buf, "cat %s", argv[1]);
system(buf);
return 0;
}
$ gcc cat.c -o mycat
$ chmod +s mycat; sudo chown root mycat
$ ls -lth mycat
-rwsr-sr-x 1 root ... 11:12 mycat
$ ls -lth secret
-rw------- 1 root ... 11:10 secret
I thought ./mycat secret
should be able to read the secret file because mycat is a setuid program, and its owner is root
. However, here is what I get:
$ ./mycat secret
cat: secret: Permission denied
$ sudo chown user1 secret
$ ./mycat secret
4ea6f17dd6818
Anything I misunderstood?
This program demonstrates what's working and what doesn't :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char buf[64];
if (fork() == 0){
char *newargv[] = { "cat", argv[1], NULL };
execve("/usr/bin/cat", newargv, NULL); // This call directly `cat` without spawning a `shell`, so works as expected.
return 0;
}
sprintf(buf, "cat %s", argv[1]);
system(buf); // `system` spawns a shell which then calls `cat`, as the `shell` lost setuid privilaege, `cat` fails with `Permission denied`.
return 0;
}