diff --git a/ql/src/semmle/go/frameworks/Websocket.qll b/ql/src/semmle/go/frameworks/Websocket.qll index c16555da3..95fac6468 100644 --- a/ql/src/semmle/go/frameworks/Websocket.qll +++ b/ql/src/semmle/go/frameworks/Websocket.qll @@ -132,3 +132,150 @@ module WebSocketRequestCall { override DataFlow::Node getRequestUrl() { result = this.getArgument(0) } } } + +/* + * A message written to a WebSocket, considered as a flow sink for reflected XSS. + */ + +class WebsocketReaderAsSource extends UntrustedFlowSource::Range { + WebsocketReaderAsSource() { + exists(WebSocketReader r | this = r.getAnOutput().getNode(r.getACall())) + } +} + +/** + * A function or a method which reads a message from a WebSocket connection. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `WebSocketReader::Range` instead. + */ +class WebSocketReader extends Function { + WebSocketReader::Range self; + + WebSocketReader() { this = self } + + /** Gets an output of this function that is read from a WebSocket connection. */ + FunctionOutput getAnOutput() { result = self.getAnOutput() } +} + +/** Provides classes for working with messages read from a WebSocket. */ +module WebSocketReader { + /** + * A function or a method which reads a message from a WebSocket connection + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `WebSocketReader` instead. + */ + abstract class Range extends Function { + /**Returns the parameter in which the function stores the message read. */ + abstract FunctionOutput getAnOutput(); + } + + /** + * Models the `Receive` method of the `golang.org/x/net/websocket` package. + */ + private class GolangXNetCodecRecv extends Range, Method { + GolangXNetCodecRecv() { + // func (cd Codec) Receive(ws *Conn, v interface{}) (err error) + this.hasQualifiedName("golang.org/x/net/websocket", "Codec", "Receive") + } + + override FunctionOutput getAnOutput() { result.isParameter(1) } + } + + /** + * Models the `Read` method of the `golang.org/x/net/websocket` package. + */ + private class GolangXNetConnRead extends Range, Method { + GolangXNetConnRead() { + // func (ws *Conn) Read(msg []byte) (n int, err error) + this.hasQualifiedName("golang.org/x/net/websocket", "Conn", "Read") + } + + override FunctionOutput getAnOutput() { result.isParameter(0) } + } + + /** + * Models the `Read` method of the `nhooyr.io/websocket` package. + */ + private class NhooyrWebsocketRead extends Range, Method { + NhooyrWebsocketRead() { + // func (c *Conn) Read(ctx context.Context) (MessageType, []byte, error) + this.hasQualifiedName("nhooyr.io/websocket", "Conn", "Read") + } + + override FunctionOutput getAnOutput() { result.isResult(1) } + } + + /** + * Models the `Reader` method of the `nhooyr.io/websocket` package. + */ + private class NhooyrWebsocketReader extends Range, Method { + NhooyrWebsocketReader() { + // func (c *Conn) Reader(ctx context.Context) (MessageType, io.Reader, error) + this.hasQualifiedName("nhooyr.io/websocket", "Conn", "Reader") + } + + override FunctionOutput getAnOutput() { result.isResult(1) } + } + + /** + * Models the `ReadFrame`function of the `github.com/gobwas/ws` package. + */ + private class GobwasWsReadFrame extends Range { + GobwasWsReadFrame() { + // func ReadFrame(r io.Reader) (f Frame, err error) + this.hasQualifiedName("github.com/gobwas/ws", "ReadFrame") + } + + override FunctionOutput getAnOutput() { result.isResult(0) } + } + + /** + * Models the `ReadHeader`function of the `github.com/gobwas/ws` package. + */ + private class GobwasWsReadHeader extends Range { + GobwasWsReadHeader() { + // func ReadHeader(r io.Reader) (h Header, err error) + this.hasQualifiedName("github.com/gobwas/ws", "ReadHeader") + } + + override FunctionOutput getAnOutput() { result.isResult(0) } + } + + /** + * Models the `ReadJson` function of the `github.com/gorilla/websocket` package. + */ + private class GorillaWebsocketReadJson extends Range { + GorillaWebsocketReadJson() { + // func ReadJSON(c *Conn, v interface{}) error + this.hasQualifiedName("github.com/gorilla/websocket", "ReadJSON") + } + + override FunctionOutput getAnOutput() { result.isParameter(1) } + } + + /** + * Models the `ReadJson` method of the `github.com/gorilla/websocket` package. + */ + private class GorillaWebsocketConnReadJson extends Range, Method { + GorillaWebsocketConnReadJson() { + // func (c *Conn) ReadJSON(v interface{}) error + this.hasQualifiedName("github.com/gorilla/websocket", "Conn", "ReadJSON") + } + + override FunctionOutput getAnOutput() { result.isParameter(0) } + } + + /** + * Models the `ReadMessage` method of the `github.com/gorilla/websocket` package. + */ + private class GorillaWebsocketReadMessage extends Range, Method { + GorillaWebsocketReadMessage() { + // func (c *Conn) ReadMessage() (messageType int, p []byte, err error) + this.hasQualifiedName("github.com/gorilla/websocket", "Conn", "ReadMessage") + } + + override FunctionOutput getAnOutput() { result.isResult(1) } + } +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.expected b/ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.expected index c68fd7f83..a0b614961 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.expected +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.expected @@ -1,9 +1,13 @@ -| DialFunction.go:25:2:25:43 | call to Dial | DialFunction.go:25:17:25:30 | untrustedInput | -| DialFunction.go:28:2:28:29 | call to DialConfig | DialFunction.go:27:35:27:48 | untrustedInput | -| DialFunction.go:30:2:30:49 | call to Dial | DialFunction.go:30:30:30:43 | untrustedInput | -| DialFunction.go:33:2:33:33 | call to Dial | DialFunction.go:33:14:33:27 | untrustedInput | -| DialFunction.go:35:2:35:56 | call to DialContext | DialFunction.go:35:37:35:50 | untrustedInput | -| DialFunction.go:37:2:37:44 | call to Dial | DialFunction.go:37:30:37:43 | untrustedInput | -| DialFunction.go:40:2:40:45 | call to Dial | DialFunction.go:40:31:40:44 | untrustedInput | -| DialFunction.go:42:2:42:31 | call to BuildProxy | DialFunction.go:42:17:42:30 | untrustedInput | -| DialFunction.go:43:2:43:24 | call to New | DialFunction.go:43:10:43:23 | untrustedInput | +| DialFunction.go:21:2:21:43 | call to Dial | DialFunction.go:21:17:21:30 | untrustedInput | +| DialFunction.go:24:2:24:29 | call to DialConfig | DialFunction.go:23:35:23:48 | untrustedInput | +| DialFunction.go:26:2:26:49 | call to Dial | DialFunction.go:26:30:26:43 | untrustedInput | +| DialFunction.go:29:2:29:33 | call to Dial | DialFunction.go:29:14:29:27 | untrustedInput | +| DialFunction.go:31:2:31:56 | call to DialContext | DialFunction.go:31:37:31:50 | untrustedInput | +| DialFunction.go:33:2:33:44 | call to Dial | DialFunction.go:33:30:33:43 | untrustedInput | +| DialFunction.go:36:2:36:45 | call to Dial | DialFunction.go:36:31:36:44 | untrustedInput | +| DialFunction.go:38:2:38:31 | call to BuildProxy | DialFunction.go:38:17:38:30 | untrustedInput | +| DialFunction.go:39:2:39:24 | call to New | DialFunction.go:39:10:39:23 | untrustedInput | +| WebsocketReadWrite.go:30:12:30:42 | call to Dial | WebsocketReadWrite.go:30:27:30:29 | uri | +| WebsocketReadWrite.go:40:14:40:50 | call to Dial | WebsocketReadWrite.go:40:42:40:44 | uri | +| WebsocketReadWrite.go:50:17:50:37 | call to Dial | WebsocketReadWrite.go:50:29:50:31 | uri | +| WebsocketReadWrite.go:66:20:66:51 | call to Dial | WebsocketReadWrite.go:66:48:66:50 | uri | diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.go b/ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.go index a1153b8d8..6943404ec 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.go +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/DialFunction.go @@ -1,10 +1,6 @@ package main -//go:generate depstubber -vendor github.com/gobwas/ws Dialer Dial -//go:generate depstubber -vendor github.com/gorilla/websocket Dialer //go:generate depstubber -vendor github.com/sacOO7/gowebsocket "" New,BuildProxy -//go:generate depstubber -vendor golang.org/x/net/websocket "" Dial,NewConfig,DialConfig -//go:generate depstubber -vendor nhooyr.io/websocket "" Dial import ( "context" diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/Read.expected b/ql/test/library-tests/semmle/go/frameworks/Websocket/Read.expected new file mode 100644 index 000000000..1907b486d --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/Read.expected @@ -0,0 +1,8 @@ +| WebsocketReadWrite.go:31:7:31:10 | definition of xnet | +| WebsocketReadWrite.go:35:3:35:7 | definition of xnet2 | +| WebsocketReadWrite.go:41:3:41:40 | ... := ...[1] | +| WebsocketReadWrite.go:44:3:44:48 | ... := ...[1] | +| WebsocketReadWrite.go:51:7:51:16 | definition of gorillaMsg | +| WebsocketReadWrite.go:55:3:55:10 | definition of gorilla2 | +| WebsocketReadWrite.go:61:3:61:38 | ... := ...[1] | +| WebsocketReadWrite.go:67:3:67:36 | ... := ...[0] | diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/Read.ql b/ql/test/library-tests/semmle/go/frameworks/Websocket/Read.ql new file mode 100644 index 000000000..df2bef5e0 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/Read.ql @@ -0,0 +1,6 @@ +import go +import semmle.go.frameworks.Websocket + +from WebSocketReader r, DataFlow::Node nd +where nd = r.getAnOutput().getNode(r.getACall()) +select nd diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/WebsocketReadWrite.go b/ql/test/library-tests/semmle/go/frameworks/Websocket/WebsocketReadWrite.go new file mode 100644 index 000000000..6cb2692a6 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/WebsocketReadWrite.go @@ -0,0 +1,74 @@ +package main + +//go:generate depstubber -vendor github.com/gobwas/ws Dialer ReadFrame,WriteFrame,NewTextFrame,Dial +//go:generate depstubber -vendor github.com/gorilla/websocket Dialer ReadJSON,WriteJSON,NewPreparedMessage +//go:generate depstubber -vendor golang.org/x/net/websocket Codec Dial,NewConfig,DialConfig +//go:generate depstubber -vendor nhooyr.io/websocket "" Dial + +import ( + "context" + "io" + "net/http" + + gobwas "github.com/gobwas/ws" + gorilla "github.com/gorilla/websocket" + websocket "golang.org/x/net/websocket" + nhooyr "nhooyr.io/websocket" +) + +func marshal(v interface{}) (data []byte, payloadType byte, err error) { + return nil, 0, nil +} +func unmarshal(data []byte, payloadType byte, v interface{}) (err error) { + return nil +} + +func xss(w http.ResponseWriter, r *http.Request) { + uri := r.Header.Get("X-Header") + origin := "test" + { + ws, _ := websocket.Dial(uri, "", origin) + var xnet = make([]byte, 512) + ws.Read(xnet) + ws.Write([]byte(xnet)) + codec := &websocket.Codec{marshal, unmarshal} + xnet2 := make([]byte, 512) + codec.Receive(ws, xnet2) + codec.Send(ws, []byte(xnet2)) + } + { + n, _, _ := nhooyr.Dial(context.TODO(), uri, nil) + _, nhooyr, _ := n.Read(context.TODO()) + n.Write(context.TODO(), 0, nhooyr) + + _, nhooyrReader, _ := n.Reader(context.TODO()) + writer, _ := n.Writer(context.TODO(), 0) + io.Copy(writer, nhooyrReader) + } + { + dialer := gorilla.Dialer{} + conn, _, _ := dialer.Dial(uri, nil) + var gorillaMsg = make([]byte, 512) + gorilla.ReadJSON(conn, gorillaMsg) + gorilla.WriteJSON(conn, gorillaMsg) + + gorilla2 := make([]byte, 512) + conn.ReadJSON(gorilla2) + pm, _ := gorilla.NewPreparedMessage(0, gorilla2) + conn.WritePreparedMessage(pm) + conn.WriteJSON(gorilla2) + + _, gorilla3, _ := conn.ReadMessage() + conn.WriteMessage(0, gorilla3) + + } + { + conn, _, _, _ := gobwas.Dial(context.TODO(), uri) + frame, _ := gobwas.ReadFrame(conn) + + gobwas.WriteFrame(conn, frame) + + resp := gobwas.NewTextFrame([]byte(uri)) + gobwas.WriteFrame(conn, resp) + } +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/go.mod b/ql/test/library-tests/semmle/go/frameworks/Websocket/go.mod index ce6c493a1..2d613048e 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Websocket/go.mod +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/go.mod @@ -1,4 +1,4 @@ -module main +module codeql-go-tests/frameworks/Websocket go 1.14 @@ -6,6 +6,6 @@ require ( github.com/gobwas/ws v1.0.3 github.com/gorilla/websocket v1.4.2 github.com/sacOO7/gowebsocket v0.0.0-20180719182212-1436bb906a4e - golang.org/x/net v0.0.0-20200421231249-e086a090c8fd + golang.org/x/net v0.0.0-20200505041828-1ed23360d12c nhooyr.io/websocket v1.8.5 ) diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gobwas/ws/stub.go b/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gobwas/ws/stub.go index 0d00bc949..f4919cdd6 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gobwas/ws/stub.go +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gobwas/ws/stub.go @@ -2,7 +2,7 @@ // This is a simple stub for github.com/gobwas/ws, strictly for use in testing. // See the LICENSE file for information about the licensing of the original library. -// Source: github.com/gobwas/ws (exports: Dialer; functions: Dial) +// Source: github.com/gobwas/ws (exports: Dialer; functions: ReadFrame,WriteFrame,NewTextFrame,Dial) // Package ws is a stub of github.com/gobwas/ws, generated by depstubber. package ws @@ -44,6 +44,11 @@ func (_ Dialer) Upgrade(_ io.ReadWriter, _ *url.URL) (*bufio.Reader, Handshake, return nil, Handshake{}, nil } +type Frame struct { + Header Header + Payload []byte +} + type Handshake struct { Protocol string Extensions []interface{} @@ -52,3 +57,50 @@ type Handshake struct { type HandshakeHeader interface { WriteTo(_ io.Writer) (int64, error) } + +type Header struct { + Fin bool + Rsv byte + OpCode OpCode + Masked bool + Mask [4]byte + Length int64 +} + +func (_ Header) Rsv1() bool { + return false +} + +func (_ Header) Rsv2() bool { + return false +} + +func (_ Header) Rsv3() bool { + return false +} + +func NewTextFrame(_ []byte) Frame { + return Frame{} +} + +type OpCode uint8 + +func (_ OpCode) IsControl() bool { + return false +} + +func (_ OpCode) IsData() bool { + return false +} + +func (_ OpCode) IsReserved() bool { + return false +} + +func ReadFrame(_ io.Reader) (Frame, error) { + return Frame{}, nil +} + +func WriteFrame(_ io.Writer, _ Frame) error { + return nil +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gorilla/websocket/stub.go b/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gorilla/websocket/stub.go index 0be1589cc..c9beb6376 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gorilla/websocket/stub.go +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/github.com/gorilla/websocket/stub.go @@ -2,7 +2,7 @@ // This is a simple stub for github.com/gorilla/websocket, strictly for use in testing. // See the LICENSE file for information about the licensing of the original library. -// Source: github.com/gorilla/websocket (exports: Dialer; functions: ) +// Source: github.com/gorilla/websocket (exports: Dialer; functions: ReadJSON,WriteJSON,NewPreparedMessage) // Package websocket is a stub of github.com/gorilla/websocket, generated by depstubber. package websocket @@ -132,4 +132,16 @@ func (_ *Dialer) DialContext(_ context.Context, _ string, _ http.Header) (*Conn, return nil, nil, nil } +func NewPreparedMessage(_ int, _ []byte) (*PreparedMessage, error) { + return nil, nil +} + type PreparedMessage struct{} + +func ReadJSON(_ *Conn, _ interface{}) error { + return nil +} + +func WriteJSON(_ *Conn, _ interface{}) error { + return nil +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/golang.org/x/net/websocket/stub.go b/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/golang.org/x/net/websocket/stub.go index b860854e6..1bd9aef8d 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/golang.org/x/net/websocket/stub.go +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/golang.org/x/net/websocket/stub.go @@ -2,7 +2,7 @@ // This is a simple stub for golang.org/x/net/websocket, strictly for use in testing. // See the LICENSE file for information about the licensing of the original library. -// Source: golang.org/x/net/websocket (exports: ; functions: Dial,NewConfig,DialConfig) +// Source: golang.org/x/net/websocket (exports: Codec; functions: Dial,NewConfig,DialConfig) // Package websocket is a stub of golang.org/x/net/websocket, generated by depstubber. package websocket @@ -16,6 +16,19 @@ import ( time "time" ) +type Codec struct { + Marshal func(interface{}) ([]byte, byte, error) + Unmarshal func([]byte, byte, interface{}) error +} + +func (_ Codec) Receive(_ *Conn, _ interface{}) error { + return nil +} + +func (_ Codec) Send(_ *Conn, _ interface{}) error { + return nil +} + type Config struct { Location *url.URL Origin *url.URL diff --git a/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/modules.txt b/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/modules.txt index 319b30b77..43950046c 100644 --- a/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/modules.txt +++ b/ql/test/library-tests/semmle/go/frameworks/Websocket/vendor/modules.txt @@ -7,7 +7,7 @@ github.com/gorilla/websocket # github.com/sacOO7/gowebsocket v0.0.0-20180719182212-1436bb906a4e ## explicit github.com/sacOO7/gowebsocket -# golang.org/x/net v0.0.0-20200421231249-e086a090c8fd +# golang.org/x/net v0.0.0-20200505041828-1ed23360d12c ## explicit golang.org/x/net # nhooyr.io/websocket v1.8.5 diff --git a/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected index 24a074cd2..c7aab9062 100644 --- a/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected +++ b/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected @@ -4,6 +4,12 @@ edges | contenttype.go:49:11:49:16 | selection of Form : Values | contenttype.go:53:34:53:37 | data | | tst.go:14:15:14:20 | selection of Form : Values | tst.go:18:12:18:39 | type conversion | | tst.go:48:14:48:19 | selection of Form : Values | tst.go:53:12:53:26 | type conversion | +| websocketXss.go:30:7:30:10 | definition of xnet : slice type | websocketXss.go:32:24:32:27 | xnet | +| websocketXss.go:34:3:34:7 | definition of xnet2 : slice type | websocketXss.go:36:24:36:28 | xnet2 | +| websocketXss.go:40:3:40:40 | ... := ...[1] : slice type | websocketXss.go:41:24:41:29 | nhooyr | +| websocketXss.go:46:7:46:16 | definition of gorillaMsg : slice type | websocketXss.go:48:24:48:33 | gorillaMsg | +| websocketXss.go:50:3:50:10 | definition of gorilla2 : slice type | websocketXss.go:52:24:52:31 | gorilla2 | +| websocketXss.go:54:3:54:38 | ... := ...[1] : slice type | websocketXss.go:55:24:55:31 | gorilla3 | nodes | ReflectedXss.go:11:15:11:20 | selection of Form : Values | semmle.label | selection of Form : Values | | ReflectedXss.go:14:44:14:51 | username | semmle.label | username | @@ -15,9 +21,27 @@ nodes | tst.go:18:12:18:39 | type conversion | semmle.label | type conversion | | tst.go:48:14:48:19 | selection of Form : Values | semmle.label | selection of Form : Values | | tst.go:53:12:53:26 | type conversion | semmle.label | type conversion | +| websocketXss.go:30:7:30:10 | definition of xnet : slice type | semmle.label | definition of xnet : slice type | +| websocketXss.go:32:24:32:27 | xnet | semmle.label | xnet | +| websocketXss.go:34:3:34:7 | definition of xnet2 : slice type | semmle.label | definition of xnet2 : slice type | +| websocketXss.go:36:24:36:28 | xnet2 | semmle.label | xnet2 | +| websocketXss.go:40:3:40:40 | ... := ...[1] : slice type | semmle.label | ... := ...[1] : slice type | +| websocketXss.go:41:24:41:29 | nhooyr | semmle.label | nhooyr | +| websocketXss.go:46:7:46:16 | definition of gorillaMsg : slice type | semmle.label | definition of gorillaMsg : slice type | +| websocketXss.go:48:24:48:33 | gorillaMsg | semmle.label | gorillaMsg | +| websocketXss.go:50:3:50:10 | definition of gorilla2 : slice type | semmle.label | definition of gorilla2 : slice type | +| websocketXss.go:52:24:52:31 | gorilla2 | semmle.label | gorilla2 | +| websocketXss.go:54:3:54:38 | ... := ...[1] : slice type | semmle.label | ... := ...[1] : slice type | +| websocketXss.go:55:24:55:31 | gorilla3 | semmle.label | gorilla3 | #select | ReflectedXss.go:14:44:14:51 | username | ReflectedXss.go:11:15:11:20 | selection of Form : Values | ReflectedXss.go:14:44:14:51 | username | Cross-site scripting vulnerability due to $@. | ReflectedXss.go:11:15:11:20 | selection of Form | user-provided value | | contenttype.go:17:11:17:22 | type conversion | contenttype.go:11:11:11:16 | selection of Form : Values | contenttype.go:17:11:17:22 | type conversion | Cross-site scripting vulnerability due to $@. | contenttype.go:11:11:11:16 | selection of Form | user-provided value | | contenttype.go:53:34:53:37 | data | contenttype.go:49:11:49:16 | selection of Form : Values | contenttype.go:53:34:53:37 | data | Cross-site scripting vulnerability due to $@. | contenttype.go:49:11:49:16 | selection of Form | user-provided value | | tst.go:18:12:18:39 | type conversion | tst.go:14:15:14:20 | selection of Form : Values | tst.go:18:12:18:39 | type conversion | Cross-site scripting vulnerability due to $@. | tst.go:14:15:14:20 | selection of Form | user-provided value | | tst.go:53:12:53:26 | type conversion | tst.go:48:14:48:19 | selection of Form : Values | tst.go:53:12:53:26 | type conversion | Cross-site scripting vulnerability due to $@. | tst.go:48:14:48:19 | selection of Form | user-provided value | +| websocketXss.go:32:24:32:27 | xnet | websocketXss.go:30:7:30:10 | definition of xnet : slice type | websocketXss.go:32:24:32:27 | xnet | Cross-site scripting vulnerability due to $@. | websocketXss.go:30:7:30:10 | definition of xnet | user-provided value | +| websocketXss.go:36:24:36:28 | xnet2 | websocketXss.go:34:3:34:7 | definition of xnet2 : slice type | websocketXss.go:36:24:36:28 | xnet2 | Cross-site scripting vulnerability due to $@. | websocketXss.go:34:3:34:7 | definition of xnet2 | user-provided value | +| websocketXss.go:41:24:41:29 | nhooyr | websocketXss.go:40:3:40:40 | ... := ...[1] : slice type | websocketXss.go:41:24:41:29 | nhooyr | Cross-site scripting vulnerability due to $@. | websocketXss.go:40:3:40:40 | ... := ...[1] | user-provided value | +| websocketXss.go:48:24:48:33 | gorillaMsg | websocketXss.go:46:7:46:16 | definition of gorillaMsg : slice type | websocketXss.go:48:24:48:33 | gorillaMsg | Cross-site scripting vulnerability due to $@. | websocketXss.go:46:7:46:16 | definition of gorillaMsg | user-provided value | +| websocketXss.go:52:24:52:31 | gorilla2 | websocketXss.go:50:3:50:10 | definition of gorilla2 : slice type | websocketXss.go:52:24:52:31 | gorilla2 | Cross-site scripting vulnerability due to $@. | websocketXss.go:50:3:50:10 | definition of gorilla2 | user-provided value | +| websocketXss.go:55:24:55:31 | gorilla3 | websocketXss.go:54:3:54:38 | ... := ...[1] : slice type | websocketXss.go:55:24:55:31 | gorilla3 | Cross-site scripting vulnerability due to $@. | websocketXss.go:54:3:54:38 | ... := ...[1] | user-provided value | diff --git a/ql/test/query-tests/Security/CWE-079/go.mod b/ql/test/query-tests/Security/CWE-079/go.mod new file mode 100644 index 000000000..67a026622 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/go.mod @@ -0,0 +1,10 @@ +module codeql-go-tests/CWE-079 + +go 1.14 + +require ( + github.com/gobwas/ws v1.0.3 + github.com/gorilla/websocket v1.4.2 + golang.org/x/net v0.0.0-20200505041828-1ed23360d12c + nhooyr.io/websocket v1.8.5 +) diff --git a/ql/test/query-tests/Security/CWE-079/vendor/github.com/gobwas/ws/LICENSE b/ql/test/query-tests/Security/CWE-079/vendor/github.com/gobwas/ws/LICENSE new file mode 100644 index 000000000..d2611fddf --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/github.com/gobwas/ws/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017-2018 Sergey Kamardin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ql/test/query-tests/Security/CWE-079/vendor/github.com/gobwas/ws/stub.go b/ql/test/query-tests/Security/CWE-079/vendor/github.com/gobwas/ws/stub.go new file mode 100644 index 000000000..3cd71fffe --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/github.com/gobwas/ws/stub.go @@ -0,0 +1,76 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/gobwas/ws, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/gobwas/ws (exports: ; functions: ReadFrame,WriteFrame,NewTextFrame,Dial) + +// Package ws is a stub of github.com/gobwas/ws, generated by depstubber. +package ws + +import ( + bufio "bufio" + context "context" + io "io" + net "net" +) + +func Dial(_ context.Context, _ string) (net.Conn, *bufio.Reader, Handshake, error) { + return nil, nil, Handshake{}, nil +} + +type Frame struct { + Header Header + Payload []byte +} + +type Handshake struct { + Protocol string + Extensions []interface{} +} + +type Header struct { + Fin bool + Rsv byte + OpCode OpCode + Masked bool + Mask [4]byte + Length int64 +} + +func (_ Header) Rsv1() bool { + return false +} + +func (_ Header) Rsv2() bool { + return false +} + +func (_ Header) Rsv3() bool { + return false +} + +func NewTextFrame(_ []byte) Frame { + return Frame{} +} + +type OpCode uint8 + +func (_ OpCode) IsControl() bool { + return false +} + +func (_ OpCode) IsData() bool { + return false +} + +func (_ OpCode) IsReserved() bool { + return false +} + +func ReadFrame(_ io.Reader) (Frame, error) { + return Frame{}, nil +} + +func WriteFrame(_ io.Writer, _ Frame) error { + return nil +} diff --git a/ql/test/query-tests/Security/CWE-079/vendor/github.com/gorilla/websocket/LICENSE b/ql/test/query-tests/Security/CWE-079/vendor/github.com/gorilla/websocket/LICENSE new file mode 100644 index 000000000..9171c9722 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/github.com/gorilla/websocket/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ql/test/query-tests/Security/CWE-079/vendor/github.com/gorilla/websocket/stub.go b/ql/test/query-tests/Security/CWE-079/vendor/github.com/gorilla/websocket/stub.go new file mode 100644 index 000000000..c9beb6376 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/github.com/gorilla/websocket/stub.go @@ -0,0 +1,147 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/gorilla/websocket, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/gorilla/websocket (exports: Dialer; functions: ReadJSON,WriteJSON,NewPreparedMessage) + +// Package websocket is a stub of github.com/gorilla/websocket, generated by depstubber. +package websocket + +import ( + context "context" + tls "crypto/tls" + io "io" + net "net" + http "net/http" + url "net/url" + time "time" +) + +type BufferPool interface { + Get() interface{} + Put(_ interface{}) +} + +type Conn struct{} + +func (_ *Conn) Close() error { + return nil +} + +func (_ *Conn) CloseHandler() func(int, string) error { + return nil +} + +func (_ *Conn) EnableWriteCompression(_ bool) {} + +func (_ *Conn) LocalAddr() net.Addr { + return nil +} + +func (_ *Conn) NextReader() (int, io.Reader, error) { + return 0, nil, nil +} + +func (_ *Conn) NextWriter(_ int) (io.WriteCloser, error) { + return nil, nil +} + +func (_ *Conn) PingHandler() func(string) error { + return nil +} + +func (_ *Conn) PongHandler() func(string) error { + return nil +} + +func (_ *Conn) ReadJSON(_ interface{}) error { + return nil +} + +func (_ *Conn) ReadMessage() (int, []byte, error) { + return 0, nil, nil +} + +func (_ *Conn) RemoteAddr() net.Addr { + return nil +} + +func (_ *Conn) SetCloseHandler(_ func(int, string) error) {} + +func (_ *Conn) SetCompressionLevel(_ int) error { + return nil +} + +func (_ *Conn) SetPingHandler(_ func(string) error) {} + +func (_ *Conn) SetPongHandler(_ func(string) error) {} + +func (_ *Conn) SetReadDeadline(_ time.Time) error { + return nil +} + +func (_ *Conn) SetReadLimit(_ int64) {} + +func (_ *Conn) SetWriteDeadline(_ time.Time) error { + return nil +} + +func (_ *Conn) Subprotocol() string { + return "" +} + +func (_ *Conn) UnderlyingConn() net.Conn { + return nil +} + +func (_ *Conn) WriteControl(_ int, _ []byte, _ time.Time) error { + return nil +} + +func (_ *Conn) WriteJSON(_ interface{}) error { + return nil +} + +func (_ *Conn) WriteMessage(_ int, _ []byte) error { + return nil +} + +func (_ *Conn) WritePreparedMessage(_ *PreparedMessage) error { + return nil +} + +type Dialer struct { + NetDial func(string, string) (net.Conn, error) + NetDialContext func(context.Context, string, string) (net.Conn, error) + Proxy func(*http.Request) (*url.URL, error) + TLSClientConfig *tls.Config + HandshakeTimeout time.Duration + ReadBufferSize int + WriteBufferSize int + WriteBufferPool BufferPool + Subprotocols []string + EnableCompression bool + Jar http.CookieJar +} + +func (_ *Dialer) Dial(_ string, _ http.Header) (*Conn, *http.Response, error) { + return nil, nil, nil +} + +func (_ *Dialer) DialContext(_ context.Context, _ string, _ http.Header) (*Conn, *http.Response, error) { + return nil, nil, nil +} + +func NewPreparedMessage(_ int, _ []byte) (*PreparedMessage, error) { + return nil, nil +} + +type PreparedMessage struct{} + +func ReadJSON(_ *Conn, _ interface{}) error { + return nil +} + +func WriteJSON(_ *Conn, _ interface{}) error { + return nil +} diff --git a/ql/test/query-tests/Security/CWE-079/vendor/golang.org/x/net/websocket/LICENSE b/ql/test/query-tests/Security/CWE-079/vendor/golang.org/x/net/websocket/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/golang.org/x/net/websocket/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ql/test/query-tests/Security/CWE-079/vendor/golang.org/x/net/websocket/stub.go b/ql/test/query-tests/Security/CWE-079/vendor/golang.org/x/net/websocket/stub.go new file mode 100644 index 000000000..480729efd --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/golang.org/x/net/websocket/stub.go @@ -0,0 +1,125 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for golang.org/x/net/websocket, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: golang.org/x/net/websocket (exports: Codec; functions: Dial) + +// Package websocket is a stub of golang.org/x/net/websocket, generated by depstubber. +package websocket + +import ( + tls "crypto/tls" + io "io" + net "net" + http "net/http" + url "net/url" + time "time" +) + +type Codec struct { + Marshal func(interface{}) ([]byte, byte, error) + Unmarshal func([]byte, byte, interface{}) error +} + +func (_ Codec) Receive(_ *Conn, _ interface{}) error { + return nil +} + +func (_ Codec) Send(_ *Conn, _ interface{}) error { + return nil +} + +type Config struct { + Location *url.URL + Origin *url.URL + Protocol []string + Version int + TlsConfig *tls.Config + Header http.Header + Dialer *net.Dialer +} + +type Conn struct { + PayloadType byte + MaxPayloadBytes int +} + +func (_ Conn) HandleFrame(_ interface{}) (interface{}, error) { + return nil, nil +} + +func (_ Conn) HeaderReader() io.Reader { + return nil +} + +func (_ Conn) Len() int { + return 0 +} + +func (_ Conn) NewFrameReader() (interface{}, error) { + return nil, nil +} + +func (_ Conn) NewFrameWriter(_ byte) (interface{}, error) { + return nil, nil +} + +func (_ Conn) TrailerReader() io.Reader { + return nil +} + +func (_ Conn) WriteClose(_ int) error { + return nil +} + +func (_ *Conn) Close() error { + return nil +} + +func (_ *Conn) Config() *Config { + return nil +} + +func (_ *Conn) IsClientConn() bool { + return false +} + +func (_ *Conn) IsServerConn() bool { + return false +} + +func (_ *Conn) LocalAddr() net.Addr { + return nil +} + +func (_ *Conn) Read(_ []byte) (int, error) { + return 0, nil +} + +func (_ *Conn) RemoteAddr() net.Addr { + return nil +} + +func (_ *Conn) Request() *http.Request { + return nil +} + +func (_ *Conn) SetDeadline(_ time.Time) error { + return nil +} + +func (_ *Conn) SetReadDeadline(_ time.Time) error { + return nil +} + +func (_ *Conn) SetWriteDeadline(_ time.Time) error { + return nil +} + +func (_ *Conn) Write(_ []byte) (int, error) { + return 0, nil +} + +func Dial(_ string, _ string, _ string) (*Conn, error) { + return nil, nil +} diff --git a/ql/test/query-tests/Security/CWE-079/vendor/modules.txt b/ql/test/query-tests/Security/CWE-079/vendor/modules.txt new file mode 100644 index 000000000..5e59711dd --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/modules.txt @@ -0,0 +1,12 @@ +# github.com/gobwas/ws v1.0.3 +## explicit +github.com/gobwas/ws +# github.com/gorilla/websocket v1.4.2 +## explicit +github.com/gorilla/websocket +# golang.org/x/net v0.0.0-20200505041828-1ed23360d12c +## explicit +golang.org/x/net +# nhooyr.io/websocket v1.8.5 +## explicit +nhooyr.io/websocket diff --git a/ql/test/query-tests/Security/CWE-079/vendor/nhooyr.io/websocket/LICENSE b/ql/test/query-tests/Security/CWE-079/vendor/nhooyr.io/websocket/LICENSE new file mode 100644 index 000000000..b5b5fef31 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/nhooyr.io/websocket/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Anmol Sethi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ql/test/query-tests/Security/CWE-079/vendor/nhooyr.io/websocket/stub.go b/ql/test/query-tests/Security/CWE-079/vendor/nhooyr.io/websocket/stub.go new file mode 100644 index 000000000..7bf2a208d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/vendor/nhooyr.io/websocket/stub.go @@ -0,0 +1,76 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for nhooyr.io/websocket, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: nhooyr.io/websocket (exports: ; functions: Dial) + +// Package websocket is a stub of nhooyr.io/websocket, generated by depstubber. +package websocket + +import ( + context "context" + io "io" + http "net/http" +) + +type CompressionMode int + +type Conn struct{} + +func (_ *Conn) Close(_ StatusCode, _ string) error { + return nil +} + +func (_ *Conn) CloseRead(_ context.Context) context.Context { + return nil +} + +func (_ *Conn) Ping(_ context.Context) error { + return nil +} + +func (_ *Conn) Read(_ context.Context) (MessageType, []byte, error) { + return 0, nil, nil +} + +func (_ *Conn) Reader(_ context.Context) (MessageType, io.Reader, error) { + return 0, nil, nil +} + +func (_ *Conn) SetReadLimit(_ int64) {} + +func (_ *Conn) Subprotocol() string { + return "" +} + +func (_ *Conn) Write(_ context.Context, _ MessageType, _ []byte) error { + return nil +} + +func (_ *Conn) Writer(_ context.Context, _ MessageType) (io.WriteCloser, error) { + return nil, nil +} + +func Dial(_ context.Context, _ string, _ *DialOptions) (*Conn, *http.Response, error) { + return nil, nil, nil +} + +type DialOptions struct { + HTTPClient *http.Client + HTTPHeader http.Header + Subprotocols []string + CompressionMode CompressionMode + CompressionThreshold int +} + +type MessageType int + +func (_ MessageType) String() string { + return "" +} + +type StatusCode int + +func (_ StatusCode) String() string { + return "" +} diff --git a/ql/test/query-tests/Security/CWE-079/websocketXss.go b/ql/test/query-tests/Security/CWE-079/websocketXss.go new file mode 100644 index 000000000..06f15e52c --- /dev/null +++ b/ql/test/query-tests/Security/CWE-079/websocketXss.go @@ -0,0 +1,58 @@ +package main + +//go:generate depstubber -vendor github.com/gobwas/ws "" ReadFrame,WriteFrame,NewTextFrame,Dial +//go:generate depstubber -vendor github.com/gorilla/websocket Dialer ReadJSON,WriteJSON,NewPreparedMessage +//go:generate depstubber -vendor golang.org/x/net/websocket Codec Dial +//go:generate depstubber -vendor nhooyr.io/websocket "" Dial + +import ( + "context" + "fmt" + "net/http" + + gorilla "github.com/gorilla/websocket" + websocket "golang.org/x/net/websocket" + nhooyr "nhooyr.io/websocket" +) + +func marshal(v interface{}) (data []byte, payloadType byte, err error) { + return nil, 0, nil +} +func unmarshal(data []byte, payloadType byte, v interface{}) (err error) { + return nil +} + +func xss(w http.ResponseWriter, r *http.Request) { + uri := r.Header.Get("X-Header") + origin := "test" + { + ws, _ := websocket.Dial(uri, "", origin) + var xnet = make([]byte, 512) + ws.Read(xnet) + fmt.Fprintf(w, "%v", xnet) + codec := &websocket.Codec{marshal, unmarshal} + xnet2 := make([]byte, 512) + codec.Receive(ws, xnet2) + fmt.Fprintf(w, "%v", xnet2) + } + { + n, _, _ := nhooyr.Dial(context.TODO(), uri, nil) + _, nhooyr, _ := n.Read(context.TODO()) + fmt.Fprintf(w, "%v", nhooyr) + } + { + dialer := gorilla.Dialer{} + conn, _, _ := dialer.Dial(uri, nil) + var gorillaMsg = make([]byte, 512) + gorilla.ReadJSON(conn, gorillaMsg) + fmt.Fprintf(w, "%v", gorillaMsg) + + gorilla2 := make([]byte, 512) + conn.ReadJSON(gorilla2) + fmt.Fprintf(w, "%v", gorilla2) + + _, gorilla3, _ := conn.ReadMessage() + fmt.Fprintf(w, "%v", gorilla3) + + } +}