I was playing around with stegging data into code by hiding it in tab/space encoded bytes after each line where a 0 is a tab and a 1 is a space.
This was a cool way to potentially hide data in a git repo, literally invisible in plain sight.
The tool I slopped together to do this can be found here.
Using the e option you can pass it a file to hide and a file to hide it in and it will write the output file into 'secret'.
The file 'secret' will look identical to the file you are hiding in, except it will contain extra whitespace after each line.
For example, if your payload was just a file containg 'A' it would be translate to binary 0100001, which would then be translated to the string equivalent of ['\t',' ','\t','\t','\t','\t','\t',' ']
where \t are tabs. This collection of whitespace would then be appended to the end of the first line of the file being used to hide the payload, and if there were another character in the payload, it would be encoded similarly and put at the end of the next line.
You can then decode the 'secret' file back into the text you are hiding in by using the d option and passing it an input file with whitespace and an output filename to write the decoded secret to.
This concept seemed cool, but marginally useful. That was until I had the idea of using this to embed malware into otherwise friendly seeming code.
To do this, I would need to first come up with a payload for what I would like to run. For simplicity, for demonstration, I will just be dumping a public key for which I have the private key in their ~/.ssh/authorized_keys
using this payload.
I then need a file in which I can hide the payload. This requires a file longer than 106 lines, as that is how long my payload is. Thankfully, the other day I wrote a really sloppy in terminal bash.org quote viewer/saver. I am going to need to add a few lines of functionality for it to load itself, parse out the whitespace, decode it, and evaluate the content. The code in my example could be less suspicious, more roundabout and not use eval(), but for now it works for demonstration purposes and blends in fairly well at a glance.
After adding the self loading and evaluating whitespace functionality to my quote viewer, I need to actually give it whitespace at the end of each line that decodes to the payload. Thankfully, the tool I wrote makes this very easy to do.
I can run node spacer.js e spacerpayload.js bashviewer.js
and get my encoded file written to 'secret'. I can then rename it to something like bashviewerprimed.js and run it to make sure everything goes smoothly. Here you can see what the output from adding the encoded payload, bashviewerprimed.js, looks like.
On running node bashviewerprimed.js
, after npm install cheerio request request-promise
ing the dependencies for the bash viewer, the program shows us bash quotes and lets us sort through and save them as usually. On start, it decodes the whitespace hidden in it and evaluates it, dropping our public key in, which we can verify with cat ~/.ssh/authorized_keys
. All of this happens without the user knowing, even if they take a light glance at a code.
This concept might be semi useful for some sorts of attacks, maybe. This is the result of a few hours of work and a lot of it could stand to be improved quite a bit. Hopefully, this inspires some creative ideas.
Thinking of adding a comment system using Google Sheets and writing a post about that but I might not. The ssh post may yet come, as well as a weird attempt at replicating ssh -R flag with nodejs, all depends what ends up catching my interest long enough.