Skip to content

V33RU/wsdos-iotdevice

Repository files navigation

wsdos

WebSocket security testing framework for IoT, automotive, and connected devices.

⚠️ Authorized testing only. This tool is built for IoT security research, red-team engagements, and stress-testing your own embedded devices. Running it against systems you do not own or have explicit written permission to test is illegal in most jurisdictions and unethical everywhere. The author accepts no responsibility for misuse.

wsdos started as a 35-line WebSocket connection-flood PoC in 2019. v3.x is a real framework: passive vulnerability scanning, known-CVE fingerprinting, frame-level fuzzing, vendor presets for the most common IoT / robotics WebSocket endpoints, and the original DoS modes (now async). v3.1 hardened the detection logic so every finding is falsifiable; see CHANGELOG.md.

What's included

7 vulnerability checks (passive, non-destructive)

Check Detects
cswsh Missing or weak Origin enforcement → Cross-Site WebSocket Hijacking
auth Endpoints accepting no auth at all, JWT alg:none, tokens in query strings
compression permessage-deflate amplification (CVE-2020-7662 family)
frames RFC 6455 violations: unmasked client frames, bad RSV bits, reserved opcodes, oversize length, dangling continuations
smuggling HTTP request smuggling at the Upgrade boundary
tls Plaintext ws://, obsolete TLS versions, weak ciphers, untrusted certs
cves Fingerprint matching against 4 verified WebSocket CVEs in the ws (npm), websocket-extensions, and socket.io-parser stacks

5 attack modes (require --i-have-authorization)

Mode Pressure pattern
flood Maximize concurrent open connections (fd / accept-loop exhaustion)
slowloris Hold many sockets open with periodic 1-byte frames (timeout-budget)
frame-flood Blast rapid small frames over few connections (parser CPU)
payload Send oversized frames (memory pressure)
compression Ship highly-compressible payloads (decoder DoS)

8 vendor presets across 3 categories (verified against vendor docs)

Category Presets
robotics ros1-rosbridge, ros2-rosbridge, foxglove-bridge
iot-smart-home home-assistant, esphome-dashboard, shelly-gen2-rpc, tasmota-console
iot-3dprinter octoprint

Every preset cites its primary source URL in wsdoscore/presets.py. Earlier versions of this README listed ~18 presets across 7 categories; that table contained guesses for vendors whose protocols I had not verified. v3.1.0 removed the unverified entries. PRs adding new verified presets (with a primary source cite) are welcome.

Install

git clone https://github.com/V33RU/wsdos-iotdevice.git
cd wsdos-iotdevice
pip install -r requirements.txt

Python 3.8+.

Quick start

Recon a target (single safe handshake)

python3 wsdos.py probe ws://192.168.1.42:8080/

Full vuln scan (all 7 checks, no attack)

python3 wsdos.py scan ws://192.168.1.42:8080/ --format pretty

Output (pretty, with confidence annotation per finding):

=== wsdos scan report ===
Target: wss://192.168.1.42:8080/
Findings: 8

Summary: [HIGH] 2  [MEDIUM] 1  [INFO] 5

