Using passwords in script, revisited!
Another look at my entry from 12th May, 2024 where I explore a method for obfuscating scripts to keep borg passphrases secure while automating my backup process.
Revisiting an old topic
In this blog entry dated 12th May, 2024 I discuss a method where I’m able to keep passphrases stored inside of a bash script, while still being able to execute the bash script. Its been a few months and I’ve improved the process for obfuscating/deobfuscating scripts, since I’m now using this method as part of my process in writing/editing backup scripts. Thus I’d like to retouch the topic since rereading the previous blogpost leaves me a bit undersatisfied.
The process
You start by writing a script, and don’t forget to include your sensitive data. I’ll include an example below of one of my backup scripts:
#!/usr/bin/env bash
NAME=pi_$(date +'%Y%m%d%H%M%S')
DIR="/home/freyja/.mnt/pi"
tmux new-session -d -s borg-pi-archive "sshfs pi:/opt $DIR; \
export BORG_PASSPHRASE=yesthisistotallymyrealpassphraseyougotmeididanoopsie; \
borg create --stats --progress --compression lz4 /home/freyja/Documents/.borg/pi::$NAME $DIR; \
export BORG_PASSPHRASE=''; \
rclone sync -P -v /home/freyja/Documents/.borg/pi proton:/borg/pi; \
umount $DIR; \
"
Obfuscation
Obviously, saving this as plaintext would be insecure. It has a whole encryption passphrase in there! But remembering all that and typing it in every time isn’t ideal either. That’s where the obfuscate
script comes in. That looks a ‘lil somethin’ like this:
#!/bin/bash
##
# obfuscate script. This will encrypt any script with a gpg id,
# then stick it into the body of a variable in a new script that can
# decrypt the variable and pipe the original script directly to bash.
#
##
if [ -z "$1" ]; then
read -p "Please enter the filename: " filename
else
filename="$1"
fi
GPG_ID='my-gpg-identity'
printf "#!/bin/bash\n\nSCRIPT=\"$(cat $filename | gpg --encrypt --armor -r $GPG_ID | base64 --wrap 0)\"\n\necho \$SCRIPT | base64 -d | gpg --decrypt --quiet | bash\n\n" > $filename.obf
chmod +x $filename.obf
calling that with obfuscate script
will spit out a file called script.obf
that is just as easy to execute as the script you obfuscated. In fact, it is literally that exact script! Except its been encrypted with your supplied GPG_ID
, turned into base64, then stuck inside a variable called SCRIPT
inside of the script.obf
file - along with some other stuff that allows script.obf
to decrypt the data stored in SCRIPT
variable then pipe it directly into bash.
The obfuscated script will look a bit like this:
#!/bin/bash
SCRIPT="LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpoUUlNQXhCRUVPVU9vQ1JEQVEvL1EvM29FOHBoeUlQSFN6bVFjSWtpUzFDR1pCQU1oWFY3RU9ld2ZaSVhpcDZOClZHM1lDMGQ5QjVwRjZ6emFQVUZmVkJPQzZSV2NPR1pHQU91QW83bXVSSmZNVU5YVWpYbDRrVFRIRnFpdE8ydFIKVHQ3d0lyVm5YMnJjVUNHR0Iva29lSDdsVG9xeG00TEtiZUkvSis2VVpCejNMSlBEQ2hkcXhtQURkbjlIRCtBMwpJT2pMNW5mbVZoRzRRUXBIa01KVFZyOUVoVXNsanJzNXRJNWNUMmg5NEZyaHBnbHE1OVhIOEJCOTJKQ25jSVo0Cis2eW1hZVdSRXBLOGFXRkF6aFVEZUd6bDdhV1VzMUs4NXRraUszdnFwRkYxUDZLdjZQb3dJOU9RRERHNmtLL08KaXlaRFNtTTNIVUJOQ3lEK29SKzBRRGJneG1TTGdUdkdkbW9xUUxCcm9ESVNLMkRiRWNBWkVqR3RwM25ienhwNwo2T1d6cDZLUzhGZURvTGZtMzdBdnpreTBMQ2ZTUGlZQm1QcFVEZzg1NlJOMytSQWlPeTgydkU0TFd4Mm14N3FZCmVCN1dQS3FNbTlhZDNnTVJUVEpUUGhzSUZrTWc4bEtEeW5uenhnUGFyQStFcnlyMUhnZVBqaThFRUZMVk44cmIKYlVtUE1BL3d6UVVFRFNyaXBBTE5WQ3lXOFF0eHh5QmtYWW9ERldTc2w5RXRCNDRCWHk4amozbHlKcXV6TzFZZgpTTjJmZThRdW9FMk1JTHM1MmRxbjBvdlFBZUN6RVF3Z29udC9hcXpzRUZ4b29tSFRPa1dVT1BUeGVoTXFhRjZKCjlKSnk2aUs0MEMrUHFTbVNVaktQMmtBZDRRQ3YzYXlabU8zaTZyRHZIM25hN0g1OHFLRlkwb2NoRWI4Qzh6blUKY0FFSkFoQk56bm5zRmNrTlVpOUhEQ05hcG1ubkxzb0xycDNWVE9yMFhZQUpyYUFZYStZZDh2RHJsYUNaeFNxTQpOYW1kUFZkc3J4K2JPTTdkbk1VbXFldm1GRzVPUm5nSUF0KytxdkNzaGNmRk42V01qcUpyYStBdWZRMFRldUZzClZZNHRVY3JzRU90REFrWHUxWDEzZVh3PQo9WENRdgotLS0tLUVORCBQR1AgTUVTU0FHRS0tLS0tCg=="
echo $SCRIPT | base64 -d | gpg --decrypt --quiet | bash
Deobfuscation
As you can see, the encrypted script is stored as base64. To run it, that script is decoded, decrypted, then piped into bash. So long as the machine you’re on has the private key for the gpg key you used to encrypt the script, it will simply ask you for your gpg passphrase before proceeding~~! How neat! But what if we want to edit the script? Seems like a bit of a pain to get your original script back, right? Well… to a degree. If you wanted to, you could lop of that pipe and bash
command at the end of the last script, replace it with >> script.deobfuscated
, and you’d have your original script back. But, that’s also kind of annoying to do every time. So I just made a deobfuscate
script that’ll do the job for you. Its just like the obfuscate
script but in reverse. It takes a file as input, looks for a variable called script
, then decodes, decrypts, and dumps it into a file appended with .deobfuscated
. Here’s the deobfuscate script:
#!/bin/bash
if [ -z "$1" ]; then
read -p "Please enter the filename: " SCRIPT_FILE
else
SCRIPT_FILE="$1"
fi
if [ ! -f "$SCRIPT_FILE" ]; then
echo "$SCRIPT_FILE not found!"
exit 1
fi
cat $SCRIPT_FILE | xargs | awk -F 'SCRIPT=' '{print $2}' | awk -F ' ' '{print $1}' | base64 -d | gpg --decrypt --quiet > $SCRIPT_FILE.deobfuscated
if [ $? -eq 0 ]; then
echo "$SCRIPT_FILE has been deobfuscated."
else
echo "Failed to decrypt the script. Ensure you have the correct GPG key and it's available."
exit 1
fi
Conclusion
That’s about it, I don’t have anything else. This section is simply a formality. I hope that if you’re reading this, you find it interesting. <3