Showing posts with label csrf. Show all posts
Showing posts with label csrf. Show all posts

Monday, October 8, 2018

WordPress CSRF Exploit Draft Status

Leave a Comment

How can I best secure WP against a CSRF exploit when creating a new post draft?

If I add a new post and save as draft, I can intercept the request using Burp Suite.

Using the engagement tool in Burp Suite, I can change the value of the post title and paste the URL back in to the browser which creates a new draft with the changed post title.

How can I secure against this?

Cheers

2 Answers

Answers 1

WordPress already provides a CSRF protection mechanism by using a nonce. When creating a new post, a new unique nonce is created. This nonce is required and must be submitted with the rest of the POST data in order for the post to be saved as a draft or be published. If the nonce is not present or invalid, the request is rejected. (Tested with Wordpress v4.9.8)

In your tests you were able to modify the draft because you submitted the correct nonce using Burp, but in a CSRF attack this value would be unknown. Burp is an intercepting proxy, so you practically performed a MITM attack on your own HTTP traffic. If you're concerned about MITM attacks you should use HTTPS. Of course an attacker could still intercept your network traffic, but all the data would be encrypted.

So, I wouldn't say that this is a CSRF exploit, but a MITM exploit. You can protect your WordPress installation from most public exploits by keeping your WordPress version, plugins and thems updated, and also you can find many security related plugins in https://wordpress.org/plugins/tags/security/.

I think the best tool for security tests on WordPress is WPScan. It has a huge database of vulnerabilities and it can detect possible exploits and enumerate users, version and plugins. WPScan is mostly a recon tool, but we can test if the reported vulnerabilities are exploitable with Metasploit or Wpxf, a less known but powerful tool that is specialized on WordPress exploitation. Note that those tools can only detect and exploit public exploits. If you want to discover new vulnerabilities then you could use Burp or similar scanners and study the WordPress source code.

If I have misunderstood the question, and you have a form that doesn't have a nonce (let's say you're writting a plugin), you can add a nonce with wp_nonce_field and then verify it in the script that receives the form with wp_verify_nonce. However, if you have a WordPress installation that doesn't use a nonce with its forms, you shouldn't try to add a nonce manually, but update to a newer version.

Answers 2

Wordpress does not use traditional nonces, instead binding them to a specific form action and user session combination, and persisting them for multiple usage over two ticks (default 12 hours each), which means they are by default valid for up to a full day, and may be repeatedly used over that time period, as well as being "refreshed" after a use to reset their time period entirely. This has been consistently criticized for a number of years by security professionals as misleading and insecure, and the WordPress core team has defended their stance by claiming that the requirement that someone has both the user session as well as the actual nonce makes this a negligible threat, although both a compromised host as well as a site that does not have valid ssl protection can make this pretty easy to accomplish.

The underlying issue you are encountering is symptomatic of the fact that a WordPress nonce is not a nonce at all. It is essentially an access control hash used repeatedly for a short duration for a single form action, and has no mechanism in place to insure its single use. This is why you were able to successfully intercept and re-use the nonce. FYI, this behavior can also be recreated pretty easily in Zed Attack Proxy, Wireshark, Charles Proxy, and numerous other similar utilities. Burp is not the only tool that is capable of uncovering this weakness.

You do however have some recourse to correct this if you want, but it is rather involved and not particularly simple to accomplish.

The following functions are pluggable, which means you can override them with your own, and also control the system interpretation of what a nonce is. You will need to provide your own nonce system using these specific methods, and return identical values to the original expected ones so you don't break plugins/core code functionality:

You could, for example, provide your own nonce implementation using a support from a package such as elhardoum/nonce-php or wbswjc/nonce, and then implement it through a custom plugin that overrides the above pluggable functions and uses them as wrappers for your own nonce implementation, although this is not incredibly straightforward and will require a great deal of custom logic to implement.

You will need to not only override the above pluggable functions, but will also need to call apply_filters similarly to their own source, properly nullify whatever changes plugins attempt to make that are bound to those filters, and also return an expected value in the exact same format as the original so you do not disrupt how other plugins/themes you may be using have implemented them.

