I have a Python script which periodically pings machines in the network by using aioping to do it.
It requires raw socket access for the ICMP messages and one way to do this is to run the script as root, which I don't want to do.
What I've resorted to is the following:
sudo setcap cap_net_raw+ep /usr/bin/python3.8
python aio_pinger.py
where among the first lines in aio_pinger.py I call the following in order to remove cap_net_raw from the binary, but let the script still have the permissions:
import os
os.system('sudo setcap cap_net_raw-ep /usr/bin/python3.8')
This works.
The issue is that in this case, even if the script is no longer run as root, it still has root access via os.system. I need to run it as a user which can't use sudo.
When using protocols like TCP or UDP for listening, I can use something like authbind to grant normal users access to privileged ports. Is something like this possible with ICMP?
Ideally I'd just issue a command like authicmp python aio_pinger.py where I do some configuration beforehand.
An additional note: python in this case is python3 from a virtual environment. I've tried to sudo setcap cap_net_raw+ep venv/p3-pinger-2022-03-01/bin/python3, but this fails with the message
Failed to set capabilities on file
`venv/p3-pinger-2022-03-01/bin/python3' (Invalid argument)
The value of
the capability argument is not permitted for a file. Or the file is
not a regular (non-symlink) file
Is my only option to copy the python executable from /usr/bin/python3.8 into venv/p3-pinger-2022-03-01/bin/ and use setcap on that executable there, or is there some proper way of doing this?
Related
I am trying to automate a task through a Python script. The idea is to login as a regular user and then send a su command and switch to the root account.
The reason I can't directly login as root is that SSHD doesn't allow root logins.
Here's what I have:
ip='192.168.105.8'
port=22
username='xyz'
password='abc'
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip,port,username,password)
print ("SSH connection established")
stdin,stdout,stderr=ssh.exec_command('sudo fast.sh')
outlines=stdout.readlines()
outlines+=stderr.readlines()
resp=''.join(outlines)
print(resp)
Now, I want to send the su command and echo the root password. I am aware this is not good practice but I need a quick and easy way to test this so I am OK with that.
However, when I do this
stdin,stdout,stderr=ssh.exec_command('su') and provide the password, I get an error
su: must be run from a terminal
Can some one help me to solve this.
I am running Python script on my Windows laptop to ssh into a Linux device and then switch to the root user using the su command and echo the password so that I can run other commands as root.
Thanks.
First, as you know, automating su or sudo is not the correct solution.
The correct solution is to setup a dedicated private key with only privileges needed for your task. See also Allowing automatic command execution as root on Linux using SSH.
Anyway, your command fails because sudo is configured to require an interactive terminal with requiretty option in sudoers configuration file (as a way to deter its automation).
Paramiko (correctly) does not allocate a pseudo terminal for exec channel by default.
Either remove the requiretty option.
If you cannot remove it, you can force Paramiko to allocate pseudo terminal using get_pty parameter of exec_command method:
ssh.exec_command('sudo fast.sh', get_pty=True)
But that's not a good option, as it can bring you lot of nasty side effects. Pseudo terminal is intended for an interactive use, not for automating command execution. For some examples, see
Is there a simple way to get rid of junk values that come when you SSH using Python's Paramiko library and fetch output from CLI of a remote machine?
Remove of unwanted characters when I am using JSch to run command
Removing shell stuff (like prompts) from command output in JSch
I've written a python script. One of the functions opens a port to listen on. To open a port to listen on I need to do it as super user. I don't want to run the script with sudo or with root permissions, etc. I saw an answer here regarding sub-process using sudo. It's not a sub-process I want as far as I know. It's just a function within the application.
Question: How do I programmatically open a port with super user permissions?
You can't do that. If you could then malicious code would have free access to any system as root at any time!
If you want super user privileges you need to run the script from the root account or use sudo and type in the password - this is the whole point of having user accounts.
EDIT
It is worth noting that you can run bash commands from within a python script - for example using the subprocess module.
import subprocess
subprocess.run(['sudo', 'blah'])
This essentially creates a new bash process to run the given command.
If you do this your user will be prompted to enter their password in the same way as you would expect, and the privileges will only apply to the subprocess that is being created - not to the script that you are calling it from (which may have been the original question).
You could use sudo inside your python script like this, so you don't have to run the script with sudo or as root.
import subprocess
subprocess.call(["sudo", "cat", "/etc/shadow"])
I've got some code which needs to grab code from github periodically (on a Windows machine).
When I do pulls manually, I use GitBash, and I've got ssh keys running for the repos I check so everything is fine. However when I try to run the same actions in a python subprocess I don't have the ssh services which GitBash provides and I'm unable to authenticate to the repo.
How should I proceed from here. I can think of a couple of different options:
I could revert to using https:// fetches. This is problematic because the repos I'm fetching use 2-factor authentication and are going to be running unattended. Is there a way to access an https repo that has 2fa from a command line?
I've tried calling sh.exe with arguments that will fire off ssh-agent and then issuing my commands so that everything is running more or less the way it does in gitBash, but that doesn't seem to work:
"C:\Program Files (x86)\Git\bin\sh.exe" -c "C:/Program\ Files\ \(x86\)/Git/bin/ssh-agent.exe; C:/Program\ Files\ \(x86\)/Git/bin/ssh.exe -t git#github.com"
produces
SSH_AUTH_SOCK=/tmp/ssh-SiVYsy3660/agent.3660; export SSH_AUTH_SOCK;
SSH_AGENT_PID=8292; export SSH_AGENT_PID;
echo Agent pid 8292;
Could not create directory '/.ssh'.
The authenticity of host 'github.com (192.30.252.129)' can't be established.
RSA key fingerprint is XXXXXXXXXXX
Are you sure you want to continue connecting (yes/no)? yes
Failed to add the host to the list of known hosts (/.ssh/known_hosts).
Permission denied (publickey).
Could I use an ssh module in python like paramiko to establish a connection? It looks to me like that's only for ssh'ing into a remote terminal. Is there a way to make it provide an ssh connection that git.exe can use?
So, I'd be grateful if anybody has done this before or has a better alternative
The git bash set the HOME environment variable, which allows git to find the ssh keys (in %HOME%/.ssh)
You need to make sure the python process has or define HOME to the same PATH.
As explained in "Python os.environ[“HOME”] works on idle but not in a script", you need to set HOME to %USERPROFILE% (or, in python, to os.path.expanduser("~") ).
I need this command to run automatically on boot or when told to. At the moment i need to run the command in SSH and leave the session open, otherwise it stops.
python CouchPotatoServer/CouchPotato.py
This is on a ReadyNAS (Debian 7)
One easy way to do this would be to create it as a service. Take a look in /etc/init.d and you will find scripts that run as services. Copy one and modify it so that it calls your python script. An good example could be the init script used for starting the avahi daemon. Now, you can use 'service couchPotato start/stop/status', etc. It will also start the service automatically at boot time if the server ever reboots. Find a simple file to use as your template and google init scripts for further assistance. Good luck.
From this page:
To run on boot copy the init script. sudo cp CouchPotatoServer/init/ubuntu /etc/init.d/couchpotato
Change the paths inside the init script. sudo nano /etc/init.d/couchpotato
Make it executable. sudo chmod +x /etc/init.d/couchpotato
Add it to defaults. sudo update-rc.d couchpotato defaults
CouchPotatoServer/init/ubuntu can be found here
sudo update-rc.d <service> <runlevels> is the official Debian way of inserting a service at startup. Its manpage can be read there.
my 2 cents,
Use chkconfig to add the service and specify the run level. Google will give you all you need for examples of how to do this. Good luck.
Is it possible to create a raw socket without root privileges? If not, can a script elevate its privileges itself?
I wrote a Python script using a raw socket:
#!/usr/bin/env python
import socket
rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0800))
print "Worked!"
Running it with root privileges prints Worked!. However, it gives an error when run with normal user privileges.
I want to execute my script as a normal user, and it should create a raw socket without asking for anything. Is it possible?
As you noted raw sockets require higher privilege than a regular user have.
You can circumvent this issue in two ways:
Activating the SUID bit for the file with a command like chmod +s file and set its owner to root with chown root.root file. This will run your script as root, regardless of the effective user that executed it. Of course this could be dangerous if your script has some flaw.
Setting the CAP_NET_RAW capability on the given file with a command like setcap cap_net_raw+ep file. This will give it only the privileges required to open a raw socket and nothing else.
EDIT:
As pointed out by #Netch the given solutions will not work with any interpreted language (like Python). You will need some "hack" to make it work. Try googling for "Python SUID", you should find something.
There is not a way for an unprivileged process (Python or otherwise) to elevate their own privileges. It's kind of the cornerstone of having this whole privileged/unprivileged users thinga-ma-jig. In regards to raw sockets, from manual page raw(7):
Only processes with an effective user ID of 0 or the CAP_NET_RAW capability are allowed to open raw sockets.
User ID of 0 means root. See here for info about raw sockets on linux.
As pointed out in Faust's answer/comments you won't be able to directly set the CAP_NET_RAW capability for your python program, due to it being a script that gets executed by the Python interpreter, but there may be solutions out on the web that can get around this limitation.
You can also go another path and set up the application using the sudoers file, then run it via sudo
Or my preferred option is just to compile it with Nuitka, then it runs like any other executable and can be assigned run as root etc