# *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```.

- 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.
- 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.
- *```/new```*: Add a new object with the class Memo to the dict. 
- ```/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. 
- **```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.

- **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.
- 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.
- 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]```.
- 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.

#### 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:
- Then we just need to input ```1``` in the password field of the secret note, and we will receive the flag.

- 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:

- 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.
- Ahh, it returns the ```User```. But, what if we were able to change it?
- 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:
- *```__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.
- 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**.
- Let's see how it works using debugging to better undeerstand. Jump in!! 
- ```src``` is the injected attributes and ```dst``` is the object.
- ```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```.
- 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.
- It jumps into the merge function since the conditions is met.
- Continue stepping into it, now we move into the ```__qualname__``` dict.
- Jumps to checking ```hasattr```.
- ```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```..
- 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**. 
- 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```.
##### 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:


- 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:
- 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.
- 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.
- 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:
- We can then import it into our main code.
- As you can see, we can access and print out the variables of the test module.
- Now let's use the ```__globals__``` **special attribute** to polute it.
- 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). 
- But what will happened if __sys__ is not imported. In Python, we have an object called **loader**.
- Let's have a look at it.
- **loader** is an instance of class ```importlib.abc.Loader```. It is responsible for module loading. 
- **__loader__**: is an attribute being set to the loader object when loading a module.
- **__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.
.
### ii. Exploitation explaination:
- Let's debug and see why our payload works.

- Divide the property chain.

- Getting the next obj.

- Continue, we will reach ```__globals__```. Since ```Memo``` is an imported class, we can access it from ```__globals__```.
- Now we are inside the ```Memo``` class variable. We can see it contains the collections dict.
- Reach the ```collections``` dict.

- Traverse into the id property, we reach its object. 
- Set the ```password.data``` to the injected data..
- 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.
### 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
