I'm experiencing a weird behavior regarding setuid()
and the setuid bit.
It seems like the suid bit and setuid() do not work as expected. I am expecting for a binary with +s and owned by uid 1001 that calls setuid(1001)
to be called from any uid and assume uid 1001 after the call. Yet, that only seems to work if either:
- +s is not set and the calling user is root
- +s is set and the binary belongs to root
I am expecting that I overlooked a detail, however I cannot find my error.
The end goal would be to have a binary that can be called from any user and assume a fixed uid. I do not want it to be owned by root, but by the user whose identity should be assumed (mainly because this is an exercise on stack smashing and that would allow a priv esc).
I created a minimal example to pin down my problems, and here it is:
Consider test.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
int main() {
int t = setuid(1001);
if (t < 0) {
perror("Error with setuid() - errno " + errno);
}
else {
printf("did work fine, look who I am:.\n");
system("/bin/bash -c whoami");
}
}
Also, passwd looks like this in the relevant parts:
test1:x:1000:1000::/home/test1:/bin/sh
test2:x:1001:1001::/home/test2:/bin/sh
Now, consider this output:
root@kali:/tmp/test# ls -la
total 12
drwxr-xr-x 2 root root 4096 Oct 24 09:53 .
drwxrwxrwt 18 root root 4096 Oct 24 09:52 ..
-rw-r--r-- 1 root root 304 Oct 24 09:51 test.c
root@kali:/tmp/test# gcc test.c -o test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# chown test2:test2 test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# chmod +s test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
root
root@kali:/tmp/test# su test1
$ ./test
did work fine, look who I am:.
test1
$
As you can see, there's no error showing, yet the desired uid is not assumed correctly. To add insult to injury, consider this:
root@kali:/tmp/test# chown root:root test
root@kali:/tmp/test# chmod +s test
root@kali:/tmp/test# ./test
did work fine, look who I am:.
test2
root@kali:/tmp/test# su test1
$ ./test
did work fine, look who I am:.
test2
So I guess my question is: what am I doing wrong? Why does setreuid()
work and setuid()
doesn't?
Other things I tried: Using execve()
, reproducing under ubuntu 18.04, using /bin/sh instead of /bin/bash.
-p
. Replace thesystem("/bin/bash -c whoami";)
with 'execl("/usr/bin/whoami","whoami",NULL);` and see if it helps. Typically you want to usesetreuid
rather thansetuid
.