Is this script safe? - security

I need to execute some server tasks. Now I heard many many times this is very insecure. This is my solution:
Added this line to sudoers:
www-data ALL=NOPASSWD: /var/private-www/bin/webadmin (Not accessible through web)
Created this script var/private-www/bin/webadmin:
# Script for executing server tasks.
#
# Arguments:
# - Password Required for authentication, not all scripts may run this file
# - Action Action to execute
# Exit codes:
# 0 Failed
# 1 Success
# First of all check the password
if [ $1 = "secretpassword" ]
then
whoami
exit 1
else
echo "No access"
exit 0
fi
The file has these rights:
0111
SSH access is only enabled for one account. So nobody can execute the script, except me (and www-data). www-data can now access this file by doing:
exec('/usr/bin/sudo /var/private-www/bin/webadmin secretpassword', $output, $status);
Is this safe enough? How can I make it more secure?

I'm thinking that if your Apache server gets cracked, someone could access that script and execute it, but I might be wrong.
I've came across a resource you might want to read about, especially when it comes to restricting your script to your internal network.
http://www.linuxsecurity.com/content/view/133913/171/
I hope this answers your question.

Related

How would you make a shell script to monitor mounts and log issues?

I am looking for a good way monitor and log mounts on a CentOS 6.5 box. Since I am new to Linux shell scripting I am somewhat at a loss as to if there is something that is already around and proven which I could just plug in or is there a good method I should direct my research toward to build my own.
In the end what I am hoping to have running is a check of each of the 9 mounts on the server to confirm they are up and working. If there is an issue I would like to log the information to a file, possibly email out the info, and check the next mount. 5-10 minutes later I would like to run it again. I know that probably this isn't needed but we are trying to gather evidence if there is an issue or show to a vendor that what they are saying is the issue is not a problem.
This shell script will test each mountpoint and send mail to root if any of them is not mounted:
#!/bin/bash
while sleep 10m;
do
status=$(for mnt in /mnt/disk1 /mnt/disk2 /mnt/disk3; do mountpoint -q "$mnt" || echo "$mnt missing"; done)
[ "$status" ] && echo "$status" | mail root -s "Missing mount"
done
My intention here is not to give a complete turn-key solution but, instead, to give you a starting point for your research.
To make this fit your precise needs, you will need to learn about bash and shell scripts, cron jobs, and other of Unix's very useful tools.
How it works
#!/bin/bash
This announces that this is a bash script.
while sleep 10m; do
This repeats the commands in the loop once every 10 minutes.
status=$(for mnt in /mnt/disk1 /mnt/disk2 /mnt/disk3; do mountpoint -q "$mnt" || echo "$mnt missing"; done)
This cycles through mount points /mnt/disk1, /mnt/disk2, and /mnt/disk3 and tests that each one is mounted. If it isn't, a message is created and stored in the shell variable status.
You will want to replace /mnt/disk1 /mnt/disk2 /mnt/disk3 with your list of mount points, whatever they are.
This uses the command mountpoint which is standard on modern linux versions. It is part of the util-linux package. It might be missing on old installations.
[ "$status" ] && echo "$status" | mail root -s "Missing mount"
If status contains any messages, they will be mailed to root with the subject line Missing mount.
There are a few different versions of the mail command. You may need to adjust the argument list to work with the version on your system.
done
This marks the end of the while loop.
Notes
The above script uses a while loop that runs the tests every ten minutes. If you are familiar with the cron system, you may want to use that to run the commands every 10 minutes instead of the while loop.

How to take away the 'execute' permission from the root user?

I'm asked to take away the permission for the root user to execute a bash script, is that even possible? Actually how would one take away any permissions from some user? with chmod I could modify it for the current logged in user, but not for root.
If you are simply looking for a small safeguard, an obstacle to accidentally running the script as root, write the script to voluntarily exit if run as root. Add the following to the beginning of the script:
if [[ $EUID == 0 ]]; then
printf 'Do not run this script as root\n' >&2
exit 1
fi
You can't do that, root can do everything. But there are some measures to make it difficult. You can use the following command in ext{2-4} filesystems:
chattr +i script.sh
Doing this the file can't be modified, but it can be unlocked using chattr -i script.sh
Other thing you can do is: Put the script you want unchangeable for root on remote server and mount it via NFS. If the server does not offer write permissions that locks out the local root account. Of course the local root account could just copy the files over locally, unmount the remote stuff, put the copy in place and change that.
You cannot lock out root from deleting your files. If you cannot trust your root to keep files intact, you are having a social problem, not a technical one.