[HIGH] (high) cswsh.origin-enforcement No Origin enforcement: every Origin (including attacker.example, null, file://) is accepted
      baseline_no_origin_accepted=True (ok). 6/6 forged Origins accepted: ...
      -> https://owasp.org/www-community/attacks/Cross_Site_WebSocket_Hijacking_(CSWSH)

[HIGH] (medium) auth.handshake-open WebSocket handshake accepts unauthenticated clients
      Server completed the handshake with no Authorization / Cookie / X-API-Key header.
      This is acceptable only if the application enforces auth in the first WS message.

...

Single vuln check

python3 wsdos.py vuln cswsh ws://192.168.1.42:8080/
python3 wsdos.py vuln cves ws://target/
python3 wsdos.py vuln tls wss://device.lan/ws -k

Use a vendor preset

# list everything we know
python3 wsdos.py preset list

# show details
python3 wsdos.py preset show ros2-rosbridge

# scan with the preset's defaults (right port, path, scheme)
python3 wsdos.py preset scan shelly-gen2-rpc 192.168.1.50
python3 wsdos.py preset scan ros2-rosbridge 10.0.0.7
python3 wsdos.py preset scan home-assistant 192.168.1.100 --format markdown -o ha.md

Reports

# pretty (default)
python3 wsdos.py scan <target>

# JSON for piping
python3 wsdos.py scan <target> --format json > report.json

# Markdown for tickets / engagement reports
python3 wsdos.py scan <target> --format markdown -o report.md

Filter checks

python3 wsdos.py scan <target> --only cswsh,auth,tls
python3 wsdos.py scan <target> --skip frames,smuggling

Attack modes (require explicit consent flag)

python3 wsdos.py flood ws://192.168.1.42:8080/ -n 5000 -c 500 -d 60 \
  --i-have-authorization

python3 wsdos.py slowloris ws://192.168.1.42:8080/ -n 800 -i 20 \
  --i-have-authorization

python3 wsdos.py frame-flood ws://192.168.1.42:8080/api -w 20 --payload-size 256 -d 30 \
  --i-have-authorization

python3 wsdos.py payload ws://192.168.1.42:8080/ -w 5 --payload-size 8388608 --frames 50 \
  --i-have-authorization

python3 wsdos.py compression wss://device.lan/ws -k -w 4 --payload-size 10485760 -d 30 \
  --i-have-authorization

Known CVEs covered by the cves check

Every entry has been verified against NVD. Earlier versions of this README listed 10 CVEs; on verification, six of them either pointed to unrelated products (Apache UIMA, Traefik, Taiwanese-language packages) or were real CVEs but not WebSocket-specific. v3.1.0 trimmed the registry to the four that are both real and WebSocket-specific:

CVE Stack Severity
CVE-2020-7662 websocket-extensions (Node.js) < 0.1.4 , ReDoS via Sec-WebSocket-Extensions header HIGH (7.5)
CVE-2021-32640 ws (npm) 5.0.0-6.2.1, 7.0.0-7.4.5 , ReDoS via Sec-WebSocket-Protocol header MEDIUM (5.3)
CVE-2024-37890 ws (npm) < 8.17.1 , DoS via requests exceeding server.maxHeadersCount HIGH (7.5)
CVE-2023-32695 socket.io-parser 3.4.0-3.4.2, 4.0.4-4.2.2 , DoS via crafted packet (uncaught exception) HIGH (7.5)

The check is a fingerprint match against Server/X-Powered-By response headers, not active exploitation. A match is a hint, not proof , always verify the installed version against the affected range before reporting. PRs adding more verified WebSocket CVEs (with NVD link + primary advisory) are welcome.

Where the WebSocket lives, by device class

Verified preset coverage (everything below has a primary-source citation in wsdoscore/presets.py):

Device class Typical paths / ports What to test
Shelly Gen2/Gen3 relays /rpc on :80 auth, cswsh (often no auth at all on LAN)
Tasmota firmware /ws on :80 auth, cswsh
ESPHome dashboard / on :6052 auth, cswsh
Home Assistant /api/websocket on :8123 auth (token bypass), cves
OctoPrint (3D printer) /sockjs/websocket on :5000 cswsh, auth
ROS 1/2 rosbridge / on :9090 auth (default = NONE), frames, see iotsrg/awesome-ros-security
Foxglove bridge / on :8765 auth, compression

Not yet covered (would welcome PRs with vendor-doc citations): industrial fieldbus-over-WS (Modbus / BACnet / OPC UA), automotive (OBD WiFi, Tesla firehose, OVMS), IP cameras with proprietary WS bridges, building management (Niagara N4). Earlier versions of this README claimed coverage of those; on verification the entries were guesses, so v3.1.0 removed them.

Architecture

wsdos.py                # CLI dispatcher
wsdoscore/
├── __init__.py
├── common.py           # Metrics, URL helpers, Finding dataclass
├── recon.py            # probe command
├── stress.py           # 5 attack modes
├── presets.py          # 8 vendor presets (each with source citation)
├── report.py           # JSON / pretty / Markdown emitters
└── vuln/
    ├── __init__.py     # CHECK_REGISTRY
    ├── cswsh.py        # Cross-Site WebSocket Hijacking
    ├── auth.py         # no-auth, JWT alg:none, query-string tokens
    ├── compression.py  # permessage-deflate amplification
    ├── frames.py       # raw-socket RFC 6455 fuzzing
    ├── smuggling.py    # HTTP/WS upgrade-boundary smuggling
    ├── tls.py          # plaintext, weak versions, weak ciphers, untrusted certs
    └── cves.py         # known-CVE fingerprint registry

Adding a new vuln check:

  1. Create wsdoscore/vuln/<name>.py exporting async def check(args) -> list[Finding]
  2. Register in wsdoscore/vuln/__init__.py
  3. wsdos vuln <name> and wsdos scan pick it up automatically.

What to look for during a live engagement

Symptom Likely root cause
Connections cap out at ~1020 ulimit -n on a per-process fd limit
Server stops accepting after N seconds Per-IP connection cap or accept-queue exhaustion
CPU pegged but accept still works Single-threaded WebSocket handler
handshake_rejects jumps to non-zero Server-side rate-limiting kicked in (good!)
Web UI unreachable during flood No separation between control-plane and data-plane
Device reboots / freezes Watchdog or OOM kill
cswsh reports HIGH Browser-based attack chain becomes available
auth.no-auth-accepted HIGH Anyone on the LAN can drive the device
frames.rfc6455-compliance HIGH Custom parser; consider deeper fuzzing
tls.plaintext HIGH All traffic visible to on-path attackers

Reporting bugs you find on real devices

Please follow coordinated disclosure with the vendor.

Demo (legacy)

The original 2019 PoC video is still in the repo:

Original demo: https://www.youtube.com/watch?v=GhhDNFVsQBc

License

MIT, see LICENSE.

Author

@V33RU / IOTSRG

See also:

About

websockets multiple connection requests makes to web or device to get down the web page

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages