Merge remote-tracking branch 'origin/topic/awelzel/3424-http-upgrade-websocket-v1'

* origin/topic/awelzel/3424-http-upgrade-websocket-v1:
  websocket: Handle breaking from WebSocket::configure_analyzer()
  websocket: Address review feedback for BinPac code
  fuzzers: Add WebSocket fuzzer
  websocket: Fix crash for fragmented messages
  websocket: Verify Sec-WebSocket-Key/Accept headers and review feedback
  btest/websocket: Test for coalesced reply-ping
  HTTP/CONNECT: Also weird on extra data in reply
  HTTP/Upgrade: Weird when more data is available
  ContentLine: Add GetDeliverStreamRemainingLength() accessor
  HTTP: Drain event queue after instantiating upgrade analyzer
  btest/http: Explain switching-protocols test change as comment
  WebSocket: Introduce new analyzer and log
  HTTP: Add mechanism to instantiate Upgrade analyzer
This commit is contained in:
Arne Welzel 2024-01-23 18:01:50 +01:00
commit 822ca99e80
86 changed files with 1896 additions and 25 deletions

View file

@ -0,0 +1,13 @@
# @TEST-DOC: Test Broker WebSocket traffic.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/broker-websocket.pcap %INPUT
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: test ! -f analyzer.log
# @TEST-EXEC: test ! -f weird.log
@load base/protocols/conn
@load base/protocols/websocket

View file

@ -0,0 +1,33 @@
# @TEST-DOC: The reply-ping-coalesced pcap contains a WebSocket ping message right after the HTTP reply, in the same packet.
# @TEST-EXEC: zeek -b -r $TRACES/websocket/reply-ping-separate.pcap %INPUT >>out-separate
# @TEST-EXEC: test ! -f weird.log
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/reply-ping-coalesced.pcap %INPUT >>out-coalesced
# @TEST-EXEC: btest-diff out-separate
# @TEST-EXEC: btest-diff out-coalesced
# @TEST-EXEC: btest-diff weird.log
# @TEST-EXEC: diff out-separate out-coalesced
# @TEST-EXEC: test ! -f analyzer.log
@load base/protocols/websocket
event websocket_established(c: connection, aid: count)
{
print "websocket_established", c$uid, aid;
}
event websocket_frame(c: connection, is_orig: bool, fin: bool, rsv: count, opcode: count, payload_len: count)
{
print "websocket_frame", c$uid, is_orig, "fin", fin, "rsv", rsv, "opcode", WebSocket::opcodes[opcode], "payload_len", payload_len;
}
event websocket_frame_data(c: connection, is_orig: bool, data: string)
{
print "websocket_frame_data", c$uid, is_orig, "len", |data|, "data", data[:120];
}
event websocket_close(c: connection, is_orig: bool, status: count, reason: string)
{
print "websocket_close", c$uid, is_orig, "status", status, "reason", reason;
}

View file

@ -0,0 +1,42 @@
# @TEST-DOC: Test WebSocket events.
#
# @TEST-EXEC: echo "jupyter-websocket.pcap" >>out
# @TEST-EXEC: zeek -b -r $TRACES/websocket/jupyter-websocket.pcap %INPUT >>out
# @TEST-EXEC: echo "wstunnel-http.pcap" >>out
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-http.pcap %INPUT >>out
# @TEST-EXEC: echo "broker-websocket.pcap" >>out
# @TEST-EXEC: zeek -b -r $TRACES//websocket/broker-websocket.pcap %INPUT >>out
# @TEST-EXEC: echo "message-too-big-status.pcap" >>out
# @TEST-EXEC: zeek -b -r $TRACES//websocket/message-too-big-status.pcap %INPUT >>out
# @TEST-EXEC: echo "two-binary-fragments.pcap" >>out
# @TEST-EXEC: zeek -b -r $TRACES//websocket/two-binary-fragments.pcap %INPUT >>out
# @TEST-EXEC: btest-diff out
# @TEST-EXEC: test ! -f analyzer.log
# @TEST-EXEC: test ! -f weird.log
@load base/protocols/websocket
event websocket_established(c: connection, aid: count)
{
print "websocket_established", c$uid, aid, c$websocket;
}
event websocket_message(c: connection, is_orig: bool, opcode: count)
{
print "websocket_message", c$uid, is_orig, "opcode", WebSocket::opcodes[opcode];
}
event websocket_frame(c: connection, is_orig: bool, fin: bool, rsv: count, opcode: count, payload_len: count)
{
print "websocket_frame", c$uid, is_orig, "fin", fin, "rsv", rsv, "opcode", WebSocket::opcodes[opcode], "payload_len", payload_len;
}
event websocket_frame_data(c: connection, is_orig: bool, data: string)
{
print "websocket_frame_data", c$uid, is_orig, "len", |data|, "data", data[:120];
}
event websocket_close(c: connection, is_orig: bool, status: count, reason: string)
{
print "websocket_close", c$uid, is_orig, "status", status, "reason", reason;
}

View file

