SUID bit in linux, not working as it should - linux

I have a text file called Demo, which have write permission for the owner only.
I also have an executable file (here called demowr.bash) that will write to this Demo file, and because I want other users to use this program, I set the set-uid bit.
Here is what the ls -l is seen for the files.
-rw-r--r-- 1 Coder Coder 6 Oct 28 23:36 ./Demo
-rwsrwxr-x 1 Coder Coder 7472 Oct 28 23:27 ./demowr.bash*
If I execute the file as Coder, all is fine.
But if I run it as any other user, it does not work, saying that it does not have write permission.
I have used the following codes to the executable file and the text file:
chmod u+s ./demowr.bash
chmod o-w ./demowr.bash
chmod o-w ./Demo
chmod g-w ./Demo
Here is the contents of the demowr.bash file
#!/bin/bash
echo "$1">Demo
Why is that,that even when the s bit is set, I am unable to write when run as an another user?
PS
Linux ignores the setuid¹ bit on all interpreted executables (i.e.
executables starting with a #! line)
I also wrote a C program, to do the same thing. The result is the same, the access function is saying that write permission is not given.
Here is the C code:
#define FILENAME "./Demo"
int main(int argn, char *argv[])
{
int length = strlen(argv[1]);
if (access(FILENAME,W_OK) == -1){
printf("Error: You do now have write permission.\n");
return 1;
}
int fd = open(FILENAME,O_WRONLY);
write(fd,argv[1],length);
close(fd);
return 0;
}
When run as a non-owner, I am getting the error.
Error: You do now have write permission.

Related

Why the set-uid operation can't be used in an excutable file?

When learning the system security in the ubuntu 20.04 on the VMware, I tried the set-uid operation and found the fllowing question:
With the excutable file catcall compiled by the source code caltcall.c:
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[]){
char *cat = "/bin/cat";
if(argc < 2){
printf("please type a file name.\n");
return 1;
}
char *command = malloc(strlen(cat) + strlen(argv[1] + 2));
sprintf(command, "%s %s",cat, argv[1]);
system(command);
return 0;
}
I complete the set-uid operation through the following codes:
$ sudo chown root catcall
$ sudo chmod 4755 catcall
When excuting the excutable file catcall, I thought I can see the content of the file /etc/shadow, for the 'catcall' has been set to the Set-Uid programme.
But the operation is denied when trying to access the etc/shadow:
/bin/cat: /etc/shadow: Permission denied
Why did the set-uid operation failed?
Each process actually has two user ids, a real uid and an effective uid, see Difference between Real User ID, Effective User ID and Saved User ID. Normally they are equal. Setting the setuid bit causes the effective uid to be set to the owner of the binary upon exec, but the real uid remains unchanged, and will normally still be the uid of the user who actually ran the program.
So when your program starts, the effective uid will be root and the real uid will be dim_shimmer. Now you have chosen to try to start your program via system(), which executes the specified command using the shell. However, many shells have a security feature where they compare the real and effective uid, and if they are not equal, they set the effective uid equal to the real uid. (For instance, this avoids a disaster in case the sysadmin accidentally does chmod +s /bin/sh). I suspect that's what's happening here. So by the time your cat command runs, your real and effective uid are both dim_shimmer again, and that user does not have permission to read /etc/shadow.
If you run your cat command using execl instead (or one of its relatives), so as to bypass the shell, then I suspect you'll find that it works.

