Misc CTF - XSS to CSRF
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:
We have a conversation bot. Sending random sentence doesn’t seem to do anything particular:
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:
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:
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”?
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:
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 | > websocket.send('test') |
This time we got a different kind of message from the server. Interesting. We can try the /help
command:
1 | > websocket.send('/help') |
We got a command to enter moderator mode, that sound perfect:
1 | > websocket.send('/moderator') |
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.
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 | ws = new WebSocket('ws://'+window.location.host); |
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:
References
- Cross-site scripting | Web Security Academy
- Cross Site Scripting (XSS) | OWASP
- Cross-site request forgery (CSRF) | Web Security Academy
- Cross Site Request Forgery (CSRF) | OWASP
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
- Stored XSS on Twitter.com reports | HackerOne
- Reflected Cross site Scripting (XSS) on Starbucks.com | HackerOne
- Cross-Site Request Forgery (CSRF) vulnerability on API endpoint allows account takeovers | HackerOne
- Full account takeover using CSRF | HackerOne
That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!
See you next time ;)
-hg8