@ -0,0 +1,13 @@
# @TEST-DOC: Testing Jupyter WebSocket traffic.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/jupyter-websocket.pcap %INPUT
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
#
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: test ! -f analyzer.log
# @TEST-EXEC: test ! -f weird.log
@load base/protocols/conn
@load base/protocols/websocket

View file

@ -0,0 +1,7 @@
# @TEST-DOC: Test weird generation when the Sec-WebSocket-Accept socket isn't as expected.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wrong-accept-header.pcap %INPUT
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: btest-diff weird.log
@load base/protocols/websocket

View file

@ -0,0 +1,16 @@
# @TEST-DOC: Test HTTP connection tunneled within WebSocket using wstunnel. Seems something in the HTTP scripts gets confused :-/
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-http.pcap %INPUT
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
# @TEST-EXEC: zeek-cut -m ts uid host uri status_code user_agent < http.log > http.log.cut
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: btest-diff http.log.cut
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: test ! -f analyzer.log
# @TEST-EXEC: test ! -f weird.log
@load base/protocols/conn
@load base/protocols/ssh
@load base/protocols/websocket

View file

@ -0,0 +1,16 @@
# @TEST-DOC: Test SSH connection tunneled within WebSocket using wstunnel.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-https.pcap %INPUT
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
# @TEST-EXEC: zeek-cut -m ts uid version server_name ssl_history < ssl.log > ssl.log.cut
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: btest-diff ssl.log.cut
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: test ! -f analyzer.log
# @TEST-EXEC: test ! -f weird.log
@load base/protocols/conn
@load base/protocols/ssl
@load base/protocols/websocket

View file

@ -0,0 +1,33 @@
# @TEST-DOC: Test that breaking from configure_analyzer() removes the attached analyzer.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT >out 2>&1
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
# @TEST-EXEC: btest-diff out
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: test ! -f ssh.log
# @TEST-EXEC: test ! -f analyzer.log
@load base/protocols/conn
@load base/protocols/http
@load base/protocols/ssh
@load base/protocols/websocket
hook WebSocket::configure_analyzer(c: connection, aid: count, config: WebSocket::AnalyzerConfig)
{
print "WebSocket::configure_analyzer", c$uid, aid;
break;
}
# These should never be raised
event websocket_message(c: connection, is_orig: bool, opcode: count)
{
print "ERROR: websocket_message", c$uid, is_orig, "opcode", WebSocket::opcodes[opcode];
}
hook Analyzer::disabling_analyzer(c: connection, atype: AllAnalyzers::Tag, aid: count)
{
print "disabling_analyzer", c$uid, atype, aid;
}

View file

@ -0,0 +1,21 @@
# @TEST-DOC: Test SSH connection tunneled within WebSocket using wstunnel, attaches HTTP analyzer instead of SSH.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: test ! -f ssh.log
# @TEST-EXEC: test ! -f analyzer.log
@load base/protocols/conn
@load base/protocols/http
@load base/protocols/ssh
@load base/protocols/websocket
hook WebSocket::configure_analyzer(c: connection, aid: count, config: WebSocket::AnalyzerConfig)
{
print "WebSocket::configure_analyzer", c$uid, aid;
config$analyzer = Analyzer::ANALYZER_HTTP; # this is obviously wrong :-)
}

View file

@ -0,0 +1,22 @@
# @TEST-DOC: Test SSH connection tunneled within WebSocket using wstunnel, configure SSH analyzer via hook explicitly.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
# @TEST-EXEC: zeek-cut -m ts uid client server auth_success auth_attempts kex_alg host_key_alg < ssh.log > ssh.log.cut
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: btest-diff ssh.log.cut
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: test ! -f analyzer.log
# @TEST-EXEC: test ! -f weird.log
@load base/protocols/conn
@load base/protocols/ssh
@load base/protocols/websocket
hook WebSocket::configure_analyzer(c: connection, aid: count, config: WebSocket::AnalyzerConfig)
{
print "WebSocket::configure_analyzer", c$uid, aid;
config$analyzer = Analyzer::ANALYZER_SSH;
}

View file

@ -0,0 +1,19 @@
# @TEST-DOC: Test no analysis of tunneled WebSocket when the analyzer is globally disabled.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: test ! -f websocket.log
# @TEST-EXEC: test ! -f ssh.log
# @TEST-EXEC: test ! -f analyzer.log
# @TEST-EXEC: test ! -f weird.log
@load base/protocols/conn
@load base/protocols/ssh
@load base/protocols/websocket
redef Analyzer::disabled_analyzers += {
Analyzer::ANALYZER_WEBSOCKET,
};

View file

@ -0,0 +1,16 @@
# @TEST-DOC: Test SSH connection tunneled within WebSocket using wstunnel.
#
# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT
#
# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut
# @TEST-EXEC: zeek-cut -m ts uid client server auth_success auth_attempts kex_alg host_key_alg < ssh.log > ssh.log.cut
# @TEST-EXEC: btest-diff conn.log.cut
# @TEST-EXEC: btest-diff ssh.log.cut
# @TEST-EXEC: btest-diff websocket.log
# @TEST-EXEC: test ! -f analyzer.log
# @TEST-EXEC: test ! -f weird.log
@load base/protocols/conn
@load base/protocols/ssh
@load base/protocols/websocket