If you believe that there is sufficient risk, or that the data your site is safeguarding is of sufficient importance, it is likely worth the effort. If you are not handling financial transactions or sensitive data, are properly secured behind ssl, or have no particular interest in writing a custom implementation of nonces and subsequently maintaining it to work around the ways it inevitably breaks numerous plugins who expect the default lax implementation to be present, then you are probably best off taking the core devs at their word and using the defaults, provided you update frequently, have a strong security plugin like wordfence or sucuri, and routinely run updates on all of your plugins/themes.

As an absolute minimum, you pretty much must have SSL in place to mitigate MITM attacks, and should use proper access control headers to mitigate CSRF.

Read More

Wednesday, March 28, 2018

MVC 5 - Mitigating BREACH Vulnerability

Leave a Comment

I'm hoping someone will be able to help my understanding of this issue and whether or not I need to take any extra steps to protect my application.

Reading up on this particular vulnerability, it seems to impact servers that match the following criteria:

  • Be served from a server that uses HTTP-level compression
  • Reflect user-input in HTTP response bodies
  • Reflect a secret (such as a CSRF token) in HTTP response bodies

It also seems that mitigation steps, in order of effectiveness are:

  • Disabling HTTP compression
  • Separating secrets from user input
  • Randomizing secrets per request
  • Masking secrets (effectively randomizing by XORing with a random secret per request)
  • Protecting vulnerable pages with CSRF
  • Length hiding (by adding random number of bytes to the responses)
  • Rate-limiting the requests

In the view of my page, I'm calling the helper method @Html.AntiForgeryToken which creates the corresponding input and cookie when I visit the form. From looking over what this helper method does, it seems to create a new, unique token each time the page is loaded, which seems to meet point 3 in the mitigation steps and the act of using a CSRF token in the first place meets point 5.

Disabling HTTP compression seems to be widely regarded as 'not good for performance' and from some other resources I've been reading, length hiding could possibly cause issues for functionality like file upload (which this page uses)


So, after all that, the only thing that I can really thing to look at now is separating secrets from user input. I thought about maybe trying to put the CSRF token value into the session.....or am I completely over-thinking this and is the current implementation of '@Html.AntiForgeryToken` good enough to protect us?

1 Answers

Answers 1

Yes if the CSRF token is random, then it mitigates the attack. As long as you aren't sending any other secrets with user input forms you should be okay.

Alternatively,

Disable compression for on pages that have user input is a possibility as well. Checkout this answer Can gzip compression be selectively disabled in ASP.NET/IIS 7?

Read More

Monday, December 18, 2017

.net Core MVC: X-SRF-TOKEN not accepted, 400 returned

Leave a Comment

I have a .net core app using angularJS, and I want to protect the api calls protected by our cookie based authentication. I Followed the steps in this article:

https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery

  • I added the services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); to my services configuration
  • I am seeing the XSRF-TOKEN cookie in my developer tools when loading the page.
  • I am seeing the X-XSRF-TOKEN header being added to my $http sent requests.

  • I have added the [AutoValidateAntiforgeryToken] to my controller that is handling the ajax request.

  • I have ssl enabled, and am accessing the pages via https.

I can make GET requests fine through this api endpoint as expected. However, I am receiving a 400 error without any details of why the request was bad on PUTs and POSTs.

I know the X-XSRF-TOKEN is on the request, (seen in the network tab of chrome dev tools) so I am unsure what I am missing to allow these requests to be received correctly.

TL;DR: Why is .net core rejecting my valid AntiforgeryToken?

UPDATE Attempted @joey's suggested solution, but it did not work, still receiving 400 responses. code below reflects another solution I tried to fix this problem (aka angularjs's solution to setting default cookies and headers for cross site scripting protection)

I have also attempted to configure AngularJS to change what the cookie and header names match what I configured in my Startup.cs. I changed their names to try both XSRF-TOKEN (cookie) and X-XSRF-TOKEN (header) as well as CSRF-TOKEN and X-CSRF-TOKEN, and while the configurations within angular is correctly using the new default to what ever I provide, my authentication code in .net core is still not working.

for more information here is how i am configuring AngularJS:

