I want A user to do some jobs as B user. It's OK if B is root, but non-root user failed. Here are basic codes:
root.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
setuid( 0 );
system( "/tmp/script_of_root.sh" );
return 0;
}
script_of_root.sh:
#!/bin/sh
echo $RANDOM >> /tmp/file_of_root
playback:
$ cd /tmp
$ cc root.c -o root
$ su -
# chown root.root /tmp/root
# chmod 4755 /tmp/root
# exit
$ ./root
After executing "./root", file "/tmp/file_of_root" will be updated. But if I apply the same thing to a non-root user, it doesn't work. Codes:
foobar.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
setuid( 1001 ); // uid of user "foobar"
system( "/tmp/script_of_foobar.sh" );
return 0;
}
script_of_foobar.sh:
#!/bin/sh
echo $RANDOM >> /tmp/file_of_foobar
playback:
$ cd /tmp
$ cc foobar.c -o foobar
$ su -
# chown foobar.users /tmp/foobar
# chmod 4755 /tmp/foobar
# exit
$ ./foobar
If I run "./foobar" as other normal user(not "foobar" itself), it's gonna be error:
/tmp/script_of_foobar.sh: line 2: file_of_foobar: Permission denied
I am totally confused. Why the second scenario not working?
Best regards.
The setuid call in foobar.c will only succeed if you are root, or your effective UID is 1001.
So. If you're not root, setuid(1001) will fail, and you won't have the required rights to overwrite the file owned by "foobar".
From the output it looks like your non-root user is able to execute script_of_foobar.sh, but unable to write to /tmp/file_of_foobar. Are the permissions on /tmp possibly off? I believe it should be set to 1777.
Related
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
I'm writing a simple program that is linked against libdevmapper. There's little documentation available for this library, so I'm using tools/dmsetup.c:_process_all as a reference. I'm also including the dm-ioctl.h header. Note that memory is allocated for dmt automatically.
#include <libdevmapper.h>
#include <sys/ioctl.h>
#include "dm-ioctl.h"
int main(void)
{
struct dm_task *dmt;
if (!(dmt = dm_task_create(DM_LIST_DEVICES)))
return 1;
if (!dm_task_run(dmt))
return 1;
return 0;
}
The code is simple enough, but dm_task_run fails:
# gcc -Wall -o dm-test dm-test.c -ldevmapper
# ./dm-test
Internal error: unknown device-mapper task -1053229822
None of the ioctl calls have failed:
# strace -y -e ioctl -o /dev/stdout ./dm-test 2>/dev/null
ioctl(3</dev/mapper/control>, DM_VERSION, {version=4.0.0, data_size=16384, flags=DM_EXISTS_FLAG} => {version=4.43.0, data_size=16384, flags=DM_EXISTS_FLAG}) = 0
+++ exited with 1 +++
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
I have a program write.c, which creates a new file. I compiled that through root user and set the sticky bit for setuid using chmod u+s write.
Now, if a user2 executes this program. A new file is created with the root as owner, why ? The owner of the file should be user2.
For that, I changed the uid using setuid() and seteuid() to user2. And then created the file. But this also creates the file with root as owner. I want to create the file as user2 as owner.
Post an mcve. What you describe works just fine on my system. This:
#!/bin/sh -e
cat > main.c <<EOF
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
int fd;
uid_t ruid,euid,suid;
struct stat sb;
getresuid(&ruid,&euid,&suid);
printf("ruid=%ld euid=%ld suid=%ld\n", (long)ruid,(long)euid,(long)suid);
if(0>(fd = open(argv[1], O_CREAT|O_RDWR, 0660))){
perror(0);
exit(1);
}
fstat(fd,&sb);
printf("owner=%ld\n", (long)sb.st_uid);
close(fd);
seteuid(ruid);
getresuid(&ruid,&euid,&suid);
printf("ruid=%ld euid=%ld suid=%ld\n", (long)ruid,(long)euid,(long)suid);
if(0>(fd = open(argv[2], O_CREAT|O_RDWR, 0660))){
perror(0);
exit(1);
}
fstat(fd,&sb);
printf("owner=%ld\n", (long)sb.st_uid);
close(fd);
}
EOF
gcc main.c
sudo chown root a.out
sudo chmod u+s a.out
rm -f roots mine
./a.out roots mine
gets me:
ruid=1008 euid=0 suid=0
owner=0
ruid=1008 euid=1008 suid=0
owner=1008
i.e., the seteuid call succesfully resets my uid and the second file
is no longer owner by root.
Code
I wrote the following c program to print the real and effective uid:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
void main() {
printf("real uid: %d\n", (int) getuid());
printf("effective uid: %d\n", (int) geteuid());
}
I compiled it using gcc:
jazz#kryptonite beyond_basics $ gcc -o uid_demo.out uid_demo.c
Afterwards I changed owner and permissions as following:
jazz#kryptonite beyond_basics $ sudo chown root:root uid_demo.out
jazz#kryptonite beyond_basics $ sudo chmod u+s uid_demo.out
Result
Now I got:
jazz#kryptonite beyond_basics $ ll uid_demo.out
-rwsr-xr-x 1 root root 8712 Sep 8 18:12 uid_demo.out*
When running the program I get the following result:
jazz#kryptonite beyond_basics $ ./uid_demo.out
real uid: 1000
effective uid: 1000
Question
I would expect the effective uid to be 0.
Can anyone explain why it is not?
Thanks
It is surprising, isn't it?
It's worth checking the mount options on your filesystem - it may have been mounted with the nosuid option. To inspect the options, try running the mount command, or cat /proc/mounts.
(I'm sure you know which filesystem you are in, but for completeness, if you are cd'ed there, as per your example, you can use df . )