Last week I stumbled across the “AppFog OpenStack Birthday Contest” via Twitter.
I’d been quietly following AppFog’s progress since I received a PHPFog beta invite a year or two ago. At the time I hadn’t had a reason to give their service a try since I wasn’t a PHP guy. However, spurred by the allure of a coding contest and the large number of platforms AppFog supports, I finally had a reason to poke around!
Anticipating that I’d be up against stiff competition I chose to place some additional requirements on my contest submission. As the AppFog Blog recently showed I wasn’t wrong about the competition. My hope was that the extra work I put into the submission would grant me at least an honorable mention.
What I didn’t expect was that I’d end up winning the competition!
I am honored that my code was chosen as the winning submission. As a small show of thanks, I’ve decided to detail my experiences with the AppFog beta as well as annotate the de-obfuscation of my code step-by-step.
An AppFog First Impression
My first concern was getting an AppFog instance configured on which to develop. While I do have a little bit of experience dealing with shared hosting and VPS services, I have only minimal exposure to PaaS providers such as AppFog. At first I was worried about the work required to configure an application, but AppFog’s simple interface had me finished with the process before I knew I had started!
Thanks to the simple in AppFog deployment process I was able to concentrate entirely on my code, and not my hosting.
Some Speed Bumps
Unfortunately I can’t say that my experience with AppFog was completely problem free. During development I ran into occasional trouble with deployment. Applications that ran perfectly fine locally started timing out regularly during staging. When they staged they would fail to start. A few of these problems were of my own making and were easily resolved by checking the support area of the AppFog site.
For the more difficult problems, the AppFog support team met or exceeded the customer service I’d grown accustom to from both Dreamhost and Linode. With the help of the AppFog support team I was able to fix my deployment problems and submit my solution. I was especially impressed by their responsiveness given I hadn’t paid them a cent!
Enough about problems… on to the code!
Creating a Contest Submission
Now, I love obfuscation just as much as the next guy, but I wanted my submission to be slightly more than just a block of funny looking text. I wanted my submission to have a few extra (admittedly simple) levels of trickery involved. In order to satisfy this urge I added the following extra personal submission requirements:
- The code must be pretty.
- The code must be obfuscated in at least two separate ways.
- The final “Happy Birthday OpenStack” text must exist in some way outside of the source code itself.
In order to understand how I achieved these objectives lets walk backwards through the obfuscation steps to reveal the original source code.
Note: What follows is a step-by-step analysis of the code itself, performed through the lens of someone de-obfuscating my submission. The contents of this analysis are targeted at someone with minimal Ruby experience. If you feel you understand Ruby you may get more enjoyment out of attempting the de-obfuscation yourself!
Understanding the Obfuscation
None of the methods of code obfuscation I used are terribly complex. The full submission is plenty pretty with ASCII art declaring my affection for the people running the contest.
The ASCII art itself was created with the help of an open source tool called jp2a by Christian Stigen Larsen. The generated ASCII was then used to format the resulting block of obfuscated code. This method allowed me to obfuscate the code first, then tweak the ASCII art as I saw fit.
Despite how complicated it may look my submission boils down to the following four lines of code:
1 2 3 4
Despite separating the lines of code it is still plenty hard to understand what it is doing. Lets take it line by line:
The above uses Ruby’s quoted array syntax to turn a bunch of whitespace separated strings into an array of values.
1 2 3 4 5 6 7 8 9 10 11 12 13
This means that the code takes the humongous block of gibberish and turns it into a huge array of tokens. The
join method is immediately called on the response, meaning the variable
c contains a large string of characters.
The second line is a red-herring rot13 representation of the phrase
Made_by_Joe_"coderjoe"_Bauser" which can be safely ignored.
The third line:
Does nothing more than store the value of
__FILE__ (which represents the name of the currently running file) into a constant variable named
The last line is the meat and potatoes of this file. It has the job of interpreting the huge block of text! If we create some temporary variables we can see what is going on a little easier.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Now we know what the obfuscated code is! It’s a series of ASCII characters, left shifted twice, converted to hexadecimal, and separated by the string ‘0x’. It is being used as the value to
send(:eval,string) which means it must be more ruby code!
Why did I do this? I had started with simple hex conversion, but I found I needed a larger canvas on which to draw my ASCII art, so the left shifting increased the hex values enough that I had a little more text to work with!
We Have to Go Deeper
Now that we know how the code is interpreted, we print it by replacing the code creating the
:eval symbol with the symbol
The output of which is as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
We now have some code which looks more like a standard Sinatra application!
Those of you following along at home will notice that your code looks slightly different. The contents of the
get '/src' do block and line 15 of the source above were originally obfuscated in a similar manner to the original file. I’ve taken the liberty of revealing them to you now, since the process of doing so is identical to the previous process we used.
There are a few portions of this code we should make note of:
- The first index of the array
iywRFqowCSzrNeis a reversed base64 encoded zlib compressed chunk of Ruby code. It is reasonable to assume that the other two array locations may be similarly encoded.
- The /src path sets some response headers. Their purpose isn’t immediately obvious.
- The definition of
XYZZYin the original file is important. The value of
__FILE__changes when it is located inside of a string being run through
eval. Storing the value of
XYZZYallowed this obfuscated code to keep track of the current file name.
If we go ahead and print the value of the first array we find that the first array value executes the second array value, which in turn executes the third. De-obfuscating this code manually we end up with code similar to the following.
1 2 3 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
These small blocks of code, which were hidden in the array
iywRFqowCSzrNe reveal their importance.
They also help me achieve the rest of my goals for my obfuscated code!
When these chunks of code are run in order as a result of a request to the root path the result is the string “Happy Birthday OpenStack” being output as a text/plain document.
Reviewing the Objectives
I was very happy with the ways in which I met my original goals.
- The code looked pretty thanks to ASCII images in original obfuscated code.
- The code itself was obfuscated in two separate ways
- The original code is obfuscated through hex encoded shifted integer character values
- The internal code is encoded in reversed base64 zlib compressed strings
- The actual string “Happy Birthday OpenStack” isn’t present in fully de-obfuscated code
- The string itself is yet another reversed base64 encoded zlib compressed string split into 3 parts
- The first part is the host name of the machine running the code
- The second part is the value of the
i_has_a_secretHTTP response header from the /src URI
- The final part is the variable name of an array in the source code itself!
I was quite happy that I managed to come up with three distinct methods in which to store the text “Happy Birthday OpenStack”. I hope you have enjoyed this de-obfuscation walk-through and post-mortem.