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
- Bash (or even just sh)
- uudecode and uuencode
- 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.
-
At first we encode (embed) the
joker
binary intomy_script.sh
like this:uuencode joker joker_embed > my_script.sh
joker_embed
is the name the binary gets after we runuudecode
on it. -
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
- Let’s make sure that there is no previous version of
-
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!