Skip to content

Commit 3e816be

Browse files
authored
Merge pull request #218 from pf-msi/cross-site-websocket-hijacking
Add active scan script for Cross-Site WebSocket Hijacking validation
2 parents 4e7e465 + a3227db commit 3e816be

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ All notable changes to this add-on will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

66
## [Unreleased]
7+
### Added
8+
- active/Cross Site WebSocket Hijacking.js > an active scan for Cross-Site WebSocket Hijacking vulnerability
9+
710
### Changed
811
- Update links in READMEs.
912
- Update JavaDoc links to latest version.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Copyright (C) 2021 Motorola Solutions, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Author: Piotr Furman <piotr.furman at motorolasolutions.com>
19+
*
20+
* Description:
21+
*
22+
* Script to validate potential Cross-Site WebSocket Hijacking vulnerability.
23+
*
24+
* According to RFC 6455, section 10.2 Origin Considerations:
25+
*
26+
* "Servers that are not intended to process input from any web page but
27+
* only for certain sites SHOULD verify the |Origin| field is an origin
28+
* they expect. If the origin indicated is unacceptable to the server,
29+
* then it SHOULD respond to the WebSocket handshake with a reply
30+
* containing HTTP 403 Forbidden status code."
31+
*
32+
* Which means we can try to repeat WebSocket HTTP Upgrade request with
33+
* a modified Origin header and raise an alert if it was accepted.
34+
*
35+
* Note: Run ajax spider before a scan in order to evaluate your application's
36+
* JavaScript code which opens WebSocket connection.
37+
* Note: Active scripts are initially disabled, right click the script to enable it.
38+
*/
39+
40+
var Base64 = Java.type("java.util.Base64")
41+
var Random = Java.type("java.util.Random")
42+
var String = Java.type("java.lang.String")
43+
var ByteArray = Java.type("byte[]")
44+
45+
var LOG_DEBUG_MESSAGES = false // change to true for more logs
46+
47+
var RISK = 3
48+
var CONFIDENCE = 2
49+
var TITLE = "Cross-Site WebSocket Hijacking"
50+
var DESCRIPTION = "Server accepted WebSocket connection through HTTP Upgrade request with modified Origin header."
51+
var SOLUTION = "Validate Origin header on WebSocket connection handshake, to ensure only specified origins are allowed to connect.\
52+
Also, WebSocket handshake should use random tokens, similar to anti CSRF tokens."
53+
var REFERENCE = "https://tools.ietf.org/html/rfc6455#section-10.2"
54+
var OTHER = "See also https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking\
55+
or https://christian-schneider.net/CrossSiteWebSocketHijacking.html"
56+
var CWEID = 346 // CWE-346: Origin Validation Error, http://cwe.mitre.org/data/definitions/346.html
57+
var WASCID = 9 // WASC-9 Cross Site Request Forgery, http://projects.webappsec.org/w/page/13246919/Cross%20Site%20Request%20Forgery
58+
59+
function scanNode(as, msg) {
60+
var target = msg.getRequestHeader().getURI().toString()
61+
62+
// check if this is a WebSocket HTTP Upgrade request (the message should include also "Connection: Upgrade" header if we wanted to check it strictly)
63+
// TODO: in ZAP 2.11 we might use msg.isWebSocketUpgrade() check instead
64+
var upgradeHeader = msg.getRequestHeader().getHeader("Upgrade")
65+
if (!upgradeHeader || upgradeHeader.toLowerCase() !== "websocket") {
66+
if (LOG_DEBUG_MESSAGES) {
67+
print("Cross-Site WebSocket Hijacking rule skipped for url=" + target + ", it does not appear to be a WebSocket upgrade request")
68+
}
69+
return
70+
}
71+
72+
if (LOG_DEBUG_MESSAGES) {
73+
print("Cross-Site WebSocket Hijacking rule started for url=" + target)
74+
}
75+
msg = msg.cloneRequest()
76+
77+
// set random Sec-WebSocket-Key
78+
var randomBytes = new ByteArray(16)
79+
new Random().nextBytes(randomBytes)
80+
var secWsKey = new String(Base64.getEncoder().encode(randomBytes))
81+
msg.getRequestHeader().setHeader("Sec-WebSocket-Key", secWsKey)
82+
83+
// set Origin header using custom domain, .example is a reserved TLD in RFC 2606 so it should not match domain name of a scanned service
84+
msg.getRequestHeader().setHeader("Origin", "https://cswsh.example")
85+
86+
as.sendAndReceive(msg, true, false)
87+
88+
var responseStatus = msg.getResponseHeader().getStatusCode()
89+
if (responseStatus === 101) {
90+
// should not have accepted connection with different origin
91+
if (LOG_DEBUG_MESSAGES) {
92+
print("Cross-Site WebSocket Hijacking vulnerability found, sending alert for url=" + target)
93+
}
94+
as.newAlert()
95+
.setRisk(RISK)
96+
.setConfidence(CONFIDENCE)
97+
.setName(TITLE)
98+
.setDescription(DESCRIPTION)
99+
.setParam(target)
100+
.setEvidence(msg.getResponseHeader().getPrimeHeader())
101+
.setOtherInfo(OTHER)
102+
.setSolution(SOLUTION)
103+
.setReference(REFERENCE)
104+
.setCweId(CWEID)
105+
.setWascId(WASCID)
106+
.setMessage(msg)
107+
.raise()
108+
}
109+
}

0 commit comments

Comments
 (0)