-
-
Notifications
You must be signed in to change notification settings - Fork 732
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
Template code injection -- remote vulnerability #1359
Comments
It looks like it was intentional. @maraujop commited, that BaseInput value can be a variable now. So I guess it could be used somewhere and it is required for backwards-compatibility, maybe. But what I also guess is that nobody actually thought, that the variable value could be passed straight from the web. As it could be context variable, maybe it could be better to just support a simple form of template like Supporting whole full blown template by using |
Proposed fix for live projects -- just monkey patch it. But beware, you will loose the functionality of the BaseInput value being a context variable.
|
Proof of concept:
This will lead to rendering of the value in the HTML:
|
Hi @mpasternak, I'm not one of the decision makers here, but I've been using django-crispy-forms for a while now and maybe I can help. Here are my 2 cents:
Fieldset(
"Zaloguj się!",
"username",
"password",
Hidden("next", "{{next}}"),
), |
I am not sure if you understand the impact. Every input field, hidden or visible, in django-crispy-forms renders its value as a template, because of the code in BaseInput class. Input fields are usually filled with, well, user input. The rule is that you don't want to allow user input to run server-side. This is why things like https://github.com/ivelum/djangoql exist, you don't want to allow people to run SQL queries or Python code on the server, that's why you try to limit it. The approach of rendering user input as a template in my opinion is a gaping security hole, waiting to be exploited, or exploited already. Why would somebody try to login to my site with a prepared "?next=/1/{{123+123}}" query? I hope you did not miss that part of my post. For me, this was probably a scanner. I am not sure if it was looking for Django sites actually, but as the original contributor of the code found this approach of rendering value as a template useful, then probably others also did. As all the input fields use this code, this is not a case of fixing a single login form. Sorry. |
The first time I saw this ticket I got concerned because I use django-crispy-forms in all my projects. I also maintain https://github.com/ckrybus/crispy-bulma and my project would be affected too. So I spend over 1 hour investigating it and I came to the conclusion that the way Hidden is being used in your code fragment leads to a vulnerability, but it is not a "real" vulnerability. That said, since it is so easy to use Hidden this way I'm for better docs or some asserts or something else. @mpasternak did you try my solution? The error does not occur anymore, right? The reason it works is because it is being read from the context which is being properly escaped. If you pass it directly to Hidden then it becomes part of the template. All classes inheriting from In my opinion putting a return HttpResponse(request.GET["next"]) --> unsafe, XSS risk, it bypasses the escaping part of django I might be wrong on this of course ( I'm > 99% sure) that's why I'm also impatiently awaiting a response from django-crispy-forms maintainers on this issue, I'm sure it'll come soon :-) |
I did not try your solution as I monkey-patched django-crispy-forms code in my site so the problem will not occur. I get the idea of having the value of the field being parsed as a template and I think it could be useful for some corner-cases, but this is a gaping security hole. As per the code using it, this is standard Django Also, disabling django-crispy-forms on that particular login form with hidden field makes the error go away. So this is not just passing unvalidated data to the form. This is passing a user-provided value to the code that tries to render it as a Django template, making it possible to get every single value from the context and probably to load custom tag libraries and then to call those. Please contact me on my e-mail if you have any live sites and you still doubt this is a security hole. |
yes, I've also tested that. But this code gets executed when you submit the form. You can try to edit the next field in the DOM directly and put "/1/{{value+value}}" as value there, there will be no error, it will be interpreted as a string value. The "vulnerability" you are writing about is in the initial form rendering phase. DM sent :) |
The class name is |
OK, I think there's some confusion here… — there are two things going on:
The take home message is that any redirect value from the request should always use Django's tools for handling redirects, rather than trying to do that raw oneself. I don't (thus far) see an issue in 1. 2 is Django's responsibility, and not an issue in Crispy Forms. I hope that makes sense? I'll leave this open for an extra pair of eyes for the moment. Thanks. |
OK, I'm going to close given no follow up. |
Title:
django-crispy-forms renders hidden input elements in a way, that allows remote template code injection attack.
Sorry for reporting this publicly, but I see there is no security policy for this repository.
Description:
I am using
django-crispy-forms
to render a typical login form like:The URL to this view looks like:
The form looks nothing special:
Recently I noticed suspicious activity in the log files. Possibly a malicious user sending requests like:
http://127.0.0.1:8000/accounts/login/?next=%2F%2A1%2A%2F%7B%7B833316405%2B810976201%7D%7D
Which actually resolve to
http://127.0.0.1:8000/accounts/login/?next=/*1*/{{833316405+810976201}}
By accessing this URL, I get an error:
So obviously the code from the ?next= variable gets executed.
I think the code that is responsible for the bug is this part (sorry for the screenshot but it shows the problem I hope a bit more clearly than the text itself) -- see below.
When executing the code in layout.py line 256 function render, self.value is '/1/{{833316405+810976201}}'. This value, after being converted to a string, is used as the actual template. It can not be parsed, obviously, this is why I get the error. But it looks like there is no problem with passing any other value that would be executed in the template context.
Why the self.value of the hidden input (or any kind of
inputbutton, submit, reset buttons) would be converted to a template, then rendered is a mystery, if you ask me. Probably something that django-crispy-forms devs could help explaining.The text was updated successfully, but these errors were encountered: