1

I have the following task:

  • the command has to be run as root on server remotely in bash script over ssh and the command output has to be fetched in variable.
  • logging over ssh as root is disabled.
  • sudo on server is disabled, so I have to use su.
  • EDIT: since I want to make it as automated as possible in bash, the password has to be stored inside command

I have Googled for days, but it seems that I cannot find a solution for this.

Solution proposed here: ssh to server and switch user and change a directory

    ssh -t username@hostname "sudo su - otheruser -c \"cd /path/to/directory && command\""

does not work because sudo is disabled on server:

Does anyone have a solution to this?

  • 1
    To switch to another user, you need not use sudo su - username, you can plainly use su - username. – Mukesh Sai Kumar Apr 6 '18 at 16:55
  • Thanks for your answer @MukeshSaiKumar. Do you really think that I have "Googled for days" just to find "su" command? Also have you at least tried this? It is not working! – spaceman117X Apr 9 '18 at 7:26
  • su is already a setuid binary, so it must be able to switch to any user which you demand it to, with proper authentication. If su doesn't seem to be working, check if it has the setuid bit set. – Mukesh Sai Kumar Apr 21 '18 at 18:32
2

Perhaps somewhat off topic but this could be achieved with Python and the paramiko module:

#!/usr/bin/python2
import time
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('127.0.0.1', port=22, username='user', password='pass')

stdin, stdout, stderr = ssh.exec_command('su')
time.sleep(0.1) # some enviroment maybe need this.
stdin.write('root_password_goes_here\n')

[ add extra code here to execute a command ]

stdin.flush()
print (stdout.readlines())
ssh.close()

It should be noted that storing passwords in script generally is a bad idea from a security perspective. Make sure you have proper permissions set to the script (e.g. chmod 740)

  • Thanks! looks nice, I heard about paramiko but I have not used it so far. I will try this. I am always interested in trying some alternative methods. – spaceman117X Apr 9 '18 at 7:35
  • I just tried this. I put both regular user and root password. However, when I put touch /tmp/test/ into the [ add extra code here to execute a command ] line it looks like that /tmp/test is still owned by regular user and not root. I have also tried to do it in one line like this stdin, stdout, stderr = ssh.exec_command('su root -c "touch /tmp/test"') stdin.write('password\n') then /tmp/test is not created. Any ideas? – spaceman117X Apr 9 '18 at 9:49
  • When I'm home later today I will see what I can come up with for you. I should have something similar somewhere that you could use. – Jeroen Apr 9 '18 at 14:06
2

