Freyja's Blog

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