From 1585fbd9730303c99f331bae2a6c8a640970a504 Mon Sep 17 00:00:00 2001 From: davidrobert Date: Thu, 19 Sep 2024 10:57:32 +0300 Subject: [PATCH] Add PCI card information check --- src/node-agent/pkg/ebpf/eventreader.go | 7 +- src/node-agent/pkg/ebpf/types/types.go | 14 ++++ src/node-agent/pkg/eventparser/init.go | 6 ++ .../pkg/eventparser/pcidata/creditcard.go | 77 +++++++++++++++++++ .../pkg/eventparser/pcidata/handlers.go | 32 ++++---- .../pkg/eventparser/pcidata/parser.go | 32 ++++---- 6 files changed, 132 insertions(+), 36 deletions(-) create mode 100644 src/node-agent/pkg/eventparser/pcidata/creditcard.go diff --git a/src/node-agent/pkg/ebpf/eventreader.go b/src/node-agent/pkg/ebpf/eventreader.go index e3e24278..32115187 100644 --- a/src/node-agent/pkg/ebpf/eventreader.go +++ b/src/node-agent/pkg/ebpf/eventreader.go @@ -74,7 +74,12 @@ func (e *EventReader) Start() { // Process the event cInfo := e.containerMap[pidNamespaceInode] - eventContext := types.EventContext{Event: event, Data: data, Container: cInfo} + eventContext := types.EventContext{ + Event: event, + Data: data, + Container: cInfo, + Metadata: &types.EventMetadata{}, + } err = eventparser.ProcessEvent(eventContext) if err != nil { logrus.Printf("error processing event: %s", err) diff --git a/src/node-agent/pkg/ebpf/types/types.go b/src/node-agent/pkg/ebpf/types/types.go index c6de43ae..0c85c0f1 100644 --- a/src/node-agent/pkg/ebpf/types/types.go +++ b/src/node-agent/pkg/ebpf/types/types.go @@ -21,6 +21,13 @@ const ( BpfEventTypeURetProbe BpfEventType = "URetProbe" ) +type EventTag string + +const ( + EventTagPCI EventTag = "PCI" + EventTagPII EventTag = "PII" +) + type BpfProgram struct { Type BpfEventType Symbol string @@ -29,8 +36,15 @@ type BpfProgram struct { Address uint64 } +// EventContext contains the data and metadata for a BPF event - used for parsing and handling of events type EventContext struct { Data []byte Event otrzebpf.BpfSslEventT Container container.ContainerInfo + Metadata *EventMetadata // Metadata for the event - this is editable by parsers +} + +// EventMetadata contains the parsed metadata for a BPF event +type EventMetadata struct { + Tags map[EventTag]bool } diff --git a/src/node-agent/pkg/eventparser/init.go b/src/node-agent/pkg/eventparser/init.go index baf81d04..d4b701ba 100644 --- a/src/node-agent/pkg/eventparser/init.go +++ b/src/node-agent/pkg/eventparser/init.go @@ -5,6 +5,7 @@ import ( ebpftypes "github.com/otterize/network-mapper/src/node-agent/pkg/ebpf/types" "github.com/otterize/network-mapper/src/node-agent/pkg/eventparser/httprequest" "github.com/otterize/network-mapper/src/node-agent/pkg/eventparser/httpresponse" + "github.com/otterize/network-mapper/src/node-agent/pkg/eventparser/pcidata" "github.com/otterize/network-mapper/src/node-agent/pkg/eventparser/types" "github.com/sirupsen/logrus" ) @@ -21,6 +22,11 @@ func init() { // Initialize HTTP response parser httpResponseParser := &httpresponse.Parser{} parsers["httpresponse"] = httpResponseParser + + // Initialize PCI data parser + pciParser := &pcidata.Parser{} + pciParser.RegisterHandler(pcidata.ContainsPaymentInformation) + parsers["pci"] = pciParser } func ProcessEvent(ctx ebpftypes.EventContext) error { diff --git a/src/node-agent/pkg/eventparser/pcidata/creditcard.go b/src/node-agent/pkg/eventparser/pcidata/creditcard.go new file mode 100644 index 00000000..b9267b88 --- /dev/null +++ b/src/node-agent/pkg/eventparser/pcidata/creditcard.go @@ -0,0 +1,77 @@ +package pcidata + +import ( + "strings" + "unicode" +) + +// List of card prefixes and their corresponding lengths +var cardPrefixes = map[string][]int{ + "34": {15}, // AMEX + "37": {15}, // AMEX + "300": {15}, // Diners + "301": {15}, // Diners + "302": {15}, // Diners + "303": {15}, // Diners + "36": {15}, // Diners + "38": {15}, // Diners + "6011": {16}, // Discover + "2014": {16}, // Enroute + "2149": {16}, // Enroute + "2100": {16}, // JCB 15 + "1800": {16}, // JCB 15 + "3088": {16}, // JCB 16 + "3096": {16}, // JCB 16 + "3112": {16}, // JCB 16 + "3158": {16}, // JCB 16 + "3337": {16}, // JCB 16 + "3528": {16}, // JCB 16 + "51": {16}, // MasterCard + "52": {16}, // MasterCard + "53": {16}, // MasterCard + "54": {16}, // MasterCard + "55": {16}, // MasterCard + "4": {13, 16}, // Visa + "4539": {16}, // Visa + "4556": {16}, // Visa + "4916": {16}, // Visa + "4532": {16}, // Visa + "4929": {16}, // Visa + "40240071": {16}, // Visa + "4485": {16}, // Visa + "4716": {16}, // Visa + "8699": {13, 16}, // Voyager +} + +// Matches the following card formats: +// 4111111111111111 +// 4111 1111 1111 1111 +// 4111-1111-1111-1111 +// 4111.1111.1111.1111 +// **** **** **** 1111 +const cardRegex = `(?:(\d|\*)[ -\.]*?){13,19}` + +// Normalize card number by removing non-digit characters (if separated by spaces, dots, or dashes) +func normalizeCardNumber(card string) string { + var normalized string + for _, char := range card { + if unicode.IsDigit(char) { + normalized += string(char) + } + } + return normalized +} + +// Check if the card number is valid based on prefixes and length +func isValidCardNumber(card string) bool { + for prefix, lengths := range cardPrefixes { + if strings.HasPrefix(card, prefix) { + for _, length := range lengths { + if len(card) == length { + return true + } + } + } + } + return false +} diff --git a/src/node-agent/pkg/eventparser/pcidata/handlers.go b/src/node-agent/pkg/eventparser/pcidata/handlers.go index 691d5bed..d6d0cfcd 100644 --- a/src/node-agent/pkg/eventparser/pcidata/handlers.go +++ b/src/node-agent/pkg/eventparser/pcidata/handlers.go @@ -1,31 +1,25 @@ package pcidata import ( - "github.com/otterize/iamlive/iamlivecore" - "github.com/otterize/intents-operator/src/shared/errors" ebpftypes "github.com/otterize/network-mapper/src/node-agent/pkg/ebpf/types" - "io" - "net/http" + "regexp" ) -const AWSHost = "amazonaws.com" +func ContainsPaymentInformation(ctx ebpftypes.EventContext, data string) error { + // Regular expression for possible credit card patterns (13-19 digits, allowing spaces, dashes, or dots as separators) + re := regexp.MustCompile(cardRegex) -func HandleAwsRequest(ctx ebpftypes.EventContext, req *http.Request) error { - body, err := io.ReadAll(req.Body) - if err != nil { - return errors.Wrap(err) - } - - // Check if the event is an AWS request - called to host "amazonaws.com" - if req.Host != AWSHost { - return nil - } + // Find all matches + matches := re.FindAllString(data, -1) - // Check if the event is an egress event - if ebpftypes.Direction(ctx.Event.Meta.Direction) != ebpftypes.DirectionEgress { - return nil + // Filter matches based on valid credit card prefix and length + for _, match := range matches { + normalized := normalizeCardNumber(match) + if isValidCardNumber(normalized) { + // Set PCI tag + ctx.Metadata.Tags[ebpftypes.EventTagPCI] = true + } } - iamlivecore.HandleAWSRequest(req, body, 200) return nil } diff --git a/src/node-agent/pkg/eventparser/pcidata/parser.go b/src/node-agent/pkg/eventparser/pcidata/parser.go index ee116435..9cef4f25 100644 --- a/src/node-agent/pkg/eventparser/pcidata/parser.go +++ b/src/node-agent/pkg/eventparser/pcidata/parser.go @@ -1,40 +1,40 @@ package pcidata import ( - "bufio" - "bytes" "fmt" - "github.com/otterize/intents-operator/src/shared/errors" ebpftypes "github.com/otterize/network-mapper/src/node-agent/pkg/ebpf/types" "github.com/otterize/network-mapper/src/node-agent/pkg/eventparser/types" "github.com/sirupsen/logrus" - "net/http" + "unicode" ) type Parser struct { - handlers []types.DataHandler[*http.Request] + handlers []types.DataHandler[string] } -// Parse parses the HTTP request from the given data +// Parse parses the data to check if its plain text func (p *Parser) Parse(ctx ebpftypes.EventContext) (interface{}, error) { - reader := bufio.NewReader(bytes.NewReader(ctx.Data)) - req, err := http.ReadRequest(reader) - if err != nil { - return nil, errors.Wrap(err) + for _, b := range ctx.Data { + // Check if the byte is a printable character or common whitespace (ASCII values 32-126 or newline/carriage return) + if b > unicode.MaxASCII || (!unicode.IsPrint(rune(b)) && b != '\n' && b != '\r' && b != '\t') { + return nil, fmt.Errorf("data is not plain text") + } } + logrus.Debugf("Got plain text data: %s\n", string(ctx.Data)) - req.RemoteAddr = ctx.Container.PodIP - - logrus.Debugf("Got HTTP request: %s\n", string(ctx.Data)) + return string(ctx.Data), nil +} - return req, nil +// RegisterHandler registers a handler for PCI data +func (p *Parser) RegisterHandler(handler types.DataHandler[string]) { + p.handlers = append(p.handlers, handler) } // RunHandlers executes all registered handlers on the parsed data func (p *Parser) RunHandlers(ctx ebpftypes.EventContext, data interface{}) error { - req, ok := data.(*http.Request) + req, ok := data.(string) if !ok { - return fmt.Errorf("invalid type: expected *http.Request") + return fmt.Errorf("invalid type: expected string") } for _, handler := range p.handlers {