From cfa39f15bc156bf0125babe3471cae43b8254533 Mon Sep 17 00:00:00 2001 From: Matteo Pace Date: Wed, 13 Dec 2023 16:02:02 +0100 Subject: [PATCH] more forgiving base64 transformation --- internal/transformations/base64decode.go | 18 ++++- internal/transformations/base64decode_test.go | 78 +++++++++++++++++-- 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/internal/transformations/base64decode.go b/internal/transformations/base64decode.go index c4be9897c..52bb86baa 100644 --- a/internal/transformations/base64decode.go +++ b/internal/transformations/base64decode.go @@ -5,16 +5,28 @@ package transformations import ( "encoding/base64" + "strings" stringsutil "github.com/corazawaf/coraza/v3/internal/strings" ) // base64decode decodes a Base64-encoded string. func base64decode(data string) (string, bool, error) { - dec, err := base64.StdEncoding.DecodeString(data) + // RawStdEncoding.DecodeString accepts and requires an unpadded string as input + // https://stackoverflow.com/questions/31971614/base64-encode-decode-without-padding-on-golang-appengine + dataNoPadding := strings.TrimRight(data, "=") + dec, err := base64.RawStdEncoding.DecodeString(dataNoPadding) if err != nil { - // Forgiving implementation, which ignores invalid characters - return data, false, nil + // If the error is of type CorruptInputError, we can get the position of the illegal character + // and perform a partial decoding up to that point + if corrErr, ok := err.(base64.CorruptInputError); ok { + illegalCharPos := int(corrErr) + // Forgiving call to DecodeString, decoding is performed up to the illegal characther + // If an error occurs, dec will still contain the decoded string up to the error + dec, _ = base64.RawStdEncoding.DecodeString(dataNoPadding[:illegalCharPos]) + } else { + return data, false, nil + } } return stringsutil.WrapUnsafe(dec), true, nil } diff --git a/internal/transformations/base64decode_test.go b/internal/transformations/base64decode_test.go index d022b1659..65b43adbf 100644 --- a/internal/transformations/base64decode_test.go +++ b/internal/transformations/base64decode_test.go @@ -10,17 +10,81 @@ import ( "testing" ) -var b64DecodeTests = []string{ - "VGVzdENhc2U=", - "P.HNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==", - "VGVzdABDYXNl", +var b64DecodeTests = []struct { + name string + input string + expected string +}{ + { + name: "Valid", + input: "VGVzdENhc2U=", + expected: "TestCase", + }, + { + name: "Valid with \u0000", + input: "VGVzdABDYXNl", + expected: "Test\x00Case", + }, + { + name: "Valid without padding", + input: "VGVzdENhc2U", + expected: "TestCase", + }, + { + name: "Valid without longer padding", + input: "PA==", + expected: "<", + }, + { + name: "valid ", + input: "PFRFU1Q+", + expected: "", + }, + { + name: "decoded up to the space (invalid caracter)", + input: "PFR FU1Q+", + expected: "