Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CORS example exploitation demo has no 'protected' page to 'exploit' #135

Open
chrisdlangton opened this issue Nov 22, 2021 · 0 comments
Open

Comments

@chrisdlangton
Copy link

chrisdlangton commented Nov 22, 2021

The main problem is the entire demo relies on this package, and is default insecure.

from flask.ext.cors import CORS, cross_origin
app = Flask(__name__, static_url_path='/static', static_folder='static')
@app.after_request
def add_headers(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
return response

The package that is meant to be an example of enabling CORS, is actually inherently insecure too!

It defaults to disable CORS protections, not demonstration enabling CORS

I.e. putting Access-Control-Allow-Origin: * is not enabling CORS, it is telling the browser to disable same-origin policy protections for CORS and allow all origins, not allow a specific cross-origin to share resources with.

Essentially this demo snippet:

@app.route("/protected", methods=['GET'])
def protected():
    return "protected"

This is not enabling CORS, or protected by CORS protections. it is unprotected by design.

The next snippet in the demo implies the application has enabled CORS:

@app.route("/allowed", methods=['GET'])
@cross_origin()
def allowed():
    return "allowed"

That use of @cross_origin() implies enabling CORS, but without the attribute origins it just means there are no allowed origins, and it will use the decorator default origin setting to allow all origins..

all origins is an important semantic because CORS is a protection to permit only allowed origins to share resources with, so enabling CORS should add this protection of only allowed origins! When you allow all origins, not just a permitted origin, you effectively disable CORS protections and force the behaviour no cross-origin resource sharing because, public is just public, it's not cross-origin when all origins are ignored and the resources are just shared to any origin.

What the demo actually does

Firstly it's easy to see that /protected has not enabled any CORS configuration to protect anything, the default disabled same-origin policy and allowed all origins, so the method is deliberately unprotected - ergo /unprotected, and there is no part of the demo app that has any actual protected paths to be exploited.

There is no way to demo an exploit if there's nothing to exploit in the demo..

What would make this demo, an actual demo of exploiting CORS

If there was a protected path in this demo, to exploit, CORS would actually be enabled

@app.route("/protected", methods=['GET'])
@cross_origin(origins=["app.realdomain.tld"])
def protected():
    return "protected"

NB: the list for origins is misleading, only 1 origin is a valid value: corydolphin/flask-cors#300

Current demo can never be a good demo

As long as the @app.after_request to always send Access-Control-Allow-Origin: *

The confusion is /allowed , what is the intention? it uses @cross_origin() without an origin, so does that mean it intended it to be same-origin? We covered above that it doesn't act this way by default, so does that mean the demo intended this /allowed path to be all origins? If that is the intention then using @cross_origin() is redundant and if you delete the decorator the behaviour is completely unchanged because you have @app.after_request to always send Access-Control-Allow-Origin: * (which is default for @cross_origin())

Which in itself is a massive problem because the entire demo will always respond with Access-Control-Allow-Origin: * and importing cross_origin at all is redundant, even my example improved /protected method that defined an allowed origin is redundant because @app.after_request makes all origins always allowed!

A better demo

To actually have a demo that shows an exploitation of CORS, you must first have a server-side demonstration of using CORS to permit only an allowed origin to the /protected path. Then the exploit would need to demonstrate how to access the /protected path from a malicious origin (which is not actually possible using a browser, but can be demonstrated using cURL or other non-browser clients)

Be honest, not a leet haxor exploit demo..

Misconfiguration demo is still a very good demo, it doesn't need to be called an exploit!

Just be honest, and say that the demo is showing how an intentionally insecure by-design app, that completely misconfigures CORS, can be exposing parts of your app you assumed were protected.

There is no exploit but rather an honest demo, without all the hyperbolic hacker nonesense, just a truthful humble demo of what a misconfiguration looks like. And the entire demo language changes to something that a developer (and most normal people) can relate too, and therefore actually find useful and learn from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant