---
# System prepended metadata

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

---

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

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

## 1. Proton Memo
- It's a challenge about Python Class Pollution on DreamHack. Let's begin.

### i. Challenge:
#### a) Source code:
- **```app.py```**:
    - First, it defines a function ```get_memo_with_auth_or_abort```: 
        - The function takes in and ```id``` and a ```password```. It then pass the ```id``` into a method called from a class ```Memo```. 
    ![image](https://hackmd.io/_uploads/rkN_F6WER.png)
            - The function uses the id that being passed in, then search for it in the ```collections``` dictionary. It then checks if that ```id``` exists as a key in the dict. 
    - It then create an object with class ```Memo``` and add it to the ```collections``` dict.![image](https://hackmd.io/_uploads/rkDDjTbVR.png)
    - Then it defines 4 routes. Let's go through them quickly:
        - *```/```*: Return the id and title of the memo for each memo in the ```collections``` dict.![image](https://hackmd.io/_uploads/BJN_ppZVR.png)

        - *```/new```*: Add a new object with the class Memo to the dict. ![image](https://hackmd.io/_uploads/HkX9p6WEA.png)
        - ```/edit/<uuid:memo_id>```: By sending a POST req, you can edit the values of the the choosen memo object, using the ***```set_attr```*** method. We will come back to this method later.
         - ```/view/<uuid:memo_id>```: Take in a password that is set when create a new memo, then return its content. ![image](https://hackmd.io/_uploads/H1uXJR-V0.png)

- **```models.py```**: This is where the challenge defines the classes. Let's go through them quickly.
    - **Password**:
        - ```__init__```: hashes the password with SHA256.
        - ```check_password```: check the self.data return by __init__ with the password being pass in after being hash to see if they are the same.
        ![image](https://hackmd.io/_uploads/BJd-W0W40.png)
        
    - **Title**:
        - ```__init__```: Takes in the data is the title, and the edit_time which uses the time() method.
        - ```get_raw_data```: Returns the title without the whitespace.
        - ```get_title```: Returns the title in the format ```Title: <title>```.
        - ```get_title_with_edit_time```: Returns the title and the time it was last edited.

    - **Content**: The same as **```Title```**.
    - **Memo**: 
        - First it creates the ```collections``` dict.
        - ```__init__```: 
            - ```self.id```: Generates a unique ID for the memo using uuid4().
            - ```self.title```: Initializes the title attribute with a new Title object.
            - ```self.content```: Initializes the content attribute with a new Content object.
            - ```self.password```: Initializes the password attribute with a new Password object.
        - Then it calls the methods from other classes, and defines two methods:
            - ```get_memo_by_id```: Return the memo if found in the ```collections``` dict.
            - ```add_memo_to_collection```: add the memo object into the ```collections``` using the id.

- **```utils.py```**: Let's go into this function.
    - The functions takes in three arguments: obj, prop and value.
        - It first split the prop chain by the **```.```**, which then takes the first property from the current chain after splitting.![image](https://hackmd.io/_uploads/SkDv4MGNC.png)

        - It then check if the there is 1 element of prop_chain, then it will check:
            - If the obj is a dict, then it will set the value being passed in to the current prop of the obj dict.
            - If not, then it will use ```setattr``` to set the attribute cur_prop to the value.![image](https://hackmd.io/_uploads/HkwIOMMV0.png)

        - If the len of prop_chain isn't 1, then it will jump to the else part.
            - First, it checks of the obj is a dict, if so, then it will check:
                - If the current prop exist as a key in the dict, then it sets the variable ```next_obj = obj[cur_prop]```.![image](https://hackmd.io/_uploads/H1PRuMMER.png)
                - If not, then it create an empty dictionary as ```next_obj``` and set it to ```obj[cur_prop]```
            - If not a dict, then it will:
                - Check if the current prop has the attribute being passed in. If so, then it get the next_obj using the ```getattr``` method to move to the next property.
                - If not, then it will create an empty dict and set it to the current prop.
                - Then it will call to ```set_attr``` passing in the next_obj.
![image](https://hackmd.io/_uploads/H1KyaQGNR.png)

#### b) The exploit:
- Since I want the rest of this blog is to try to explain what i learned. So I'm going to exploit first, before explaining.
- First, let's create a new note. Then use the edit function of it. Catching it with burp we can modified the request, something like this.
```
selected_option=__init__.__globals__.Memo.collections.<secret_note_id>.password&edit_data=<injected_password>&password=<password_of_our_public_note
```
- This is how we gen the injected password:![image](https://hackmd.io/_uploads/HyEF9M44R.png)
- Then we just need to input ```1``` in the password field of the secret note, and we will receive the flag.
![image](https://hackmd.io/_uploads/S1qvjM44R.png)

- Let's dive in to see why this works


#### c) The vulnerability:
- This challenge is about Python Class Pollution. Let's go through it together. (i'll try to explain how i understand it)
##### c.1) Brief intro:
- In Javscript, we have something called ```prototype```, which Javascript objects inherit features from one another, like methods and properties. You can read about it here: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
- In Python, we dont have ```prototype```, but we do have **special attributes**. You can read about it here: https://docs.python.org/3/reference/datamodel.html
##### c.2) Dive in:
- Let's begin with an example:
![image](https://hackmd.io/_uploads/HyFG2VGE0.png)

- We create an empty ```User``` class. Then create ```user``` instance of the ```User class```. We then add an attribute called ```name``` to it.
- Let's do something else. Let's use a special attribute to see what class the ```user``` is.![image](https://hackmd.io/_uploads/B1R71SfN0.png)


- Ahh, it returns the ```User```. But, what if we were able to change it?![image](https://hackmd.io/_uploads/BJPFGHGNC.png)

- So it changes the class name from ```User``` to what we set.
    - *```__qualname__```* or qualified name returns us the full path of the class or the function from where its being called from. For example:![image](https://hackmd.io/_uploads/rJgrdpfVA.png)
    - *```__class__```* is a references to the class of an object, in this case is ```User``` class. **```__class__.__qualname```** will point to the full path of the ```User``` class object, in this case will return ```User```. By *polluting* it by setting another value, calling ```user1``` now, it will return the class with the value that we change.

- Let's look at a popular function, its a recursive merge that helps set the attributes to an object, or merge two or more objects, ... 
```python
def merge(src, dst):
    # Recursive merge function
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)
```
- The function uses ```getattr```and ```setattr``` to recursively traverse and set attributes to an object. With an untrusted input, the attacker can manipulate the attribute of an object or item.![image](https://hackmd.io/_uploads/SJXty0fEA.png)
- After printing ```user1```, we can see now it got the attributes after calling the ```merge``` function. The ```user1-attributes``` is a dict, going through the ```merge``` function will set the key and value from the attributes dictionary and set it to the object.
- This function is pretty normal, but without any restrictions, it can be abuse, let's see what will happened if we pass in a **special attribute**.![image](https://hackmd.io/_uploads/HJodWAMNA.png)
- Let's see how it works using debugging to better undeerstand. Jump in!! ![image](https://hackmd.io/_uploads/SJBC7AMEA.png)
    - ```src``` is the injected attributes and ```dst``` is the object.![image](https://hackmd.io/_uploads/rJxUN0fV0.png)
    - ```k``` is the *__class__* while ```v``` is the *{"__qualname": "LMAO"}*, which is k's value. 
        - It then check if ```dst``` got an attribute called ```__getitem__```, then check if ```dst``` has the key ```k``` and it's corresponding value is a dictionary, recursively merge the nested dictionaries.Otherwise, directly set the key-value pair in ```dst```.![image](https://hackmd.io/_uploads/HyCj00zNR.png)

        - If not, then chec if ```dst``` has the attribute ```k``` and ```v``` is a dict. If so, then it recursively merge the nested dictionary. If not, set the attribute ```k``` to the value ```v``` using setattr.![image](https://hackmd.io/_uploads/r1Y20CzV0.png)
    - It jumps into the merge function since the conditions is met.![image](https://hackmd.io/_uploads/HkHHykXNC.png)
    - Continue stepping into it, now we move into the ```__qualname__``` dict.![image](https://hackmd.io/_uploads/B1yylyQEA.png)
    - Jumps to checking ```hasattr```.![image](https://hackmd.io/_uploads/BJWHeJm4A.png)
        - ```v``` can't be a dict, so that means it will jump to the final else, which sets the value ```LMAO``` to the attribute ```__qualname```.
    - After running, you can see it returns ```user1``` as ```LMAO```.![image](https://hackmd.io/_uploads/S175YfXN0.png).


- Let's continue going with this. In Python, a class can be inherit from another class. A child class will inherits the property and methods from the parents class. 
    - In Python, the ```__base__``` property of the class contains a list of all the base classes that the given class inherits.
        - **Friend** class inherits **User**. ![image](https://hackmd.io/_uploads/SJ-5WQXEA.png)
        - By injecting the ```__qualname__``` of the ```__base__``` property, we are directly changing the value of the base class of **Friend**, or in this case **User** class. Changing it from ```User``` to ```LMAO```.![image](https://hackmd.io/_uploads/ryoRzQmV0.png)

##### c.3) Dive in more?:
- So until now we are only polluting the classes only. But in fact we are not limit only to classes. By using ```__globals__```, we are ablt to reach the globals variable of a code, or a global class as well. Let's go for an example:
    ![image](https://hackmd.io/_uploads/rJ415PXV0.png)

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

    - As you can see, ```some_variable``` is a global variable that can be access anywhere in the code. We first called ```__class__``` attribute, which then traverse into ```__init__```, finally ```__blobals__```, which then we will be able to reach the global variable. But why is that?
        - **```__class__```**:  is an attribute on the object that refers to the class from which the object was created.
        - **```__init__```**: is used to initialize objects of a class. It contains a collection of statements, instructions, attributes, ... In this case, this calls to the  ```__init__``` inside the ```User``` class.
        - **```__globals__```**: As Python document writes:![image](https://hackmd.io/_uploads/SyYWCPQVR.png)
            - So ```__globals__``` is a dictionary that holds the access to the globals scope of a function, which we can access defined variables, modules, etc. We can access ```__globals__``` from any defined method of the instance we controlled. In this example, the ```User``` class have a ```__init__``` method, which from there we can access into ```__globals__```.
            - Since ```some_variable``` is a global variable, which can be access from anywhere in the code.![image](https://hackmd.io/_uploads/HkqvlumVC.png)
            - As we can see, we can use ```some_variable``` to set the attribute value for ```user```. So using the ```__globals__``` attributes, we can access a global variable  that the ```User``` class can access, in this cased, ```some_variable```.
    - And classes is also the same too. Since you can set other class in a class, it means that other class is global and can be access by one class.![image](https://hackmd.io/_uploads/ryctwtQ4R.png)
    - We can also use this, to even change the variable from an imported module. Let's look at an example.
    - This is a test module:![image](https://hackmd.io/_uploads/HyBPlN44R.png)
    - We can then import it into our main code.![image](https://hackmd.io/_uploads/rJA9xNNNC.png)
    - As you can see, we can access and print out the variables of the test module.![image](https://hackmd.io/_uploads/SkH4b44VC.png)
    - Now let's use the ```__globals__``` **special attribute** to polute it.![image](https://hackmd.io/_uploads/HyDKdEV4C.png)
    - As you can see, we have changed every variable and even ```__qualname__``` attribute.
    - Or maybe using the ```modules``` attribute of __sys__, which comes in the form of a dictionary, containing all the imported module when the code is loaded (only when sys is imported). ![image](https://hackmd.io/_uploads/ryMZp2E4C.png)
    - But what will happened if __sys__ is not imported. In Python, we have an object called **loader**.![image](https://hackmd.io/_uploads/By_I2pNNC.png)
    - Let's have a look at it.
        - **loader** is an instance of class ```importlib.abc.Loader```. It is responsible for module loading. ![image](https://hackmd.io/_uploads/r18AZCVN0.png)![image](https://hackmd.io/_uploads/ryHeQ0V4A.png)
        - **__loader__**: is an attribute being set to the loader object when loading a module.![image](https://hackmd.io/_uploads/rylGDOSVA.png)
        - **__spec__**: built-in attribute was introduced in Python 3.4. It contains information about the module loading process, which is defined by the ```ModuleSpec``` class.![image](https://hackmd.io/_uploads/S15nKdrVR.png)
![image](https://hackmd.io/_uploads/SkxdtdBVC.png)![image](https://hackmd.io/_uploads/Hy3u3OB4C.png)![image](https://hackmd.io/_uploads/HkvGTdrNC.png).


### ii. Exploitation explaination:
- Let's debug and see why our payload works.
![image](https://hackmd.io/_uploads/H1hjphH4C.png)
- Divide the property chain.
![image](https://hackmd.io/_uploads/rJkm0nSV0.png)
- Getting the next obj.
![image](https://hackmd.io/_uploads/SyesRnrER.png)
- Continue, we will reach ```__globals__```. Since ```Memo``` is an imported class, we can access it from ```__globals__```.![image](https://hackmd.io/_uploads/rJztJTrV0.png)
- Now we are inside the ```Memo``` class variable. We can see it contains the collections dict.![image](https://hackmd.io/_uploads/Sy3LeTrV0.png)
- Reach the ```collections``` dict.
![image](https://hackmd.io/_uploads/SkwOMpBN0.png)
- Traverse into the id property, we reach its object. ![image](https://hackmd.io/_uploads/B1O0zTSV0.png)
- Set the ```password.data``` to the injected data.![image](https://hackmd.io/_uploads/Hyy1Vpr4A.png)![image](https://hackmd.io/_uploads/r1--VTSEC.png).

    - So why don't we just pollute the global ```secret``` object. Well since after created, ```secret``` object is then add to the dict. So whether we change the global object or not, it doesn't affect the value of the secret, which is being saved inside the ```collections``` dict.![image](https://hackmd.io/_uploads/B1SsvpSN0.png)


### What i learned
- This is probably some surface of the vulnerability called ```Python  Class Pollution```. There are still more but i want to document a bit about what i learned.
- Understand some **special attributes** and how it works. Learn some more about Python class and objects.



## 2. JerryTok
- It's a challenge about Twig SSTi with PHP ```disable_functions``` and ```open base_dir``` on HacktheBox. Let's begin.

### i. Challenge:
#### a) Source code:



## Thank you for reading >.< Gud bye
![image](https://hackmd.io/_uploads/rk-UgZatp.png)






        