User input during a systemctl/service call for CentOS?

Lets say I have a service (like rsyslog) that when I stop it, I want to log the reasoning behind someone shutting it down. Expressing this simply would be
systemctl start rsyslog
systemctl stop rsyslog
(Begin the prompt as to why a user is doing this after shutting down rsyslog)
#!/bin/bash
echo "you are shutting down the syslog service. Please state your name and reason."
read -p "[name?]" name && read -p "[reason?]" reason
logger $name:$reason
Modifying the Unit Files (located in /usr/lib/systemd/system/rsyslog.service), to include an ExecStop of the path to the script, I am able to run the above script. I know that the script is working as checking the log messages shows a :, the nonvariable portion that was passed to logger.
I need to be able to have this script operate like said shell script the instant someone attempts to shutdown the logging service. This means that echo commands are shown on the terminal and variables can be recorded using the read command.
This may be similar to this persons question, but I can not understand it.
Thanks to Mark Stosberg for sharing information about the systemd-ask-password command that takes user input during a systemctl call.
For those unaware, the systemd-ask-password command is a password prompt that's available for all machines sponsoring the systemd service. A unique feature of this command is the fact it can allow for user input during a systemctl/service call. Knowing this, one can prompt for as much data as they like which integrates perfectly into standard bash scripts, allowing for the interaction that may or may not be needed during a call.
Here is an example script:
#!/bin/bash
date=$(/bin/date)
echo "Rsyslog has been turned off at $date. Below is the name and reason"
name=`systemd-ask-password --echo --no-tty "name:"`
reason=`systemd-ask-password --echo --no-tty "reason for shutting down rsyslog:"`
echo LOG:$name:$reason:ENDLOG >>/var/log/messages
You must make sure that when initializing any of your services you make changes to the unit files located in /usr/lib/systemd/system/ with an ExecStart, ExecStop, and so forth under the [Service] tag to equal the path to your scripts. You can find what other options you can here as well as some syntax, and tie in with the unit file as needed.

How can a BASH script automatically elevate to root on a remote server, without using sudoers nopasswd option?

