Password protected shell script - shell

I want to make my script password protected. If I use this code it works:
ACTUAL="sam123"
read -s -p "Password: " enteredpass
I also want to protect the script from being read with cat and vi. I tried to use vim -x <script> to encrypt it but then it won't allow me to run it.
I am using a generic user and haven't gotten anywhere.

You can't do this securely without your sysadmin's help, but you can do something sorta-kinda-maybe-not-really-adequate without it.
So, let's say you create your script like so:
cat >myscript <<EOF
echo "Doing something super secret here"
EOF
...but you don't want anyone who doesn't know the password to run it, even if they're using a shared account. You can do this by encrypting it:
gpg -ac <myscript >myscript.asc
...and then embedding that plaintext into a script:
#!/usr/bin/env bash
{ gpg -d | bash -s "$#"; } <<'EOF'
-----BEGIN PGP MESSAGE-----
jA0EBwMCBogTuO9LcuZg0lsB2wqrsPU8Bw2DRzAZr+hiecYTOe//ajXfcjPI4G6c
P3anEYb0N4ng6gsOhKqOYpZU9JzVVkxeL73CD1GSpcQS46YlKWJI8FKcPckR6BE+
7vqkcPWwcS7oy4H2
=gmFu
-----END PGP MESSAGE-----
EOF
That said, other users in the shared account can still collect your password if they connect to and trace your process while it's running -- running strace on the copy of bash -s will show the text being fed into its stdin. In general, you shouldn't rely on shared accounts for anything that needs to remain confidential.

Late answer for posterity, how about using openssl? here's my scriptencrypt.sh
It generates a new .sh file that requires a password
#!/bin/bash
if [ -z "$1" ]; then echo "usage: $(basename $0) script"; exit 1; fi
script=$(cat "$1")
checksum="$(echo "$script" | md5sum | awk '{ print $1 }')"
extension=$([[ "$(basename $1)" =~ .\.. ]] && echo ".${1##*.}" || echo "")
cat << EOF > "${1%.*}.enc${extension}"
#!/bin/bash
read -r -d '' encrypted_script << EOF2
$(openssl aes-256-cbc -a -salt -in /dev/stdin -out /dev/stdout <<< "${script}")
EOF2
read -s -p "Enter script password: " password
echo
unencrypted_script=\$(openssl aes-256-cbc -d -a -salt -in /dev/stdin -out /dev/stdout <<< "\${encrypted_script}" -pass pass:"\${password}" 2>/dev/null | tr -d '\000')
clear
checksum="\$(echo "\$unencrypted_script" | md5sum | awk '{ print \$1 }')"
if [ "\${checksum}" = "${checksum}" ]; then
eval "\${unencrypted_script}"
exit 0
else
echo "Wrong password inserted"
exit 1
fi
EOF

Related

Bash, openssl, strange behavior on exit status

