Trojan Horse in a Bash Script

Yes, you heard right. But you might ask youself why? Good question! Sometimes you might want to send a script to a customer just so that they can execute it. But this script might need an interpeter that is not already pre-installed on the target system or not even pre-packaged on that platform. That’s where you need a Trojan Horse. In this case the Trojan Horse is a Bash script, that comes with two payloads. The first payload is the static binary of the Joker interpreter. The second is the Joker LISP script that is executed.

The Ingredient for the Recipe

  1. Bash (or even just sh)
  2. uudecode and uuencode
  3. The binary you want to embed

Throwing everything into the Cauldron

The original use case of uuencode was to send binaries via email. We want to do something similar with it. We want to embed a binary in a shell script. uudecode is then used to extract the binary from the shell script again. Extract is the right word, because uudecode gracefully ignores all of the other ascii text that is in there and that would be the rest of our Bash script.

  1. At first we encode (embed) the joker binary into my_script.sh like this: uuencode joker joker_embed > my_script.sh

    joker_embed is the name the binary gets after we run uudecode on it.

  2. Now we need extend my_scipt.sh a little bit.

    • Let’s make sure that there is no previous version of joker_embed: rm -r joker_embed.
    • Then we need to extract the binary to $PWD: uudecode $0
    • And execute it: joker_embed <my embedded script>
    • Now clean up: rm -r joker_embed
  3. But wait… there is something missing.

    Right, the embedded script is missing. Depending on how this works with your interpreter, you can just pass it with a parameter or write it to a file first. With Joker I’ve chosen to write it to a file first. Otherwise the user would have seen some output from the REPL. But this is due to how Joker works.

The Result

The result should look something like this – but much longer of course.

#!/bin/bash

MYJOKERSCRIPT=$(cat << ENDOFSCRIPT
(def myreturn (joker.http/send {:url "https://showmyip.com/simple"}))
(def html (re-find #"<h1>.+<\/h1>" (get myreturn :body)))
(println
  (str "Your public IP: "
       (joker.string/replace html #"(<h1>|<\/h1>)" "")))
ENDOFSCRIPT
)

temp_file=$(mktemp -p "$PWD" -t "$(basename $0).XXXXXXXXXXXX")
rm -f joker_embed
uudecode $0
echo $MYJOKERSCRIPT > $temp_file
./joker_embed $temp_file
rm -f joker_embed
# make sure that temp_file is not empty before rm
if [ -n "$temp_file" ]; then
  rm -f $temp_file
fi
exit
begin 755 joker_embed
M?T5,1@(!`0````````````(`/@`!````\-Q%``````!``````````,@!````
M`````````$``.``'`$``&``#``8````$````0`````````!``$```````$``
M0```````B`$```````"(`0`````````0````````!`````0```"<#P``````
M`)P/0```````G`]```````!D`````````&0`````````!``````````!````
M!0````````````````!``````````$```````-F!/@``````V8$^````````
M$`````````$````$`````)`^````````D'X```````"0?@``````)?9U````
M```E]G4````````0`````````0````8`````D+0```````"0]````````)#T

Of course this is very basic and a lot more stuff could be done here… or might work completetly different with an other interpreter. So just take it as a little inspiration. Speaking of inspiration: This little experiment and blog post is heavily inspired by this answer on SO.

Have fun and happy hacking!