o's!
Maybe you can help me with this. I can't find an answer to my specific questions, because there is an obvious solution which I'm not allowed to use. But first things first, the context:
In my company, which is a service provider, we administrate a bunch of
Linux servers. Some of my colleagues has for a long time been running
a BASH script from a source server, that then performs some tasks over
SSH on a number of remote Linux servers. The tasks it performs has to
be executed as root, so what the script does is it authorizes the
source server as root on the remote Linux servers via SSH (the remote
servers has the source servers public SSH key). Then what happened is
a new security policy was enforced and now root login over SSH is
denied. So the mentioned method no longer works.
The solution I keep finding, which we are by policy not allowed to do, is to create an entry in the sudoers file allowing sudo to root without password for the specific user.
This is the terms and they have to obey that. The only procedure that is allowed is to log on to the target server with your personal user, and then sudo su - to root WITH password.
Cocky as I apparently was, I said, "It should be possible to have the script do that automatically", and the management was like "Cool, you do it then!" and now I'm here at Stack Overflow,
because I know this is where bright minds are.
So this is exactly what I want to do with a BASH script, and I do not know if it's possible or how it's done, I really hope you can help me out:
Imagine Bob, he's logged into the source server, and he wants to
execute the script against a target server. Knowing that root over SSH
doesn't work, the authorization part of the script has been upgraded.
When Bob runs the script, it prompts him for his password. The
password is then stored in a variable (encrypted would be amazing) and
the script then logs on the target server as his user (which is
allowed) and then automatically elevates him to root on the target
server using the password he entered on the source server. Now the
script is root and it runs its tasks as usual.
Can it be done with BASH? and how?
UPDATE:
The Script:
## define code to be run on the remote system
remote_script='sudo -S hostname'
## local system
# on the local machine: prompt the user for the password
read -r -p "Enter password for $host: " password
# ...and write the password, followed by a NUL delimiter, to stdin of ssh
ssh -t 10.0.1.40 "$remote_script" < <(printf '%s\0' "$password")
The error:
[worker#source ~]$ sh elevate.sh
Enter password for : abc123
elevate.sh: line 10: syntax error near unexpected token `<'
elevate.sh: line 10: `ssh -t 10.0.1.40 "$remote_script" < <(printf '%s\0' "$password")'
First: Because it exposes plaintext passwords to the remote system (where they can be read by an attacker using diagnostic tools such as strace or sysdig), this is less secure than correctly using the NOPASSWD: flag in sudoers. If your security team aren't absolute idiots, they'll approve a policy exemption (perhaps with some appropriate controls, such as having a dedicated account with access to a setuid binary specific to the command being run, with authentication to that account being performed via public key authentication w/ the private key stored encrypted) rather than approving use of this hack.
Second: Here's your hack.
## define code to be run on the remote system
remote_script='sudo -S remote_command_here'
## local system
# on the local machine: prompt the user for the password
read -r -p "Enter password for $host: " password
# ...and write the password, followed by a NUL delimiter, to stdin of ssh
ssh "$host" "$remote_script" < <(printf '%s\0' "$password")
Allright, this is not the final answer, but I think I'm getting close, with the great help of CharlesDuffy.
So far I can run the script without errors on a remote server, that already has the publickey of my source server. However the command I execute doesn't create a file as I tell it to on the remote system.
However the script seems to run and the password seems to be accepted by the remote system.
Also I have to change in the sudoers on the remote host the line "Defaults requiretty" to "Defaults !requiretty", else it will tell me that I need a TTY to run sudo.
#!/bin/bash
## define code to be run on the remote system
remote_script='sudo -S touch /elevatedfile'
## local system
# on the local machine: prompt the user for the password
read -r -p "Enter password for $host: " password
# ...and write the password, followed by a NUL delimiter, to stdin of ssh
ssh -T 10.0.1.40 "$remote_script" < <(printf '%s\0' "$password")
UPDATE: When I tail /var/log/secure on the remote host I get the following after executing the script, which seems like the password is not being accepted.
May 11 20:15:20 target sudo: pam_unix(sudo:auth): conversation failed
May 11 20:15:20 target sudo: pam_unix(sudo:auth): auth could not identify password for [worker]
May 11 20:15:20 target sshd[3634]: Received disconnect from 10.0.1.39: 11: disconnected by user
May 11 20:15:20 target sshd[3631]: pam_unix(sshd:session): session closed for user worker
What I see on the source server, from where I launch the script:
[worker#source ~]$ bash elevate.sh
Enter password for : abc123
[sudo] password for worker:
[worker#source ~]$
Just make a daemon or cron script running as root, that in turn will check for any new scripts in specified secure location (ie. DB that it only has READ access to), and if they exist, it will download and execute them.

Running keychain as different user

In order to improve security a bit, I'd like to run the keychain agent as a different user. This shall prevent users who hijack my system from gaining the actual private key, while maintaining the ability to use it to authenticate ssh and scp connections.
What have I tried?
I created a user called agent who should store the private key and run the ssh-agent process. I created a script file to set up the right permissions for the socket:
#!/bin/sh
export EVAL=$(keychain --eval -q)
eval $EVAL
chmod 770 $(dirname $SSH_AUTH_SOCK) $(dirname $GPG_AGENT_INFO)
chmod 660 $SSH_AUTH_SOCK $(echo $GPG_AGENT_INFO | sed 's/:.*//')
echo $EVAL
And call that one in my .bashrc, eval'ing it.
But when I now connect to a server via ssh, I get
$ ssh server
Error reading response length from authentication socket.
Any hints?
keychain seems to use either an already running ssh-agent or gpg-agent, and start one if needed.
ssh-agent checks if the user id of the running process matches the id of the user connecting through the unix domain socket (with the exception of root). If you run the agent in debug mode you'll see the corresponding error message. In this case the socket is immediately closed, so you'll get the error message you mention above - you're probably using ssh-agent on your system. That means what you try to do won't be possible using ssh-agent (unless you don't modify it).
It should work if you use gpg-agent with the --enable-ssh-support option as replacement for ssh-agent, but you should be aware that this setup doesn't really increase security. With the permissions you're trying to set, it would allow every user that has access rights to the socket the to authenticate as you using the added key once it has been unlocked, so it's actually less secure.

Resources