At VDA Labs, we get to work on challenging information security problems across many technologies and diverse industries. This broad exposure sometimes gives us unique ideas on how to approach challenges we encounter.
One of these ideas that we have been using with success internally, is related to assessing Web Sockets. There are many great resources about the basics of how Web Sockets work and how to get started assessing them manually, but for the average web application penetration tester, development team, or bug bounty hunter, toolsets for dynamically assessing Web Sockets are quite lacking. For example, one of our favorite web application penetration testing tools, Burp Suite Pro, allows users to intercept Web Socket messages and manipulate them manually (one at a time), but essential functionality like dynamic scanning is not yet available. To help overcome this Web Socket tooling challenge, the VDA team turned to the concept of a fuzzing harness that we typically use during fuzz testing of unmanaged code.
Would you like to be able to leverage traditional web application penetration testing tools during assessments of Web Socket heavy applications? The good news is that by building a Web Socket Harness, you can! By following the example included in this blog post, you can assess Web Sockets with tools like SQLMap, Burp Suite Pro Active Scan, and Commix.
The Web Socket Harness Concept
So how does this concept of a Web Socket Harness function? The idea in its most basic form is to stand up a web server on the loopback interface of your attacking workstation that will act as a “shim” or middle man between your dynamic web scanning tool (like SQLMap), and the Web Socket endpoint you desire to target. The web server running on loopback will receive a traditional web GET request, forward any parameters passed in to the target Web Socket endpoint, return any response from the target Web Socket endpoint, then finally pass the response back to the original web GET request. The diagram below demonstrates how this could work with any dynamic web application pentest tool like SQLMap.
This process will facilitate allowing any dynamic web application penetration testing tool to make traditional web GET requests, and receive back traditional web responses, while the Web Socket Harness handles converting normal web communication to Web Socket communication in the background. Next let’s look at a proof of concept Web Socket Harness written in Python.
Building a Web Socket Harness
To build a quick Proof of Concept, we chose Python because of great web library support and ease of use. This example harness is by no means a production application, but hopefully it can help others get stated with using traditional web penetration testing tools to attack Web Socket applications.
#!/usr/bin/python
import socket,ssl
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
from websocket import create_connection, WebSocket
from urlparse import parse_qs
import argparse
import os
LOOP_BACK_PORT_NUMBER = 8000
def FuzzWebSocket(fuzz_value):
print fuzz_value
ws.send(ws_message.replace("[FUZZ]", str(fuzz_value[0])))
result = ws.recv()
return result
def LoadMessage(file):
file_contents = ""
try:
if os.path.isfile(file):
f = open(file,'r')
file_contents = f.read()
f.close()
except:
print ("Error reading file: %s" % file)
exit()
return file_contents
class myWebServer(BaseHTTPRequestHandler):
#Handler for the GET requests
def do_GET(self):
qs = parse_qs(self.path[2:])
fuzz_value = qs['fuzz']
result = FuzzWebSocket(fuzz_value)
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write(result)
return
parser = argparse.ArgumentParser(description='Web Socket Harness: Use traditional tools to assess web sockets')
parser.add_argument('-u','--url', help='The remote WebSocket URL to target.',required=True)
parser.add_argument('-m','--message', help='A file that contains the WebSocket message template to send. Please place [FUZZ] where injection is desired.',required=True)
args = parser.parse_args()
ws_message = LoadMessage(args.message)
ws = create_connection(args.url,sslopt={"cert_reqs": ssl.CERT_NONE},header={},http_proxy_host="", http_proxy_port=8080)
try:
#Create a web server and define the handler to manage the
#incoming request
server = HTTPServer(('', LOOP_BACK_PORT_NUMBER), myWebServer)
print 'Started httpserver on port ' , LOOP_BACK_PORT_NUMBER
#Wait forever for incoming http requests
server.serve_forever()
except KeyboardInterrupt:
print '^C received, shutting down the web server'
server.socket.close()
ws.close()
This Python script requires a couple command line arguments to get it working. The first argument (“-u”) called “URL” is where you must specify the remote Web Socket endpoint to target. That typically looks something like “ws://dvws.local:8080/authenticate-user” or “wss://dvws.local:8080/authenticate-user” and can be customized for your own use. The second argument (“-m”), called “Message” is a template of the Web Socket message you desire to send to the target Web Socket endpoint. This must reference a file with the guts of the input that the remote Web Socket endpoint is expecting to receive. You can typically obtain this template by watching Web Socket messages between your browser and a target application. The template Web Socket message must have the value “[FUZZ]” placed somewhere that you desire to inject fuzzing input. An example template Web Socket message that we will use later on looks like this:
For the example Web Socket message above, the input location we desire to inject into is the value for the “auth_pass” parameter. The Web Socket harness will replace the “[FUZZ]” placeholder with injected values from our dynamic testing tool.
After creating a template Web Socket message, and choosing a Web Socket endpoint to target, executing the Python script should result in something like this:
To demo this entire process end-to-end, we are going to use this example Web Socket Harness script to attack a vulnerable Web Socket application with SQLMap. Hopefully this makes the concept easier to follow and provides an example to craft for your own needs.
Proof of Concept: Attack Damn Vulnerable Web Sockets
The Damn Vulnerable Web Sockets (DVWS) project was created by OWASP and provides a working example of a vulnerable Web Socket application, which is perfect for this demo. We quickly spun up the docker image version to use as a target application. The goal of this demo will be to use SQLMap and our Web Socket Harness script to find a SQL Injection vulnerability inside a Web Socket request message.
After getting the target application running, the next step involved capturing Web Socket communication for the “Error SQL Injection” page. We proxied our browser through Burp Suite Pro and discovered the following message being sent.
With this information, we created the following Web Socket message template and chose to target the input for the “auth_pass” part of this Web Socket request. By placing the placeholder “[FUZZ]” in the template, the Web Socket Harness script will know what part of the Web Socket message we want SQLMap to inject into.
Next, we started up our Web Socket Harness script, and included the URL to the Web Socket endpoint we wanted to target. As can be observed below, the script started a web server for us to attack with SQLMap on our loopback (http://127.0.0.1) interface. The Web Socket endpoint of “ws://dvws.local:8080/authenticate-user” was passed into the script as the target.
Now that we have everything setup to handle converting normal HTTP GET requests and responses to Web Socket Messages, we can point SQLMap (or any other dynamic testing tool) at our web server running on loopback port 8000, and see if SQLMap finds a vulnerability. We must pass in the GET parameter called “fuzz” which SQLMap will be able to target with injection attempts. In the background, the Web Socket Harness will translate those injection attempts into the “[FUZZ]” placeholder in the Web Socket message template we setup above. As can be observed below, SQLMap quickly identified the SQL Injection vulnerability that exists in the “ws://dvws.local:8080/authenticate-user” page of the DVWS web application.
This same method can also be used to identify Blind SQL or Blind Command Injection vulnerabilities, but due to sensitivity around response timing, we recommend that dynamic testing tools be set to use a single thread when using this particular Websocket Harness script.
Hopefully, this idea we had (in-part from our work writing unmanaged code fuzzing test harnesses for languages like C and C++), helps other web application penetration testers leverage the power of the many traditional web application dynamic testing tools to assess Web Sockets. Perhaps we don’t need to rewrite all of our tools for Web Sockets, a Web Socket Harness can simply be placed in the middle.