setuid() C function changes euid value too? - c

This sample suid program
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void main() {
int ret;
printf("uid=%d, euid=%d\n", getuid(), geteuid());
ret = setuid(1000);
printf("uid=%d, euid=%d\n", getuid(), geteuid());
}
has 'noemi' (id=1001) as owner:
sarah-$ logname
sarah
sarah-$ ls -l p.bin
-rwsr-xr-x 1 noemi noemi 7028 17 dic 10.30 p.bin
If started from user 'sarah' (id=1000) euid changes to 1000
Why? p.bin changes only uid (this should have no effect, since uid was 1000 when p.bin was started by 'sarah'):
sarah-$ ./p.bin
uid=1000, euid=1001
uid=1000, euid=1000
sarah-$
I am using Debian 6 64 bit.
Please help me understand.
Thank you

Check man 2 setuid:
setuid() sets the effective user ID of the calling process. If the effective UID of the caller
is root, the real UID and saved set-user-ID are also set.
So, as you already have observed, when you are executing setuid() as regular user it will only change the effective user id.

Related

Not understanding setuid

I created a VERY simple script:
//#escalate.c - a setuid utility so that we can call shutdown
//# and other things safely without needing root access. We
//# do need to:
//# gcc escalate.c -o escalate.out
//# sudo chown root:root escalate.out
//# sudo chmod 4755 escalate.out
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
int main()
{
int status;
status = setuid( 0 ); // you can set it at run time also
system("date > /tmp/date.fil");
return errno;
}
On Raspian it generates the file in /tmp, owned by the root and returns 0 as expected.
On Ubuntu 22 it created the file owned by ME and the return status is 1. What am I missing about setuid(0); ?
I tried creating, modifying the permissions and ownership etc. On Raspian it works like a charm, on Ubuntu it does not.
==================
OK - solved it myself. On Ubuntu I was running with an encrypted home and so it was mounted with nosuid set.
the problem was that the file system was mounted nosuid

C cannot endors another user permissions using setresuid

I wrote the following code expecting to spawn a /bin/sh from another user.
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
setresgid(getegid(), getegid(), getegid());
setresuid(geteuid(), geteuid(), geteuid());
execve("/bin/sh", argv, envp);
return 0;
}
I then changed the owner to match with my target user and changed permissions (too much, I know)
chown usertarget:globalgroup ./shell
chmod 777 ./shell
chmod +s ./shell
ls -lah shell
Everything is fine according to me. However, It keeps opening a shell as my current user, not the target one.
I already tried to hardcode the userid of my target user and a few other things (setuid function, ...) but nothing seems to work...
Anyone has an idea or anything that could help me investigate this problem ?
EDIT #1
baseuser#machine:/tmp/tata$ ls -lah shell2
-rwsrwsrwx 1 targetuser globalgroup 7.2K Aug 18 18:21 shell2
baseuser#machine:/tmp/tata$ id
uid=1507(baseuser) gid=1314(globalgroup) groups=1314(globalgroup),100(users)
baseuser#machine:/tmp/tata$ ls -lah shell2
-rwsrwsrwx 1 targetuser globalgroup 7.2K Aug 18 18:21 shell2
baseuser#machine:/tmp/tata$ ./shell2
====== WELCOME USER ======
baseuser#machine:/tmp/tata$ id -a
uid=1507(baseuser) gid=1314(globalgroup) groups=1314(globalgroup),100(users)
baseuser#machine:/tmp/tata$
Well in facts, the parition was mounted with nosuid option. This can be checked through mount command

Why is effective UID still not 0?

So I got this code below from here. However when I follow the commands:
sudo chown root:root a.out
sudo chmod u+s a.out
It still won't run with effective uid to 0.
This is the code:
#define _POSIX_C_SOURCE 200112L // Needed with glibc (e.g., linux).
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void report (uid_t real) {
printf ("Real UID: %d Effective UID: %d\n", real, geteuid());
}
int main (void) {
uid_t real = getuid();
report(real);
seteuid(real);
report(real);
return 0;
}
The output is:
Real UID: 1000 Effective UID: 1000
Real UID: 1000 Effective UID: 1000
Where I supposed it should have been:
Real UID: 1000 Effective UID: 0
Real UID: 1000 Effective UID: 1000
The getuid function returns the real user id only. The real user id of user process is still 1000. The 1000 is stored in the real variable.
So, while calling of seteuid function you again sets the 1000 as the effective user id.But actually you have to set the 0 in that place. So only the effective user id doesn't changed.
Try the below it will works fine.
#define _POSIX_C_SOURCE 200112L // Needed with glibc (e.g., linux).
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void report (uid_t real) {
printf ("Real UID: %d Effective UID: %d\n", real, geteuid());
}
int main (void) {
uid_t real = getuid();
report(real);
seteuid(0);
report(real);
return 0;
}
Apparently as #MarkPlotnick said.
cd to the directory where that a.out is. Run df . to get the mount
point. Run mount | grep themountpoint and see what the filesystem type
and mount options are.
If there is something saying nosuid then you need to remount that part of filesystem without the nosuid flag.
This website here gives a good explanation about how to do that.

setuid() returns 0 but has no effect

I have the following code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void main(int argc, char* argv[]) {
printf("uid=%u euid=%u\n", getuid(), geteuid());
printf("%d = setuid(euid)\n", setuid(geteuid()));
printf("uid=%u euid=%u\n", getuid(), geteuid());
}
Compiled and run this way:
val#particle:/tmp $ sudo gcc foo.c
val#particle:/tmp $ sudo chown dev-misc:dev-misc a.out
val#particle:/tmp $ sudo chmod u+s a.out
val#particle:/tmp $ ./a.out
uid=1000 euid=1006
0 = setuid(euid)
uid=1000 euid=1006
Why does the uid remain unchanged? And why does setuid report success? (according to the man page, 0 means success)
setuid() sets the effective user ID, not the real process ID. From the manual:
setuid() sets the effective user ID of the calling process. If the
effective UID of the caller is root (more precisely: if the caller
has the CAP_SETUID capability), the real UID and saved set-user-ID
are also set.
To be able to change real user ID, the process must have effective user ID set to 0. Since, it's not the case in your example, it doesn't change. setuid() succeeds because you are just setting it to the same effective user ID the process already has.

Why my own suid-ed program still holds the original uid?

I'm using the following program, and I've suid-ed it (by running chown root XXX; chmod 4755 XXX as root), but the output is still ruid 1000, euid 1000, suid 1000, shouldn't effect uid be zero here?
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
int main()
{
uid_t ruid, euid, suid;
if (! getresuid (&ruid, &euid, &suid))
printf ("ruid %d, euid %d, suid %d\n", ruid, euid, suid);
else
perror ("getresuid");
return 0;
}
Output of ls -l:
-rwsr-xr-x 1 root root 9.7K May 1 11:36 test*
Please check the mount command output, your file system could be mounted with nosuid option.
From mount man page
nosuid: Do not allow set-user-identifier or set-group-identifier bits
to take effect.

Resources