I'm writing a script that should do a dictionary attack on a text file passed as argument encrypted with openssl.
Here is what I wrote:
#!/bin/bash
# written by Cosimo Colaci
passwords=( $(cat italian.txt) ) # italian.txt is a list of words
for word in ${passwords[#]}
do
openssl enc -d -aes-128-cfb1 -in "$1" -k $word 2>/tmp/err
pid=$$
wait $pid
if [ -s /tmp/err ]
then
continue
else
openssl enc -d -aes-128-cfb1 -in "$1" -k $word;
break;
fi
done
I also tried
for word in ${passwords[#]}
do
openssl enc -d -aes-128-cfb1 -in "$1" -k $word &>/dev/null
exitstatus=$?
if [ $exitstatus -ne 0 ]
then
continue
else
openssl enc -d -aes-128-cfb1 -in "$1" -k $word;
break;
fi
done
The problem is that on some cicles the exit status is 0 even if decription fails, as I can see by launching:
bash -x ./crack_italian.sh filetodecript.txt
but the same command, in a terminal, behave as expected and fails.
while read -r word; do
if openssl enc -d -aes-128-cfb1 -in "$1" -k "$word" >openssl.out 2>&1
then
cat openssl.out
break
fi
done <italian.txt
rm -f openssl.out
You don't need to read the file into an array.
You can use the exit status directly in an if statement. Note that in your second example, the assignment of $? to exitstatus changes $?.
Variable expansions should be double quoted.
Slightly shorter:
while read -r word; do
openssl enc -d -aes-128-cfb1 -in "$1" -k "$word" >openssl.out 2>&1 &&
{ cat openssl.out; break; }
done <italian.txt
rm -f openssl.out

Script to automate kadmin principal

I am trying to write a script to automate kerberos principal and but the script is not working. Not sure what i am missing. Below is the code:
#!/bin/bash
read -p "Please enter space-delimited list of principal to create: " NEW_Principal
clear
echo "password" | kinit adminuser/admin ; echo "password" | kadmin
for i in $NEW_ORGS
do
addprinc ${i}
${i}
echo ""
done
Also tried writing this way:
################### create principal #############
pass="principal_password"
echo "password" | kinit adminuser/admin
printf "%b" "password" | kadmin
printf "%b" "addprinc principal_name\n$pass\n$pass"
But its not working in script.
I have done it. All I have to do is pass the command as a string. Here is the answer:
echo -e "${i}\n${i}" | kadmin -w "$krb_pass" -q "addprinc

ssh instruction interrupt a while cycle?

I'm trying to deploy a cluster with a script which uses a yaml file. Except for an entry called "RaftFS" each yaml entry represents a machine to deploy. I don't understand why the script does only one while cycle if the ssh command is executed (even if the command is a simple ls !) but if I delete it then everything is fine and it does a number of cycle equals to the number of machines defined in the yaml file!
cat RaftFS/servers.yaml | shyaml keys-0 |
while read -r -d $'\0' value; do
if [ ! $value == "RaftArgs" ]; then
address=$(cat RaftFS/servers.yaml | shyaml get-value $value.machineIP | xargs -0 -n 1 echo)
username=$(cat RaftFS/servers.yaml | shyaml get-value $value.username | xargs -0 -n 1 echo)
password=$(cat RaftFS/servers.yaml | shyaml get-value $value.password | xargs -0 -n 1 echo)
#uploading my fingerprint (in order to use pssh)
echo $address $username $password
echo "uploading my fingerprint on $username#$address $password"
sshpass -p $password ssh-copy-id -oStrictHostKeyChecking=no $username#$address
echo "creating RaftFS"
ssh $username#$address echo "MACHINE=$value vagrant up">>vagrantscript.sh
fi
echo $address $username $password
done
I think there is no issue with the ssh command but it is a delimiter's issue
I've played a little with read -r -d $'\0' and these are the results
echo "a\0b\0c" | while read -r -d $'\0' var; do echo $var; done
prints
a
b
and
echo "a\0b\0c\0" | while read -r -d $'\0' var; do echo $var; done
prints
a
b
c
I assume there is some difference in the end line when the $value == "RaftArgs"
The standard input to the while loop is also the standard input to every command within the while loop. ssh reads from standard input in order to pipe the data to the remote command. It's probably consuming the data intended for the read statement.
You can redirect the ssh command's input:
ssh $username#$address ... >>vagrantscript.sh < /dev/null
Or you can run ssh with the "-n" flag to prevent reading from stdin:
ssh -n $username#$address ... >>vagrantscript.sh

Bash script help/evaluation

I'm trying to learn some scripting however I can't find solution for one functionality.
Basically I would like to ask to evaluate my script as it's probably possible to reduce the complexity and number of lines.
The purpose of this script is to download random, encrypted MySQL backups from Amazon S3, restore the dump and run some random MySQL queries.
I'm not sure how to email the output from printf statements - one is for headers and second one for actual data. I've tried to format the output so it looks like below but I had to exclude the headers from the loop:
Database: Table: Entries:
database1 random_table 0
database2 random_table 0
database3 random_table 0
database4 random_table 0
I would like to include this output in the email and also change the email subject based on the success/failure of the script.
I probably use to much if loops and MySQL queries are probably to complicated.
Script:
#!/usr/bin/env bash
# DB Details:
db_user="user"
db_pass="password"
db_host="localhost"
# Date
date_stamp=$(date +%d%m%Y)
# Initial Setup
data_dir="/tmp/backup"
# Checks
if [ ! -e /usr/bin/s3cmd ]; then
echo "Required package (http://s3tools.org/s3cmd)"
exit 2
fi
if [ -e /usr/bin/gpg ]; then
gpg_key=$(gpg -K | tr -d "{<,>}" | awk '/an#example.com/ { print $4 }')
if [ "$gpg_key" != "an#example.com" ]; then
echo "No GPG key"
exit 2
fi
else
echo "No GPG package"
exit 2
fi
if [ -d $data_dir ]; then
rm -rf $data_dir/* && chmod 700 $data_dir
else
mkdir $data_dir && chmod 700 $data_dir
fi
# S3 buckets
bucket_1=s3://test/
# Download backup
for backup in $(s3cmd ls s3://test/ | awk '{ print $2 }')
do
latest=$(s3cmd ls $backup | awk '{ print $2 }' | sed -n '$p')
random=$(s3cmd ls $latest | shuf | awk '{ print $4 }' | sed -n '1p')
s3cmd get $random $data_dir >/dev/null 2>&1
done
# Decrypting Files
for file in $(ls -A $data_dir)
do
filename=$(echo $file | sed 's/\.e//')
gpg --out $data_dir/$filename --decrypt $data_dir/$file >/dev/null 2>&1 && rm -f $data_dir/$file
if [ $? -eq 0 ]; then
# Decompressing Files
bzip2 -d $data_dir/$filename
if [ $? -ne 0 ]; then
echo "Decompression Failed!"
fi
else
echo "Decryption Failed!"
exit 2
fi
done
# MySQL Restore
printf "%-40s%-30s%-30s\n\n" Database: Table: Entries:
for dump in $(ls -A $data_dir)
do
mysql -h $db_host -u $db_user -p$db_pass < $data_dir/$dump
if [ $? -eq 0 ]; then
# Random DBs query
db=$(echo $dump | sed 's/\.sql//')
random_table=$(mysql -h $db_host -u $db_user -p$db_pass $db -e "SHOW TABLES" | grep -v 'Tables' | shuf | sed -n '1p')
db_entries=$(mysql -h $db_host -u $db_user -p$db_pass $db -e "SELECT * FROM $random_table" | grep -v 'id' | wc -l)
printf "%-40s%-30s%-30s\n" $db $random_table $db_entries
mysql -h $db_host -u $db_user -p$db_pass -e "DROP DATABASE $db"
else
echo "The system was unable to restore backups!"
rm -rf $data_dir
exit 2
fi
done
#Remove backups
rm -rf $data_dir
You'll get the best answers if you ask specific questions (rather than, "please review my code")...and if you limit each post to a single question. Regarding emailing the output of your printf statements:
You can group statements into a block and then pipe the output of a block into another program. For example:
{
echo "This is a header"
echo
for x in {1..10}; do
echo "This is row $x"
done
} | mail -s "Here is my output" lars#example.com
If you want to make the email subject conditional upon the success or
failure of something elsewhere in the script, you can (a) save your
output to a file, and then (b) email the file after building the
subject line:
{
echo "This is a header"
echo
for x in {1..10}; do
echo "This is row $x"
done
} > output
if is_success; then
subject="SUCCESS: Here is your output"
else
subject="FAILURE: Here are your errors"
fi
mail -s "$subject" lars#example.com < output

encrypting/decrypting password stored in config file

I have a simple Bash script automating tasks which require password-based authentication.
Currently I store the credentials in plain text:
$ cat ~/.myconfig
username=foo
password=bar
Obviously that's bad - so I wonder whether there's a simple way to encrypt/decrypt the password using my public/private key pair. Using Yet Another Password for the encryption wouldn't gain much, so I want it to happen pretty much automatically.
I've done some research (around here and elsewhere), but am way out of my depth on this one...
You can store password into md5 sum, add some salt before.
create:
\#!/bin/bash
salt=12345_
protocol=sha1sum
read -p "Enter login: " username
read -p -s "Password: " pass1
read -p -s "Repeat: pass2
if [ "pass1 != pass2" ]; then echo "Pass missmatch"; exit 1; else password=pass1; fi
echo -en "$username " >> ./mypasswd
echo -e "${salt}${password} | $protocol | awk '{print $1}'" >> ./mypqsswd
read:
\#!/bin/bash
salt=12345_ #(samesalt)
protocol=sha1sum
read -p "Enter username: " username
read -p -s "Enter password: " password
if [ `grep $username ./mypasswd | awk '{print $2}' != `echo -e "`echo ${salt}${password} | $protocol | awk '{print $2}'`" ]; then echo -e "wrong username or password"; exit 127; else echo -e "login successfull"; fi
There's your code.
To automate your task means providing the password; it won't make a difference is you encrypt/obfuscate the password, you'll need to provide the decrypting too.
The only way around this dilemma is an agent-like program, as for example ssh-agent, which stores your passwords for you.
(edit: corrected link)
If you simply want to hide the password then store its SHA1 hash. The compare the hash of the entered password with your stored hash.

Resources