app.config(function ($httpProvider) {     $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN';     $httpProvider.defaults.xsrfCookieName = 'CSRF-TOKEN'; }); 

here is the ConfigureServices line I have in my Startup.cs file:

services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN"); 

and lastly here is the code I added to the Configure method of the Startup.cs file:

    app.Use(next => context =>      {         string path = context.Request.Path.Value;         if (path.Contains("/MyProtectedPath/"))         {             var tokens = antiforgery.GetAndStoreTokens(context);             context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken,                 new CookieOptions { HttpOnly = false });         }         return next(context);     }); 

UPDATE 2: I have added the following to my controller action:

if (HttpContext.Request.Method.ToLower(CultureInfo.InvariantCulture) != "get") {     await _antiforgery.ValidateRequestAsync(HttpContext); } 

AntiforgeryValidationException: The provided antiforgery token was meant for a different claims-based user than the current user.

I thought maybe antiforgery.GetAndStoreTokens(context) might be overriding the current cookie sent on the page load, so I make it only hit that code on GET requests, but I get the same result for the posts.

2 Answers

Answers 1

In the code you have posted, you are adding the header X-XSRF-TOKEN, but the header should be X-CSRF-TOKEN.

The example from the web page you linked provides the example:

services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");  

Update:

Thanks for clarifying with the additional code & information. The means of implementing CSRF selected here is one which passes the token as a header on the response of the initial HTML file. Here is an example of how such a case might be configured for a SPA web application:

app.Use(next => context => {     string path = context.Request.Path.Value;     if (         string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||          string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase)     )     {         var tokens = antiforgery.GetAndStoreTokens(context);         context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken,              new CookieOptions() { HttpOnly = false });     }      return next(context); }); 

However, with your service configured to using the String.Contains method [1], antiforgery.GetAndStoreTokens(context) is invoked for any path containing /MyProtectedPath/ anywhere. This means it has been configured in such a way that matches not only /MyProtectedPath/, but also /MyProtectectedPath/a/b/c or /a/b/c/MyProtectedPath/.

To check the CSRF token sent in subsequent requests of an applicable HTTP method as shown below:

if (string.Equals("POST", context.Request.Method, StringComparison.OrdinalIgnoreCase)) {     await antiforgery.ValidateRequestAsync(context);     // The line above will throw if the CSRF token is invalid. } 

If the method GetAndStoreTokens is called before this for any matching path, the token will be overwritten before it is checked, which is why .net examples will typically order GetAndStoreTokens first, but with the specific condition for looking at the path and HTTP method.

[1] https://msdn.microsoft.com/en-us/library/dy85x1sa(v=vs.110).aspx

Answers 2

Joey's answer seems to be right. But since you've mentioned it doesn't work for you here's what I had to do to get it working.

First, from the docs:

AngularJS uses a convention to address CSRF. If the server sends a cookie with the name XSRF-TOKEN, the Angular $http service will add the value from this cookie to a header when it sends a request to this server. This process is automatic; you don't need to set the header explicitly. The header name is X-XSRF-TOKEN. The server should detect this header and validate its contents.

Add the AntiForgery service

Add the Antiforgery service to the service collection in Startup.ConfigureServices() after the call to AddMvc():

services.AddAntiforgery(options => {     options.HeaderName = "X-XSRF-TOKEN"; }); 

We're basically telling ASP.NET to look for the X-XSRF-TOKEN header while validating the xsrf token.

Send a cookie with the token

Now on every request from the SPA, we need to send a XSRF-TOKEN cookie with the token value. We can do that with a quick middleware:

// TODO: Refactor this to a separate middleware class app.Use(next => context => {     // TODO: Add if conditions to ensure the cookies     // are only sent to our trusted domains      // Send the token as a javascript readable token     var tokens = antiforgery.GetAndStoreTokens(context);     context.Response.Cookies.Append(         "XSRF-TOKEN",          tokens.RequestToken,          new CookieOptions() { HttpOnly = false }     );      return next(context); }); 

Validate your actions

The easiest way to validate the tokens is to add the [ValidateAntiForgeryToken] attribute. A better option is to configure MVC to apply the AutoValidateAntiforgeryToken globally for all actions with the following in Startup.ConfigureServices():

services.AddMvc(options =>      options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())); 

Read the docs on token validation.

Read More

Monday, October 9, 2017

Can't make lusca CSRF work with https: 403 forbidden

Leave a Comment

This is driving me nuts. I have tried reading the lusca source code but found it hard to understand.

Checked several examples too, but since each config is different, and the only debugging output I have are two strings to compare, I'd better ask for some help!

Here's the code server side:

