suid binary privilege escalation - linux

if /usr/bin/bash has the suid bit set
why does my euid change to root only when I use the -p option like so /usr/bin/bash -p
what does this -p option stand for?
and when you spawn a bash shell from a suid binary why euid is set to root and why not uid?

From the documentation:
-p
Turn on privileged mode. In this mode, the $BASH_ENV and $ENV files are not processed, shell functions are not inherited from the environment, and the SHELLOPTS, BASHOPTS, CDPATH and GLOBIGNORE variables, if they appear in the environment, are ignored. If the shell is started with the effective user (group) id not equal to the real user (group) id, and the -p option is not supplied, these actions are taken and the effective user id is set to the real user id. If the -p option is supplied at startup, the effective user id is not reset. Turning this option off causes the effective user and group ids to be set to the real user and group ids.
This is done because setuid shell scripts have been a common source of security bugs. So the programmer is required to use the -p option to indicate that they really need the privilege escalation, e.g. by using
#!/usr/bin/bash -p
Without this, setting the suid bit on /usr/bin/bash itself would be an enormous security hole, since most scripts don't take the necessary precautions needed when running with elevated permissions.

Related

"Permission denied" reading from a process-substitution FIFO in an unprivileged child process

Consider the following, observed with bash 4.4 on a Linux 3.19 kernel:
# in reality, this may access files "nobody" isn't allowed
get_a_secret() { printf '%s\n' "This is a secret"; }
# attach a process substitution reading the secret to FD 10
exec 10< <(get_a_secret)
# run a less-privileged program that needs the secret, passing it the file descriptor.
chpst -u nobody:nobody -- cat /dev/fd/10
...or the shorter/simpler:
chpst -u nobody:nobody -- cat <(get_a_secret)
Either fails in a manner akin to the following:
cat: /proc/self/fd/10: Permission denied
So, two branches to this question:
What's going on here?
Is there a way to get the desired behavior (passing the ability to read the secret through to the single child process being invoked in a way that doesn't persistently expose that secret to other processes running as "nobody") without exposing the FIFO's output to other processes?
(Yes, I'm well aware that I need to lock down ptrace and /proc/*/mem to prevent another process running as "nobody" from pulling the secret out of the client as it's being read; that said, that's (1) something I can do, and (2) when the process is only run before any potentially-attacker-controlled executables are invoked, less exposure than allowing any process running as nobody to pull the secret out of /proc/*/environ for the full duration of that process).
The following workaround avoids this issue:
exec 10< <(get_a_secret)
chpst -u nobody:nobody -- sh -c 'cat <&10'
Note the redirection being written as <&10 -- not </dev/fd/10 or </proc/self/fd/10 (on platforms which provide /dev/fd -- on platforms without this facility, bash rewrites it into a fdup2() call).
An answer with an explanation of the behavior (and perhaps a workaround that allows programs that don't accept a FD number as input to act on the read side?) would be in a position to supercede this one. :)

Difference between EUID and UID?

EUID is not the same as UID. At what context are these both are used in the script?
I tried to get the values by echo "UID is $UID and EUID is $EUID", but only space came as output. My machine runs Ubuntu 12.04 LTS. Seen at some sites that this is usually used to check whether it is root user and all but not able to get proper difference.
They're different when a program is running set-uid. Effective UID is the user you changed to, UID is the original user.
UID is the ID of the user that executed the program.
EUID (Effective UID) is the user ID the process is executing. Usually both are equal, unless using a program with SetUID to for example increase your privileges. A common case where UID and EUID are different would be executing sudo.
EUID and UID variables only work on bash, not in dash (in Debian based distros as Ubuntu sh is usually a symlink to dash).
If you are running the script interactively you might not have bash configured as your default shell, run bash before trying.
If you are running it from console:
bash script.sh
If you are running it using its path (for example ./script.sh) ensure the first line of the script is:
#!/bin/bash
And not:
#!/bin/sh
For a more generic way to do it -that works on any shell- check: https://askubuntu.com/questions/15853/how-can-a-script-check-if-its-being-run-as-root
In that post the command id is mentioned, where:
id -u # is the EUID
id -u -r # is the UID

Where can I set umask for system account?

I have created a system account that's used by some process specifically. I want to set umask 002 for it. For regular user account, I usually put configuration like this in .profile. This approach is not suitable for system account, as .profile is sourced at login and system account doesn't require login.
Where can I set umask 002 for system account?
On most Linux systems, it is usually set in /etc/profile, but it can also be set in /etc/bashrc.
The latter gets sourced for all bash script invocations, not just logins.
However, if the system process is not started from a bash script, then you'll need to use a PAM configuration.
edit /etc/profile and try this:
if [ `id -u` -eq $user_id_to _change ]; then
umask 002
else
umask 022
fi
of course you have to change $user_id_to_change to the user id of which you want to change the umask. than reboot.
this code snippet defenitly works with "normal" users. cant imagine, why this shouldnt work with system users.

running shell script on low privileged user

I have a requirement to run a java jar on a low privilege user on linux.
e.g. If I am currently logged in as a 'root' user and want to execute a shell script that should run with the privileges of a low privileged linux user like 'postix' user account.
Is it possible?
If yes, please post relevant references as I don't know how to do it.
Thanks in advance
Ashish
you can use the sudo command to run the script as another user.
If its set up properly, you can use it like this
sudo -u andrew myprog
will run myprog as the user andrew
Not sure what you mean by priority. If you think about scheduling priority, you can use the nice command to run the script with low priority on the CPU. Being logged as 'root' does not give any scheduling priority.
Besides this, it is always a bad idea to be logged in as 'root'.
I think sudo should do the trick .
You can also create script that will run your app change its owner and set suid bit for it
useful commands: chmode, chown

Best practice to run Linux service as a different user

Services default to starting as root at boot time on my RHEL box. If I recall correctly, the same is true for other Linux distros which use the init scripts in /etc/init.d.
What do you think is the best way to instead have the processes run as a (static) user of my choosing?
The only method I'd arrived at was to use something like:
su my_user -c 'daemon my_cmd &>/dev/null &'
But this seems a bit untidy...
Is there some bit of magic tucked away that provides an easy mechanism to automatically start services as other, non-root users?
EDIT: I should have said that the processes I'm starting in this instance are either Python scripts or Java programs. I'd rather not write a native wrapper around them, so unfortunately I'm unable to call setuid() as Black suggests.
On Debian we use the start-stop-daemon utility, which handles pid-files, changing the user, putting the daemon into background and much more.
I'm not familiar with RedHat, but the daemon utility that you are already using (which is defined in /etc/init.d/functions, btw.) is mentioned everywhere as the equivalent to start-stop-daemon, so either it can also change the uid of your program, or the way you do it is already the correct one.
If you look around the net, there are several ready-made wrappers that you can use. Some may even be already packaged in RedHat. Have a look at daemonize, for example.
After looking at all the suggestions here, I've discovered a few things which I hope will be useful to others in my position:
hop is right to point me back
at /etc/init.d/functions: the
daemon function already allows you
to set an alternate user:
daemon --user=my_user my_cmd &>/dev/null &
This is implemented by wrapping the
process invocation with runuser -
more on this later.
Jonathan Leffler is right:
there is setuid in Python:
import os
os.setuid(501) # UID of my_user is 501
I still don't think you can setuid
from inside a JVM, however.
Neither su nor runuser
gracefully handle the case where you
ask to run a command as the user you
already are. E.g.:
[my_user#my_host]$ id
uid=500(my_user) gid=500(my_user) groups=500(my_user)
[my_user#my_host]$ su my_user -c "id"
Password: # don't want to be prompted!
uid=500(my_user) gid=500(my_user) groups=500(my_user)
To workaround that behaviour of su and runuser, I've changed my init script to something like:
if [[ "$USER" == "my_user" ]]
then
daemon my_cmd &>/dev/null &
else
daemon --user=my_user my_cmd &>/dev/null &
fi
Thanks all for your help!
Some daemons (e.g. apache) do this by themselves by calling setuid()
You could use the setuid-file flag to run the process as a different user.
Of course, the solution you mentioned works as well.
If you intend to write your own daemon, then I recommend calling setuid().
This way, your process can
Make use of its root privileges (e.g. open log files, create pid files).
Drop its root privileges at a certain point during startup.
Just to add some other things to watch out for:
Sudo in a init.d script is no good since it needs a tty ("sudo: sorry, you must have a tty to run sudo")
If you are daemonizing a java application, you might want to consider Java Service Wrapper (which provides a mechanism for setting the user id)
Another alternative could be su --session-command=[cmd] [user]
on a CENTOS (Red Hat) virtual machine for svn server:
edited /etc/init.d/svnserver
to change the pid to something that svn can write:
pidfile=${PIDFILE-/home/svn/run/svnserve.pid}
and added option --user=svn:
daemon --pidfile=${pidfile} --user=svn $exec $args
The original pidfile was /var/run/svnserve.pid. The daemon did not start becaseu only root could write there.
These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
Some things to watch out for:
As you mentioned, su will prompt for a password if you are already the target user
Similarly, setuid(2) will fail if you are already the target user (on some OSs)
setuid(2) does not install privileges or resource controls defined in /etc/limits.conf (Linux) or /etc/user_attr (Solaris)
If you go the setgid(2)/setuid(2) route, don't forget to call initgroups(3) -- more on this here
I generally use /sbin/su to switch to the appropriate user before starting daemons.
Why not try the following in the init script:
setuid $USER application_name
It worked for me.
I needed to run a Spring .jar application as a service, and found a simple way to run this as a specific user:
I changed the owner and group of my jar file to the user I wanted to run as.
Then symlinked this jar in init.d and started the service.
So:
#chown myuser:myuser /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar
#ln -s /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar /etc/init.d/springApp
#service springApp start
#ps aux | grep java
myuser 9970 5.0 9.9 4071348 386132 ? Sl 09:38 0:21 /bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar

Resources