From eff26f2536d1df32d6eb205f3bdd1f25c6f31298 Mon Sep 17 00:00:00 2001 From: Adrian Serrano Date: Thu, 8 Feb 2018 21:44:36 +0100 Subject: [PATCH] Fix http parsing of repeated headers (#6325) Packetbeat HTTP protocol parser was not concatenating properly repeated headers in a request or response. This caused corruption in the header in the form of null bytes (\u0000). --- CHANGELOG.asciidoc | 1 + packetbeat/protos/http/http_parser.go | 4 ++-- packetbeat/protos/http/http_test.go | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index d502b22171d..fdd75c8b686 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -128,6 +128,7 @@ https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD di - Fix http status phrase parsing not allow spaces. {pull}5312[5312] - Fix http parse to allow to parse get request with space in the URI. {pull}5495[5495] - Fix mysql SQL parser to trim `\r` from Windows Server `SELECT\r\n\t1`. {pull}5572[5572] +- Fix corruption when parsing repeated headers in an HTTP request or response. {pull}6325[6325] *Winlogbeat* diff --git a/packetbeat/protos/http/http_parser.go b/packetbeat/protos/http/http_parser.go index a35100e1b29..1526c47e985 100644 --- a/packetbeat/protos/http/http_parser.go +++ b/packetbeat/protos/http/http_parser.go @@ -356,8 +356,8 @@ func (parser *parser) parseHeader(m *message, data []byte) (bool, bool, int) { if val, ok := m.headers[string(headerName)]; ok { composed := make([]byte, len(val)+len(headerVal)+2) off := copy(composed, val) - off = copy(composed[off:], []byte(", ")) - copy(composed[off:], headerVal) + copy(composed[off:], []byte(", ")) + copy(composed[off+2:], headerVal) m.headers[string(headerName)] = composed } else { diff --git a/packetbeat/protos/http/http_test.go b/packetbeat/protos/http/http_test.go index e90ba6f2c86..3aee21531b8 100644 --- a/packetbeat/protos/http/http_test.go +++ b/packetbeat/protos/http/http_test.go @@ -1168,6 +1168,28 @@ func Test_gap_in_body_http1dot0(t *testing.T) { assert.Equal(t, false, complete) } +func TestHttpParser_composedHeaders(t *testing.T) { + data := "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "Date: Tue, 14 Aug 2012 22:31:45 GMT\r\n" + + "Set-Cookie: aCookie=yummy\r\n" + + "Set-Cookie: anotherCookie=why%20not\r\n" + + "\r\n" + http := httpModForTests(nil) + http.parserConfig.sendHeaders = true + http.parserConfig.sendAllHeaders = true + message, ok, complete := testParse(http, data) + + assert.True(t, ok) + assert.True(t, complete) + assert.False(t, message.isRequest) + assert.Equal(t, 200, int(message.statusCode)) + assert.Equal(t, "OK", string(message.statusPhrase)) + header, ok := message.headers["set-cookie"] + assert.True(t, ok) + assert.Equal(t, "aCookie=yummy, anotherCookie=why%20not", string(header)) +} + func testCreateTCPTuple() *common.TCPTuple { t := &common.TCPTuple{ IPLength: 4,