Unable to write on /dev/* files

I'm writing a basic char device driver for Linux kernel.
For this, the code flow I have considered is as follows:
alloc_chrdev_region() -> to use dynamic allocation of major number
class_create() -> to create device class in sysfs
device_creat() -> to create device under /dev/
cdv_init() -> to initialize char device structure
cdev_add() -> to add my device structure in kernel
I have added read, write, open, release methods in code.
When I try to read device file under /dev/ my read method is called.
But when I try to write on /dev/ file using echo it gives error
"bash: /dev/scull: Permission denied"
I have checked permissions of file using ls -l, and I have permissions to read or write on this file.
This problem occurs for every device driver module I have written. It works well in on another machine.
I'm working on ubuntu 15.10, custom compiled kernel 4.3.0
the result of ls -l /dev/scull:
crw------- 1 root root 247, 0 Dec 30 18:06 /dev/scull
the exact command I used to open the file
$ sudo echo 54 > /dev/scull
the source code for the open implementation
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){
pr_alert("Device Written\n");
return 0;
}
Behavior I'm seeking here is, I should be able to see 'Device Written' in dmesg ouput?
I assume that you are normally not root on your bash shell. Then this command line
sudo echo 54 > /dev/scull
does not what you think. The command is executed in two steps:
The bash setups the output redirection, i.e., it tries to open /dev/scull with the current user privileges.
The command sudo echo 54 is executed whereas stdout is connected to the file.
As you have no write-permissions as non-root user, the first step fails and the bash reports
"bash: /dev/scull: Permission denied"
You must already be root to setup the output redirection. Thus execute
sudo -i
which gives you an interactive shell with root privileges. The you can execute
echo 54 > /dev/scull
within that root shell.
I know the thread is too old to answer but just in case if someone wants to know alternative method without switching to root user, here is the solution:
sudo bash -c 'echo "54" > /dev/my_dev'
I wanted to note that on your system only root (file owner) has read / write permissions. Your (normal) user account has not! So another (fast) solution would be to give all users read / write permissions.
Probably this is not the safest solution! Only do this in your test environment!
sudo chmod a+rw /dev/scull
But now you test your module with your user account (without sudo)
echo "hello, world!" > /dev/scull
cat < /dev/scull
You can do so while going root with the command
sudo su
and then going into the /dev folder and enter your command (to save data into /dev/scull).
cd /dev
echo 54 > scull

How to make a fifo in C?

I have to use mkfifo in my C program in Ubuntu. But I have an error when I compile: no such file or directory .
I think the problem because I have not set the panel_fifo environment variables. But I don't khow how could I do this.
Here is my code I use to test this method:
char *myfifo="./sock/myfifo";
if (mkfifo(myfifo,0777)<0)
perror("can't make it");
if (fd=open(myfifo,O_WRONLY)<0)
perror("can't open it");
I compile this with:
gcc gh.c -o gh
When I run, I get this error message:
can't make it:no such file or directory
can't open it:no such file or directory
It's because the directory sock doesn't exist.
In a terminal:
christian#fujiu1404:~/tmp/t2$ ls
t2.c
christian#fujiu1404:~/tmp/t2$ cat t2.c
#include <fcntl.h>
main() {
int fd;
char *myfifo="./sock/myfifo";
if (mkfifo(myfifo,0777)<0)
perror("can't make it");
if (fd=open(myfifo,O_WRONLY)<0)
perror("can't open it");
}
christian#fujiu1404:~/tmp/t2$ cc t2.c
christian#fujiu1404:~/tmp/t2$ ./a.out
can't make it: No such file or directory
can't open it: No such file or directory
christian#fujiu1404:~/tmp/t2$ mkdir sock
christian#fujiu1404:~/tmp/t2$ ./a.out
Note the program hasn't completed, but your fifo does exist.
Now in a second terminal, put a string into the fifo
christian#fujiu1404:~/tmp/t2$ ls -l sock/
total 0
prwxrwxr-x 1 christian christian 0 May 27 06:45 myfifo
christian#fujiu1404:~/tmp/t2$ echo abc >sock/myfifo
Note echo also is suspended
Now in a third terminal, read from the fifo
christian#fujiu1404:~/tmp/t2$ cat sock/myfifo
abc
christian#fujiu1404:~/tmp/t2$
Note now all programs complete and exit (in all terminals)
You try
myfifo("./sock/myfifo", ...)
You get
no such file or directory
which is ENOENT.
You then want to look up the relevant documentation and find the following in man 3 mkfifo:
ERRORS
[...]
ENOENT A directory component in pathname does not exist or is a dangling symbolic link.
From all this one could conculde ./sock does not exist.

In Linux, does the location of an executable affect how the setuid bit is interpreted?

In a Linux system, does the permissions of the directory in which a setuid program resides affect how the kernel launches the process? The reason I ask is that when I compiled an identical setuid program in two different directories, it only actually assumed the user permissions in one directory. I compiled it in /tmp and /home/flag03 where flag03 is the user account that I am attempting to gain access to. When executed from /tmp it did not escalate privileges as expected, but it worked under /home.
Some background on the problem:
I'm working on level 03 of exploit-exercises.com/nebula. The exercise requires that you gain access to a flag03 user account. The exercise is setup so that the flag03 user is periodically running a cronjob which will allow you to execute a script in a specific directory. My plan was to write a simple bash script which will compile a setuid program that itself launches a bash shell, and then set the setuid bit with chmod +s. The idea is that when the setuid program is compiled, it is compiled by user flag03 via the cronjob. Once this newly compiled program is executed, it will launch a shell as user flag03, and that is the goal.
Here is the simple setuid program (l3.c, based on levels 1 + 2):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv, char **envp)
{
uid_t uid;
gid_t gid;
uid = geteuid();
gid = getegid();
setresuid(uid,uid,uid);
setresgid(gid,gid,gid);
printf("uid: %d\n", getuid());
printf("gid: %d\n", getgid());
system("/bin/bash");
return 0;
}
In order for this to work, a bash script compiles the program as user flag03 and then chmods the setuid bit.
#!/bin/bash
#gcc -o /tmp/l3 /tmp/l3.c
#chmod +s,a+rwx /tmp/l3
gcc -o /home/flag03/l3 /tmp/l3.c
chmod +s,a+rwx /home/flag03/l3
The executable generated in /tmp does not escalate privileges as expected, but the one generated in /home/flag03 works as expected.
NOTE I just created a new bash script to move the version of the setuid program that was compiled in /tmp to /home/flag03, and then reset the setuid bit. When executed from there, that version worked as well. So it appears to me that the permissions of the directory in which the setuid program resides has some kind of impact with how the process is launch. Maybe this is related to /tmp being a somewhat "special" directory?
Thanks for any interest in this long-winded question!
If the filesystem is mounted with the nosuid option, the suid bit will be ignored when executing files located there. As I understand it, /tmp is usually a separate filesystem (often tmpfs) mounted with the nosuid option. The motivation for this configuration is preventing a compromised account that has no writable storage except /tmp (e.g. nobody) from being able to produce suid binaries, which may be used in certain elaborate multi-step attacks to elevate privilege.

Allowing a non-root user to drop cache

I am carrying out performance tests on a system where I need to ensure I am reading data from the disk, and that it is not just cached (say from earlier tests). I read here that I can drop cache with the command
echo 3 | sudo tee /proc/sys/vm/drop_caches
However, note that even though my account is an admin account (login peter), it still requires my password. I want to be able to run this in a batch script without the requirement to input a password (as this is obviously manual)
More research led me to the sudoers file. My plan was to place the above command into a one line script called dropCache, and edit sudoers so that I could run it without entering a password. So I added the line
ALL ALL=(ALL)NOPASSWD:/home/peter/dropCache
at the end of my sudoers file (using visudo). With my admin account, if I run
sudo -l
I get
(ALL) NOPASSWD: /home/peter/dropCache
However, if I run my dropCache script I still get asked for my password
./dropCache
[sudo] password for peter:
Any help with this would be much appreciated. I am running Ubuntu 12.04
Thanks
Peter
What I did when I needed this was I wrote a small C program, changed the owner of the compiled file to root, and set the setuid bit.
Here is the source code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
extern void sync(void);
int main(void) {
if (geteuid() != 0) {
fprintf(stderr, "flush-cache: Not root\n");
exit(EXIT_FAILURE);
}
printf("Flushing page cache, dentries and inodes...\n");
// First: the traditional three sync calls. Perhaps not needed?
// For security reasons, system("sync") is not a good idea.
sync();
sync();
sync();
FILE* f;
f = fopen("/proc/sys/vm/drop_caches", "w");
if (f == NULL) {
fprintf(stderr, "flush-cache: Couldn't open /proc/sys/vm/drop_caches\n");
exit(EXIT_FAILURE);
}
if (fprintf(f, "3\n") != 2) {
fprintf(stderr, "flush-cache: Couldn't write 3 to /proc/sys/vm/drop_caches\n");
exit(EXIT_FAILURE);
}
fclose(f);
printf("Done flushing.\n");
return 0;
}
I tried this on Ubuntu 21.04 and it works:
Step 1: create a small script like below (assuming the name to be clear_drop_cacahes.sh):
#!/bin/sh
# Run a sync to reduce dirty caches
sync
# Tell the OS to clear caches
echo 3 > /proc/sys/vm/drop_caches
Step 2: make the script executable: chmod 744 clear_drop_caches.sh
Step 3: need to do this with someone with sudo right:
sudo visudo
Add the following line (to the end of the file)
ALL ALL=(ALL) NOPASSWD:/path-to-the-small-script/clear_drop_caches.sh
Step 4: now any user can run the drop caches script like below:
sudo /path-to-the-small-script/clear_drop_caches.sh
I am not sure about the security of doing something like this.

Resources