A page of ideas on how I would look to compromise Django applications..
Django comes with a automatic HTML escaping filter, so most XSS is stopped by the automatic escaping in views
- There are places where it doesn't work (e.g https://docs.djangoproject.com/en/3.0/ref/templates/language/#automatic-html-escaping)
- If you use it inside tag attributes, you could escape the attribute and set other attributes (e.g. onclick)
- It needs to be enabled in the MIDDLEWARE setting in settings.py. A lot of Django developers wouldn't think to check and might have accidentally removed it
- A developer might have had issues with it escaping, googled it and found a StackOverflow question saying to add the
'safe'filter, inadvertantly adding an XSS flaw to their page
Other thoughts
- Does it apply to all view engines?
- What about templates that set properties in JavaScript content?
- This only applies to the view renderer. XSS is defacto on most sites with 3rd party javascript keystroke skimming see magecart
Django's ORM has parametrized query models, so cannot be used for SQL injection. However..
- You can run SQL queries on the database, using
raw()orcursor.execute(). Django lures you into thinking that parameterised queries protect you from SQL injection, but if you HAVE encapsulated your parameters with quotes, they could be escaped. e.g.cursor.execute("SELECT * FROM users WHERE id = '%s'", [id])could easily be escaped withid=' OR 1=1 - A developer might set a scheduled job to run in a seperate Python script and write SQL directly from external input, e.g. database
- A developer might user another ORM tool, which has it's own caveats
Django has a CSRF middleware module which catches most CSRF attacks. However..
- It must be listed in MIDDLEWARE
- Every
<form method=POSTmust contain{% csrf_token %}otherwise it does nothing against CSRF attacks. I could see many people forgetting this - AJAX queries to view methods or API view methods must use the
X-CSRFTokencustom header, use the CSRF cookie or include the csrf token in the POST values. The developer must rememeber to do all of those things!
As it's easy to guess the login of the Django default admin/ app, it would be easy to sit and dictionary attack the admin login.
The username, URL are both known quantities. Anyone who has ever watched web server logs would know how often admin/ and wp-admin/ gets hammered by bots.
Third party authentication modules can have the following challenges:
- Configuration is complex, complexity leads to mistakes (or copy+pasting from SO), especially with complex protocols like OAuth, OpenID, etc.
- Third party modules may have known/undisclosed security issues. Developers are unlikely to check all of their Django dependencies
- (repeat of the auth challenge) Third party modules may have known/undisclosed security issues. Developers are unlikely to check all of their Django dependencies
Many sites don't update their Django versions as Django revisions frequently have breaking changes, AND, most Django apps rely on 3rd party modules which may not reliably support new versions.
There is a fairly substantial list of Django CVEs https://www.cvedetails.com/product/18211/Djangoproject-Django.html?vendor_id=10199 All you have to do is figure out which version the site is running (by trying the attack or getting the app to leak information)
Session hijacking is simple to accomplish if:
- The site uses permanent sessions (via a database or other store) and the linkage to the user is bound via an easily-manipulatable property, e.g. URL param, IP address etc.
- The site uses client-based (i.e. non-permanent sessions)
Applications which are configured with APIs are likely to configure permanent sessions, or use an API token.
- Django's default session engine
- https://docs.djangoproject.com/en/3.0/topics/http/sessions/#topics-session-security
This is just a game of looking up all uses of Pyyaml and the pickle module.
- Using the [PickleSerializer] as the session engine means an attacker can put arbitrary code inside their session data, serialize it using Pickle from the client. Requires knowledge of SECRET_KEY See
- Any application that takes YAML input yaml.load(load=Loader)
- Using Django's file-based caching mechanism (would depend on the way app is written). An attacker could input data which is then cached, e.g. an image or avatar. Instead of uploading an avatar, the attacker would upload a file with Pickle data and code to be executed. The caching engine would load the cached instance from a file and execute the code.
- Developers need to use decorators (or configuration) to set which permissions are required for that view. They would forget, or put the wrong ones on.
Not specific to Django, but easy to find and test in most web frameworks.
- In web application, site shows a list of items, e.g. "Order History", each is clickable to a view. e.g.
orders/id/view/. A view/route takes an "ID" or other reference type and then shows the data. Does not verify that entity belongs to that user on the second step. Attacker swaps ID for another users' ID. - A POST form view takes data from a form. Form contains hidden "ID" field with the ID of the entity that is being changed. Attacker swaps ID in POST (using burp or something similar) for another ID to edit another users' data. This can easily be used for resetting passwords, given themselves higher access, leaking info, etc.
- An AJAX request has ID of entity in POST, attacker swaps ID key using burpsuite.
Impact versus complexity, I would rank them in order most-likely and biggest impact::
- Easily guessable admin logins
- Parameter manipulation
- SQL injection
- RCE using caches
- XSS via 3rd party JS libs
- Known CVEs