WebSocket Fuzzing - Development of a Fuzzer

WebSocket Fuzzing

Development of a Fuzzer

Andrea Hauser
by Andrea Hauser
on April 20, 2023
time to read: 8 minutes

Keypoints

This is how you can approach WebSocket Fuzzing

  • Tool support in the area of WebSockets is not good or not complete
  • If many WebSocket messages are sent by the application, manual testing is nearly impossible
  • A custom script was created which automates the sending and fuzzing of WebSocket messages
  • However, the evaluation of the fuzzed messages must still be done manually by the tester

In a recent project, we encountered a website that communicates almost exclusively via WebSockets. In the past, we had already encountered websites with WebSockets, but only for a small and very specific part of the website. If only a small part of the website interacts with WebSockets, the WebSockets can be tested manually. In this project, however, it became apparent that this approach is not practical for larger projects with more WebSocket interactions.

The tool support is not very advanced in the area of WebSockets, for example, although WebSockets can be captured in Burp and manually manipulated and repeated, there is no way to scan or fuzz WebSocket messages. A quick internet search shows that OWASP ZAP is supposed to have an integrated WebSocket fuzzing functionality, but the tested website could no longer be used as soon as it was passed through ZAP as a proxy, as the WebSocket connections were always closed immediately. Thus, ZAP was also ruled out as a possibility for automated evaluation of WebSockets. A slightly more in-depth internet search reveals some WebSocket fuzzers, but they are very outdated and still based on Python2 and could not be started in current test environments without effort. Accordingly, we decided to create our own WebSocket fuzzing script.

Investing time in developing our own script also makes sense if recent statements by PortSwigger are taken into account in the decision. According to PortSwigger, WebSocket fuzzing is not currently implemented and is something they hope to research in the future. Therefore, in the meantime, as long as there is no support from Burp, a solution of our own has to be found. PortSwigger cites that WebSocket scanning is difficult because it is not easy to determine cause and effect. This issue was also considered in the development of our script and it was decided not to include vulnerability detection logic in the script at this time. Instead, the script only triggers payloads and, if received, records the server’s responses. It is then left to the tester to manually process and interpret the elicited responses and other behaviour of the server. The purpose of the script is to save the tester the manual sending of many WebSocket messages.

Functionality of the Script

The essential requirements for this script were deliberately kept low, so the script only needs to be able to successfully establish a WebSocket connection and then send a payload from a file. This was completed with the following function, shortened for the article:

def fuzzer(cookie, hostname, url, fuzz_values_file, websocket_messages_file, proxy_host, proxy_port, verbose):

    # Read fuzzing payloads from text file
    with open(fuzz_values_file, "r") as f:
        fuzz_values = [payload_parsing(line.rstrip('\n')) for line in f.readlines()]

    # Read WebSocket message from text file
    with open(websocket_messages_file, "r") as messages_file:

        for websocket_message in messages_file:
            websocket_message = websocket_message.strip()
            for fuzz_value in fuzz_values:
                # Create the WebSocket
                if proxy_host is None:
                    ws = websocket.WebSocket()
                    ws.connect("wss://"+hostname+url, cookie=cookie, origin="https://"+hostname)
                else:
                    ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
                    ws.connect("wss://"+hostname+url, cookie=cookie, origin="https://"+hostname,
                               http_proxy_host=proxy_host, http_proxy_port=proxy_port, proxy_type="http")

                # Replace FUZZ_VALUE with attack payload from the file
                message = websocket_message.replace("FUZZ_VALUE", fuzz_value)
                print("\n<----> WebSocket message that will be sent/fuzzed: " + message + "\n")

                # Send the fuzzed message over the WebSocket connection and wait for answer
                ws.send(message)
                ws.recv()
                ws.close()

In the very first version of the script, a manual adjustment of the script had to be made every time a WebSocket message was fuzzed, because the message to be fuzzed was located within the script. This was solved by moving the WebSocket messages to a second file. Although this creates a somewhat unwieldy nested for-loop, it is much easier to use during testing.

Also, in this version of the script, the payload parsing is designed for JSON, as in our case JSON messages were sent via WebSockets. Depending on the WebSocket messages encountered, this would also have to be optimised before fuzzing.

def payload_parsing(payload):
    payload = payload.replace('"', '\\"')
    return payload

The entire script has been made available on our GitHub. There are also examples of its effective use listed.

It is important to note when using this script that the script itself does not make any evaluations of the fuzzing results. This means that it is currently strongly recommended to run the script through a proxy such as Burp, so that the triggered responses can be further evaluated manually afterwards..

WebSocket Testing Tipps

The following are tips for testers on how to use the script for best results: First, analyse how the website builds and sends the WebSocket messages. Sending a message should first be able to be repeated with the script without fuzzing, otherwise fuzzing makes little sense. During our testing, it was found that often more than one message needs to be sent over the WebSocket to get a response from the server. Accordingly, in the script, the possibility was provided to specify such “pre messages” before the actual fuzzing message is processed. The fuzzing of the WebSocket messages themselves is only as good as the compiled fuzzing payloads, accordingly such lists should be compiled with care.

After the messages have been successfully fuzzed, the following can be done to simplify the manual analysis: In the proxy used, only display the messages received from the server in the WebSocket history and sort them by size. This way it can be quickly recognised if there are messages with a deviating size, which can then be evaluated first. It is also possible to manually filter for expected error messages.

In addition to what the script provides in terms of testing possibilities, it should also be noted that there are other WebSocket specific vulnerabilities that are not covered by this script. How these areas of WebSockets can be tested has already been described in detail in one of our earlier Labs articles.

Ideas for Future Enhancements

The following improvements have already been noted for this script and will be developed at a later date:

Conclusion

The provided script can take part of the manual processing of WebSocket messages off a tester’s hands. Testers using this script must however be aware that there is still manual effort involved in evaluating the messages generated by this script. Nevertheless, the script simplifies fuzzing considerably, as it allows far more messages to be sent than would be possible with just manually repeating messages. Although the script has already received some improvements and enhancements during testing, there are still areas where time can be invested to make the script even better to use for testers.

About the Author

Andrea Hauser

Andrea Hauser graduated with a Bachelor of Science FHO in information technology at the University of Applied Sciences Rapperswil. She is focusing her offensive work on web application security testing and the realization of social engineering campaigns. Her research focus is creating and analyzing deepfakes. (ORCID 0000-0002-5161-8658)

Links

You want to test the security of your firewall?

Our experts will get in contact with you!

×
Ways of attacking Generative AI

Ways of attacking Generative AI

Andrea Hauser

XML Injection

XML Injection

Andrea Hauser

Burp Macros

Burp Macros

Andrea Hauser

Prototype Pollution

Prototype Pollution

Andrea Hauser

You want more?

Further articles available here

You need support in such a project?

Our experts will get in contact with you!

You want more?

Further articles available here