app.use([ cookieParser(process.env.SESSION_SECRET), session({   resave: false,   saveUninitialized: true,   secret: process.env.SESSION_SECRET,   store: new MongoStore({ url: MONGO_URL, autoReconnect: true }),   cookie: {     secure: process.env.NODE_ENV === 'production'   }, }), lusca({   csrf: true,   xframe: 'SAMEORIGIN',   xssProtection: true, })]); 

And from the clientside, I send Ajax POST requests with the x-csrf-token:l0gH3xmssge53E/p2NsJ4dGnHaSLdPeZ+bEWs= header in it:

fetch(url, {   method: 'POST',   credentials: 'include',   headers: {     'x-csrf-token': CSRF_TOKEN   } }); 

Crazy thing is, it's working locally, but as soon as I go https in production, I get the 403 Forbidden error message.

Here are the versions I use:

"cookie-parser": "1.4.3", "express-session": "1.15.3", "lusca": "1.5.1", 

Also I read this from the express/session doc:

Note Since version 1.5.0, the cookie-parser middleware no longer needs to be used for this module to work.

But as far as I'm concerned, I need to store some persistent ID of the users (longer than the session). I need to use cookies for that, right?

I'd like to understand better on the whole session/cookie thing, but until now I never found any useful resource on the topic.

Thanks!

1 Answers

Answers 1

If you are running your Node.js server behind a proxy you will need to set trust proxy to true:

var isProductionEnv = process.env.NODE_ENV === 'production';  app.use([ cookieParser(process.env.SESSION_SECRET), session({   resave: false,   saveUninitialized: true,   secret: process.env.SESSION_SECRET,   store: new MongoStore({ url: MONGO_URL, autoReconnect: true }),   proxy: isProductionEnv,   cookie: {     secure:isPrudictionEnv,   }, }), lusca({   csrf: true,   xframe: 'SAMEORIGIN',   xssProtection: true, })]);   app.set('trust proxy', isProductionEnv); 

Check out this stack overflow answer. Also check out this page on Express behind proxies.

Read More

Wednesday, September 6, 2017

React frontend and REST API, CSRF

Leave a Comment

React frontend with REST API as backend, authorisation by JWT, but how to handle session ? For example after login i get JWT token from REST, if i save it to localStorage i am vulnerable to XSS, if i save it to Cookies, same problems only if am not setting HttpOnly, but react can't read HttpOnly Cookies (i need to read cookie to take jwt from it, and use this jwt with rest requests), also i didn't mention CSRF problem, if you using REST as backend, you can't use CSRF Token.

As a result React with REST seems like bad solution and i need to rethink my architecture, how to be? Is it possible to offer your users secure react application what have all business logic handled on REST API side without fear to lose their data?

Update:

As far as i understood, there is possibility to do this:

  1. React makes AJAX call to REST API
  2. React gets JWT token from REST
  3. React writes httponly cookie
  4. Because react can't read httponly cookie, we use it as-is in our all REST call where we need authentication
  5. REST on calls checks XMLHttpRequest header, what is some kind of CSRF protection
  6. REST side check for cookie, read JWT from it and do stuff

I have lack of theoretical knowledge here, but looks logic and pretty secure, but i still need an answer to my questions and approve of this "workflow".

2 Answers

Answers 1

1.React makes AJAX call to REST API

assured, lots of restful resource client lib available

2.React gets JWT token from REST

assured, this is what JWT should do

3.React writes httponly cookie

I don't think so, It should not work, but session is not such a important thing, it'll soon get out of date, and recheck password on key operations, even the hackers got it in a very shot time, you can bind session token together with IP when user login and check it in your backend apis. If you want it most secured, just keep token in memory, and redo login when open new page or page refreshes

4.Because react can't read httponly cookie, we use it as-is in our all REST call where we need authentication

assured, check user and permissions through login token, like csrf you can put your login token into your request header, and check it in your backend apis. Bind login token to your own restful lib will save you a lot codes

5.REST on calls checks XMLHttpRequest header, what is some kind of CSRF protection REST side check for cookie, read JWT from it and do stuff

assured, as most people do. Also, bind csrf token to your own restful lib will save you a lot codes

use user token in header https://www.npmjs.com/package/express-jwt-token Authorization JWT < jwt token >

use csrf token in header https://github.com/expressjs/csurf req.headers['csrf-token'] - the CSRF-Token HTTP request header.

restful client https://github.com/cujojs/rest

