githubEdit

Class Pollution (Python's Prototype Pollution)

circle-check

Basic Example

Check how is possible to pollute classes of objects with strings:

class Company: pass
class Developer(Company): pass
class Entity(Developer): pass

c = Company()
d = Developer()
e = Entity()

print(c) #<__main__.Company object at 0x1043a72b0>
print(d) #<__main__.Developer object at 0x1041d2b80>
print(e) #<__main__.Entity object at 0x1041d2730>

e.__class__.__qualname__ = 'Polluted_Entity'

print(e) #<__main__.Polluted_Entity object at 0x1041d2730>

e.__class__.__base__.__qualname__ = 'Polluted_Developer'
e.__class__.__base__.__base__.__qualname__ = 'Polluted_Company'

print(d) #<__main__.Polluted_Developer object at 0x1041d2b80>
print(c) #<__main__.Polluted_Company object at 0x1043a72b0>

Basic Vulnerability Example

Gadget Examples

chevron-rightCreating class property default value to RCE (subprocess)hashtag
chevron-rightPolluting other classes and global vars through globalshashtag
chevron-rightArbitrary subprocess executionhashtag
chevron-rightOverwritting __kwdefaults__hashtag

__kwdefaults__ is a special attribute of all functions, based on Python documentationarrow-up-right, it is a “mapping of any default values for keyword-only parameters”. Polluting this attribute allows us to control the default values of keyword-only parameters of a function, these are the function’s parameters that come after * or *args.

chevron-rightOverwriting Flask secret across fileshashtag

So, if you can do a class pollution over an object defined in the main python file of the web but whose class is defined in a different file than the main one. Because in order to access __globals__ in the previous payloads you need to access the class of the object or methods of the class, you will be able to access the globals in that file, but not in the main one. Therefore, you won't be able to access the Flask app global object that defined the secret key in the main page:

In this scenario you need a gadget to traverse files to get to the main one to access the global object app.secret_key to change the Flask secret key and be able to escalate privileges knowing this key.

A payload like this one from this writeuparrow-up-right:

Use this payload to change app.secret_key (the name in your app might be different) to be able to sign new and more privileges flask cookies.

Check also the following page for more read only gadgets:

Python Internal Read Gadgetschevron-right

References

circle-check

Last updated