Self-extracting shell scripts
Recently at work, I had to figure out on how to transfer some data to systems used by scripts that were executed directly on the hosts. It wasn’t that much payload, and I really didn’t want to be bothered to set up a separate filesystem place where to hosts rsync the data from, make sure that ssh works, etc. So, why not attach the data to the scripts itself? Here’s what I came up with.
SUBJECT="/path/to/your/payload" if [[ "$1" = "rebuild" || "$1" = "clean" ]] then echo "rebuilding myself..." PAYLOADSTART=`awk '/^__PAYLOAD_FOLLOWS__/ {print NR + 1; exit 0; }' $0` # full replace, must use cp for that (piping breaks control flow) head -n "$(( $PAYLOADSTART-1 ))" $0 > tmp cp tmp $0 rm tmp echo "cleaned." [ "$1" != "clean" ] || exit 0 echo "archiving payload... ($SUBJECT)" OLDPWD=`pwd` cd "dirname $SUBJECT" TMPDIR=`mktemp -d /tmp/pkgInstaller.XXXXXX` tar -czf $TMPDIR/archive-o-matic.tar.gz "$SUBJECT" cd "$OLDPWD" cat "$TMPDIR/archive-o-matic.tar.gz" >> $0 echo "payload attached." rm -rf "$TMPDIR" echo "done here." exit 0 fi # Self extraction export TMPDIR=`mktemp -d /tmp/pkgInstaller.XXXXXX` # determine start of payload PAYLOADSTART=`awk '/^__PAYLOAD_FOLLOWS__/ {print NR + 1; exit 0; }' $0` # extract payload tail -n+$PAYLOADSTART $0 | tar xzv -C $TMPDIR # copy to target cp -R "$TMPDIR/$SUBJECT" "/your/target/path" # cleanup rm -rf $TMPDIR exit 0 __PAYLOAD_FOLLOWS__
What this basically does, is to append, read or delete data after the line __PAYLOAD_FOLLOWS__
 (in the same file!). To prevent the shell to choke on this data (it shouldn’t be executed as well), the exit 0
statement lets the script execution be halted before reaching this portion of the file.
Funnily enough, Bash doesn’t mind when you append to an currently executing script. In earlier version’s, I’ve used exec
to replace the current (script-executing) process in order to be able modify the files held open by it. Turn’s out that doesn’t seem to be necessary. Note that while rebuilding, the script replaces itself mid-execution completely. I’m not sure wether this works only because a copy of the original script is held in memory (and didn’t have the time to check that out either). But if it’s really replacing itself, that would mean self-modifying shellcode was created here accidentally
Oh, and don’t try to open the file in your favourite editor after the payload has been attached – most often, it’ll have a hard time figuring out what’s going on, eat up your CPU and memory while doing so and sometimes get so confused that a crash follows suit. Does not compute, eh?
Hat tip to the linux journal article, from which I got some ideas.
Bash: Preparing and executing commands in a variable/string Setting up virtual users in vsftpd