Misc CTF - XSS to CSRF

— Written by — 4 min read

This challenge highlight two issue at once: the very common Cross Site Scripting (XSS), Cross-site request forgery (CSRF) and how both vulnerabilities can be chained.

Tl;Dr: You have to exploit a XSS vulnerability chained with CSRF in order to access a protected Websocket endpoint.

Alright! Let’s get into the details now!


Recon

Opening the challenge displays the following application:

misc ctf chatbot

We have a conversation bot. Sending random sentence doesn’t seem to do anything particular:

misc ctf chatbot chat

Cross-site Scripting (XSS)

While playing around we can quickly notice it’s possible to inject HTML. If we pass the message <s>Hello</s> it gets displayed as HTML:

misc ctf html injection

This is open door to XSS right ?

Let’s try a common one:

1
<img src=x onerror=alert(1)>

The XSS payload gets executed when the message gets displayed:

misc ctf chatbot xss

Well that’s nice but it’s only Self-XSS so far, since a bot handled the conversation the XSS won’t trigger on its side…

Let’s move on.

Bad words

Then we notice this warning:

This chatbot is a safe-place, badwords are prohibited!

Well I wonder what will happen if we use “bad words”?

misc ctf chatbot bad words

Interesting. It seems like a human is still interacting with some chat messages if they contains bad words. It’s good to know maybe we can use our XSS on the moderator side…

Websocket

Let’s now try to understand how the app is communicating with the server.
Opening our Browser Dev tools we don’t notice any HTTP requests being made but we can see a Websocket connection is opened.

The WebSocket API is an technology that makes it possible to open a two-way interactive communication session between the user’s browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.

https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

That make sense for our use case. Still using the browser dev tools it’s possible to looks at the messages sent and received from the server:

misc ctf chatbot websocket

Let’s now try to directly interact with the WebSocket (with a bit of luck maybe we could inject something directly?).

Using the browser dev tool console we create we a new connexion with the server:

1
> websocket = new WebSocket('ws://misc.ctf:33433/');

Then setup a little function to display on the console the server response:

1
> websocket.onmessage = function(message) { console.log(message.data); }

We should now be able to send and receive messages. Let’s give it a try:

1
2
> websocket.send('test')
Unrecognized message, type /help for a list of command

misc ctf websocket chatbot connexion

This time we got a different kind of message from the server. Interesting. We can try the /help command:

1
2
3
> websocket.send('/help')
{ "content": "<message>" } to send a message
/moderator to enter moderator mode debugger

We got a command to enter moderator mode, that sound perfect:

1
2
> websocket.send('/moderator')
You need to be authenticated to execute this command

That would have been too easy… But with all the informations we got so far we can probably find a way to access this endpoint right ?

Cross-site Request Forgery

We have XSS and a protected endpoint we need to access. It’s the perfect scenario for CSRF.

Cross-site request forgery (also known as CSRF) is a web security vulnerability that allows an attacker to induce users to perform actions that they do not intend to perform. It allows an attacker to partly circumvent the same origin policy, which is designed to prevent
different websites from interfering with each other.

https://portswigger.net/web-security/csrf

portswinger csrf

In our case we are going to use Cross-site Scripting in order to have a moderator access /moderator endpoint for us.

We got a Javascript code to access /moderator endpoint using WebSocket:

1
2
ws = new WebSocket('ws://'+window.location.host);
ws.onopen = () => ws.send('/moderator');

Let’s include it to our XSS payload:

1
<img src=x onerror="ws=new WebSocket('ws://'+window.location.host);ws.onopen=()=>ws.send('/moderator')">

Last step, we need to include a “bad word” in our message so it gets transferred to a Moderator which have access to /moderator endpoint. The final payload should be the following:

1
🖕 <img src=x onerror="ws=new WebSocket('ws://'+window.location.host);ws.onopen=()=>ws.send('/moderator')">

Let’s send it as message and see the result:

misc ctf xss csrf flag

References

Prevention Methods

  • Filter input on arrival. At the point where user input is received, filter as strictly as possible based on what is expected or valid input.
  • Encode data on output. At the point where user-controllable data is output in HTTP responses, encode the output to prevent it from being interpreted as active content. Depending on the output context, this might require applying combinations of HTML, URL, JavaScript, and CSS encoding.
  • Use appropriate response headers. To prevent XSS in HTTP responses that aren’t intended to contain any HTML or JavaScript, you can use the Content-Type and X-Content-Type-Options headers to ensure that browsers interpret the responses in the way you intend.
  • Content Security Policy. As a last line of defense, you can use Content Security Policy (CSP) to reduce the severity of any XSS vulnerabilities that still occur.
  • See -> Cross Site Scripting Prevention Cheat Sheet for more.

Real Life Examples


That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!

See you next time ;)

-hg8



CTFMisc
, , , ,