Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit d1d4c2e

Browse files
author
Porcupiney Hairs
committed
Golang : Add WebSocket Read and Write Functions.
1 parent 806cfc7 commit d1d4c2e

140 files changed

Lines changed: 22350 additions & 126 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ql/src/semmle/go/frameworks/Websocket.qll

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,150 @@ module WebSocketRequestCall {
132132
override DataFlow::Node getRequestUrl() { result = this.getArgument(0) }
133133
}
134134
}
135+
136+
/*
137+
* A message written to a WebSocket, considered as a flow sink for reflected XSS.
138+
*/
139+
140+
class WebsocketReaderAsSource extends UntrustedFlowSource::Range {
141+
WebsocketReaderAsSource() {
142+
exists(WebSocketReader r | this = r.getAnOutput().getNode(r.getACall()))
143+
}
144+
}
145+
146+
/**
147+
* A function or a method which reads a message from a WebSocket connection.
148+
*
149+
* Extend this class to refine existing API models. If you want to model new APIs,
150+
* extend `WebSocketReader::Range` instead.
151+
*/
152+
class WebSocketReader extends Function {
153+
WebSocketReader::Range self;
154+
155+
WebSocketReader() { this = self }
156+
157+
/** Gets an output of this function that is read from a WebSocket connection. */
158+
FunctionOutput getAnOutput() { result = self.getAnOutput() }
159+
}
160+
161+
/** Provides classes for working with messages read from a WebSocket. */
162+
module WebSocketReader {
163+
/**
164+
* A function or a method which reads a message from a WebSocket connection
165+
*
166+
* Extend this class to model new APIs. If you want to refine existing API models,
167+
* extend `WebSocketReader` instead.
168+
*/
169+
abstract class Range extends Function {
170+
/**Returns the parameter in which the function stores the message read. */
171+
abstract FunctionOutput getAnOutput();
172+
}
173+
174+
/**
175+
* Models the `Receive` method of the `golang.org/x/net/websocket` package.
176+
*/
177+
private class GolangXNetCodecRecv extends Range, Method {
178+
GolangXNetCodecRecv() {
179+
// func (cd Codec) Receive(ws *Conn, v interface{}) (err error)
180+
this.hasQualifiedName("golang.org/x/net/websocket", "Codec", "Receive")
181+
}
182+
183+
override FunctionOutput getAnOutput() { result.isParameter(1) }
184+
}
185+
186+
/**
187+
* Models the `Read` method of the `golang.org/x/net/websocket` package.
188+
*/
189+
private class GolangXNetConnRead extends Range, Method {
190+
GolangXNetConnRead() {
191+
// func (ws *Conn) Read(msg []byte) (n int, err error)
192+
this.hasQualifiedName("golang.org/x/net/websocket", "Conn", "Read")
193+
}
194+
195+
override FunctionOutput getAnOutput() { result.isParameter(0) }
196+
}
197+
198+
/**
199+
* Models the `Read` method of the `nhooyr.io/websocket` package.
200+
*/
201+
private class NhooyrWebsocketRead extends Range, Method {
202+
NhooyrWebsocketRead() {
203+
// func (c *Conn) Read(ctx context.Context) (MessageType, []byte, error)
204+
this.hasQualifiedName("nhooyr.io/websocket", "Conn", "Read")
205+
}
206+
207+
override FunctionOutput getAnOutput() { result.isResult(1) }
208+
}
209+
210+
/**
211+
* Models the `Reader` method of the `nhooyr.io/websocket` package.
212+
*/
213+
private class NhooyrWebsocketReader extends Range, Method {
214+
NhooyrWebsocketReader() {
215+
// func (c *Conn) Reader(ctx context.Context) (MessageType, io.Reader, error)
216+
this.hasQualifiedName("nhooyr.io/websocket", "Conn", "Reader")
217+
}
218+
219+
override FunctionOutput getAnOutput() { result.isResult(1) }
220+
}
221+
222+
/**
223+
* Models the `ReadFrame`function of the `github.com/gobwas/ws` package.
224+
*/
225+
private class GobwasWsReadFrame extends Range {
226+
GobwasWsReadFrame() {
227+
// func ReadFrame(r io.Reader) (f Frame, err error)
228+
this.hasQualifiedName("github.com/gobwas/ws", "ReadFrame")
229+
}
230+
231+
override FunctionOutput getAnOutput() { result.isResult(0) }
232+
}
233+
234+
/**
235+
* Models the `ReadHeader`function of the `github.com/gobwas/ws` package.
236+
*/
237+
private class GobwasWsReadHeader extends Range {
238+
GobwasWsReadHeader() {
239+
// func ReadHeader(r io.Reader) (h Header, err error)
240+
this.hasQualifiedName("github.com/gobwas/ws", "ReadHeader")
241+
}
242+
243+
override FunctionOutput getAnOutput() { result.isResult(0) }
244+
}
245+
246+
/**
247+
* Models the `ReadJson` function of the `github.com/gorilla/websocket` package.
248+
*/
249+
private class GorillaWebsocketReadJson extends Range {
250+
GorillaWebsocketReadJson() {
251+
// func ReadJSON(c *Conn, v interface{}) error
252+
this.hasQualifiedName("github.com/gorilla/websocket", "ReadJSON")
253+
}
254+
255+
override FunctionOutput getAnOutput() { result.isParameter(1) }
256+
}
257+
258+
/**
259+
* Models the `ReadJson` method of the `github.com/gorilla/websocket` package.
260+
*/
261+
private class GorillaWebsocketConnReadJson extends Range, Method {
262+
GorillaWebsocketConnReadJson() {
263+
// func (c *Conn) ReadJSON(v interface{}) error
264+
this.hasQualifiedName("github.com/gorilla/websocket", "Conn", "ReadJSON")
265+
}
266+
267+
override FunctionOutput getAnOutput() { result.isParameter(0) }
268+
}
269+
270+
/**
271+
* Models the `ReadMessage` method of the `github.com/gorilla/websocket` package.
272+
*/
273+
private class GorillaWebsocketReadMessage extends Range, Method {
274+
GorillaWebsocketReadMessage() {
275+
// func (c *Conn) ReadMessage() (messageType int, p []byte, err error)
276+
this.hasQualifiedName("github.com/gorilla/websocket", "Conn", "ReadMessage")
277+
}
278+
279+
override FunctionOutput getAnOutput() { result.isResult(1) }
280+
}
281+
}

ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@
77
| DialFunction.go:40:2:40:45 | call to Dial | DialFunction.go:40:31:40:44 | untrustedInput |
88
| DialFunction.go:42:2:42:31 | call to BuildProxy | DialFunction.go:42:17:42:30 | untrustedInput |
99
| DialFunction.go:43:2:43:24 | call to New | DialFunction.go:43:10:43:23 | untrustedInput |
10+
| WebsocketReadWrite.go:30:12:30:42 | call to Dial | WebsocketReadWrite.go:30:27:30:29 | uri |
11+
| WebsocketReadWrite.go:40:14:40:50 | call to Dial | WebsocketReadWrite.go:40:42:40:44 | uri |
12+
| WebsocketReadWrite.go:50:17:50:37 | call to Dial | WebsocketReadWrite.go:50:29:50:31 | uri |
13+
| WebsocketReadWrite.go:66:20:66:51 | call to Dial | WebsocketReadWrite.go:66:48:66:50 | uri |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| WebsocketReadWrite.go:31:7:31:10 | definition of xnet |
2+
| WebsocketReadWrite.go:35:3:35:7 | definition of xnet2 |
3+
| WebsocketReadWrite.go:41:3:41:40 | ... := ...[1] |
4+
| WebsocketReadWrite.go:44:3:44:48 | ... := ...[1] |
5+
| WebsocketReadWrite.go:51:7:51:16 | definition of gorillaMsg |
6+
| WebsocketReadWrite.go:55:3:55:10 | definition of gorilla2 |
7+
| WebsocketReadWrite.go:61:3:61:38 | ... := ...[1] |
8+
| WebsocketReadWrite.go:67:3:67:36 | ... := ...[0] |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import go
2+
import semmle.go.frameworks.Websocket
3+
4+
from WebSocketReader r, DataFlow::Node nd
5+
where nd = r.getAnOutput().getNode(r.getACall())
6+
select nd
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package main
2+
3+
//go:generate depstubber -vendor github.com/gobwas/ws "" ReadFrame,WriteFrame,NewTextFrame,Dial
4+
//go:generate depstubber -vendor github.com/gorilla/websocket Dialer ReadJSON,WriteJSON,NewPreparedMessage
5+
//go:generate depstubber -vendor golang.org/x/net/websocket Codec Dial
6+
//go:generate depstubber -vendor nhooyr.io/websocket "" Dial
7+
8+
import (
9+
"context"
10+
"io"
11+
"net/http"
12+
13+
gobwas "github.com/gobwas/ws"
14+
gorilla "github.com/gorilla/websocket"
15+
websocket "golang.org/x/net/websocket"
16+
nhooyr "nhooyr.io/websocket"
17+
)
18+
19+
func marshal(v interface{}) (data []byte, payloadType byte, err error) {
20+
return nil, 0, nil
21+
}
22+
func unmarshal(data []byte, payloadType byte, v interface{}) (err error) {
23+
return nil
24+
}
25+
26+
func xss(w http.ResponseWriter, r *http.Request) {
27+
uri := r.Header.Get("X-Header")
28+
origin := "test"
29+
{
30+
ws, _ := websocket.Dial(uri, "", origin)
31+
var xnet = make([]byte, 512)
32+
ws.Read(xnet)
33+
ws.Write([]byte(xnet))
34+
codec := &websocket.Codec{marshal, unmarshal}
35+
xnet2 := make([]byte, 512)
36+
codec.Receive(ws, xnet2)
37+
codec.Send(ws, []byte(xnet2))
38+
}
39+
{
40+
n, _, _ := nhooyr.Dial(context.TODO(), uri, nil)
41+
_, nhooyr, _ := n.Read(context.TODO())
42+
n.Write(context.TODO(), 0, nhooyr)
43+
44+
_, nhooyrReader, _ := n.Reader(context.TODO())
45+
writer, _ := n.Writer(context.TODO(), 0)
46+
io.Copy(writer, nhooyrReader)
47+
}
48+
{
49+
dialer := gorilla.Dialer{}
50+
conn, _, _ := dialer.Dial(uri, nil)
51+
var gorillaMsg = make([]byte, 512)
52+
gorilla.ReadJSON(conn, gorillaMsg)
53+
gorilla.WriteJSON(conn, gorillaMsg)
54+
55+
gorilla2 := make([]byte, 512)
56+
conn.ReadJSON(gorilla2)
57+
pm, _ := gorilla.NewPreparedMessage(0, gorilla2)
58+
conn.WritePreparedMessage(pm)
59+
conn.WriteJSON(gorilla2)
60+
61+
_, gorilla3, _ := conn.ReadMessage()
62+
conn.WriteMessage(0, gorilla3)
63+
64+
}
65+
{
66+
conn, _, _, _ := gobwas.Dial(context.TODO(), uri)
67+
frame, _ := gobwas.ReadFrame(conn)
68+
69+
gobwas.WriteFrame(conn, frame)
70+
71+
resp := gobwas.NewTextFrame([]byte(uri))
72+
gobwas.WriteFrame(conn, resp)
73+
}
74+
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
module main
1+
module codeql-go-tests/frameworks/Websocket
22

33
go 1.14
44

55
require (
66
github.com/gobwas/ws v1.0.3
77
github.com/gorilla/websocket v1.4.2
8+
github.com/sacOO7/go-logger v0.0.0-20180719173527-9ac9add5a50d // indirect
89
github.com/sacOO7/gowebsocket v0.0.0-20180719182212-1436bb906a4e
9-
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd
10+
golang.org/x/net v0.0.0-20200505041828-1ed23360d12c
1011
nhooyr.io/websocket v1.8.5
1112
)

ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gobwas/httphead/LICENSE

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gobwas/httphead/README.md

Lines changed: 63 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)