Login via SSH (as unprivileged user), then run the command su without any arguments to change to the root user. You will need the root password to do this. Then run whatever commands you want to run.
EDIT: If you want to do it in one line, you can use the following:
ssh username@hostname "su -c \"code_here\""
If this doesn't work, make sure the root password is enabled by running passwd as root. This will ask you for a new root password.
Extra: To run a command as another user besides root (Please note that this requires the target user's password):
ssh username@hostname "su - username_of_target -c \"code_here\""

  • Thanks for your answer @Giraffer and everyone who voted this up. Have you at least tried this? It is not working! it says: user@server ~ $ ssh admin@server "su - root -c \"code_here\""admin@server.com's password: su: must be run from a terminal Please do not post stuffs that are not checked. Everyone can copy/paste from google! – spaceman117X Apr 9 '18 at 7:30
  • I have checked, and it worked. No copy/paste from google here. Did you run passwd as root before hand? – Giraffer Apr 10 '18 at 2:28
  • The issue here can be different versions of the su command, as I found on another websites. But then I would need to upgrade su on all servers. Thats why python solution might be better and easier in this case. – spaceman117X Apr 10 '18 at 6:38
0

So, after 4 hours of additional web crawling, I finally made it! Big thanks for @jeroen-it-nerdbox for giving me insights on this:

Task was to take data from smartctl (which requires root credentials), from server with disabled ssh-root and disabled sudo. This will of course also work with sudo instead of su.

here is the full workable code in Python with Paramiko implementation.

#!/usr/bin/python2

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('rootserver.domain.com', port=22, username='admin', password='adminpass')

stdin, stdout, stderr = ssh.exec_command('/bin/su root -c "smartctl -a /dev/sda > /tmp/smartctl_output"', get_pty=True)
stdin.write('rootpass\n')

stdin.flush()
print (stdout.readlines())
ssh.close()
0

You can also used paramiko invoke shell command for interactive session. https://www.youtube.com/watch?v=lLKdxIu3-A4

enter code here

import paramiko
from paramiko.channel import Channel
import time
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('ip', port=22, username='non-root', password='non-root-password')

channel:Channel = ssh.invoke_shell()
print(type(channel))
channel_data = str()

while True:
   if channel.recv_ready():
       time.sleep(2)
       channel_data += str(channel.recv(999))
   else:
       continue

   channel.send("whoami\n")
   time.sleep(2)
   channel_data += str(channel.recv(999))

   channel.send("su\n")
   time.sleep(5)
   channel_data += str(channel.recv(999))

   # if "Password" in channel_data:
   channel.send("rootpaasword\n")
   time.sleep(2)
   channel_data += str(channel.recv(999))

   channel.send("whoami\n")
   time.sleep(2)
   channel_data += str(channel.recv(999))

   # channel_data += str(channel.recv(999))
   break

print(channel_data)

0

For somewhat less of a security nightmare than putting the root password in a script, you can use a setuid executable.

setuid executables are run as root, no matter which user executes them.

The main advantage of this is that if someone steals your laptop, they can run smartctl -a /dev/sda as root, but otherwise only has your user privileges. Or even less, if you set up a public key with a forced command as mentioned later.

Write a simple C program, smartctl_wrapper.c, that simply runs the script or program you need, like this:

#include <unistd.h>

int main() {
    //depending on your use case, you may want 
    //setuid(0), setgid(0), and/or setegid(0) here
    execl("/full/path/to/smartctl","smartctl","-a","/dev/sda",(char*) NULL);
}

And compile it as gcc smartctl_wrapper.c -o smartctl_wrapper.

You then make this belong to root, and the group that should be able to run it. These commands should be run as root:

chown root:some_group smartctl_wrapper

Then make it a setuid executable. Also prevent any user from editing it:

chmod 4510 smartctl_wrapper

This is now an executable that can be run by any member of some_group with root permissions, without requiring any password.

Now you can simply run it with ssh:

ssh user@server.domain /path/to/smartctl_wrapper

If the server allows it, you can set up the ssh connection with a public key to allow connections without a password. You can also use forced commands so that this key isn't good for anything besides running this script.

If the server does not allow it, you can instead make a script with the ssh password in it. In this case, I would highly recommend you make a new user just for this with minimal permissions and a login shell of /sbin/nologin.

Alternatively, for your specific use case it may make more sense to avoid running commands as root over ssh entirely. You could, for example, schedule this command to run periodically using cron. You can edit root's crontab with:

su -c crontab -e -u root

and adding the line:

5 0 * * sun smartctl -a /dev/sda >> /some/path/to/log/some/non/root/user/can/read

The line given will run the command once weekly, 5 minutes after midnight on Sunday. You can tweak this to your liking, following the directions in crontab(5).

Then you can use ssh just to read the logs.

0

you can do this simply like this in bash : that simulate human interaction with su. I use it on my automatic remote installers for servers that don't have sudo.

sucmd="sh -c 'sleep 3; echo $pass' | script -qc 'su -c ./yourscript.sh root '"

ssh -t -l "$user" "$ipaddress" -p 22 "$sucmd"

kind regards,

  • 1
    (1) What do you mean by “full bash”?  (2) Can you explain this?  Parts of it seem to be unnecessarily complicated. … … … … … … … … … … … … … … … … … Please do not respond in comments; edit your answer to make it clearer and more complete. – Scott Aug 7 at 3:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.