react with jwt https://github.com/joshgeller/react-redux-jwt-auth-example

Answers 2

Your server can set the JWT cookie directly as a response to the login request.

The server responds to POST /login with Set-Cookie: JWT=xxxxxx. That cookie is http only and therefore not vulnerable to XSS, and will be automatically included on all fetch requests from the client (as long as you use withCredentials: true).

CSRF is mitigated as you mentioned, see OWASP for details.

Read More

Monday, March 21, 2016

How can I prevent SSRF via pathinfo passing a URL in PHP?

Leave a Comment

After scanning through our code using Acunetix for vunerabilities, we had an issue with the following script which said:

"An HTTP request was initiated for the domain hit0yPI7kOCzl.bxss.me which indicates that this script is vulnerable to SSRF (Server Side Request Forgery)."

How can I prevent this?

<?php $filename = strip_tags($_GET['url']);  if (substr($filename,0,4) !== 'http') {     die("Need a valid URL..."); }  $ext = pathinfo($filename, PATHINFO_EXTENSION);   switch ($ext) {     case "gif":         header('Content-Type: image/gif');         readfile($filename);         break;     case "png":         header('Content-Type: image/png');         readfile($filename);         break;     case "jpg":     default:         header('Content-Type: image/jpeg');         readfile($filename);         break; } ?> 

1 Answers

Answers 1

Source if issue in your case is that with your server will try to fetch data from any passed url. Given it has http://google.com inside url parameter, script will respond with actual google website contents.

Why its bad? That, for example, could be exploited to circumvent your firewall settings, access internal network of your server or pollute socket connections so your server will be unable to connect or be connected to and will become unresponsive.

First of all you should think if you really want to serve your static files with PHP. Most likely this responsibility could be delegated to web server. Its even possible to "serve" static from 3rd party website with current webservers, so you should seriously consider getting rid of that code.

If you 100% sure you want to use with PHP in that case, you should add restrictions to your code.

  1. add domain whitelist, so that will allow usage of trusted domain list only inside url variable;
  2. do not process files with unknown extensions.

In that case code will look like this:

<?php  $whitelist = [     'some.whitelisted.com',     'other.whitelisted.com' ];  $extensionMap = [     'gif'  => 'image/gif',     'png'  => 'image/png',     'jpg'  => 'image/jpeg',     'jpeg' => 'image/jpeg' ];  $filename = strip_tags($_GET['url']);  $host = parse_url($filename, PHP_URL_HOST);  if(empty($host) || !in_array($host, $whitelist)) {     header('HTTP/1.1 404 Not Found');     exit; }  $ext = pathinfo($filename, PATHINFO_EXTENSION);  if(!isset($extensionMap[$ext])) {     header('HTTP/1.1 404 Not Found');     exit; }  header(sprintf('Content-Type: %s', $extensionMap[$ext])); readfile($filename); 
Read More

Tuesday, March 8, 2016

JasperServer proxy CSRF error

Leave a Comment

I have a new installation of JasperReports Server 6.2 using the bundled Tomcat on Ubuntu 14.04 LTS with an Nginx proxy so I can access https://mydomain.xyz/jasperserver. It mostly works, but I'm not able to manage users and roles. If I bypass Nginx and go straight to Tomcat http://123.123.123.123:8080/jasperserver, everything works perfectly. The log indicates:

2016-02-28 19:44:08,024 ERROR CsrfGuard,http-nio-8080-exec-3:44 - potential cross-site request forgery (CSRF) attack thwarted (user:, ip:127.0.0.1, uri:/jasperserver/flow.html, error:required token is missing from the request)

This is exactly the same as this older question: Running jasperserver behind nginx: Potential CSRF attack. But I've tried both mitigations suggested, and it's still not working.

  • I tried setting underscores_in_headers on;, first in just http, then in server, then in both.
  • When that didn't work, I removed the underscores from JASPER_CSRF_TOKEN and OWASP_CSRFTOKEN in WEB-INF/esapi/Owasp.CsrfGuard.properties

I rebooted the server just to be sure everything was cleared and restarted, but still not working.

I'm seeking suggestions for a resolution and/or guidance on where to look to diagnose the problem better. I'm new to Jasper and my Java/Tomcat skills are rusty.

1 Answers

Answers 1

to solve your problem, i think you forgot to allow underscores in nginx headers

server { underscores_in_headers on;

Read More