Skip to content

Commit

Permalink
Add sensitive traffic detection (#239)
Browse files Browse the repository at this point in the history
  • Loading branch information
otterobert authored Sep 8, 2024
1 parent 2832c74 commit e2cea47
Show file tree
Hide file tree
Showing 13 changed files with 157 additions and 56 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@
# IDE
.idea/
*.iml

# BPF specific files
*.o
vmlinux.h
20 changes: 14 additions & 6 deletions src/ebpf/agent.ebpf.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
//go:build ignore

// Common header for all eBPF programs
#include "headers.h"
#include "maps.h"
#include "filters.h"
#include "common.h"
#include "include/headers.h"

// Event logic
#include "include/events/events.h"
#include "include/events/events.c"

// Filter logic
#include "include/filters/pci.h"
#include "include/filters/pci.c"

#include "include/filters/filters.h"
#include "include/filters/filters.c"

// All eBPF programs
#include "gotls.ebpf.c"
#include "openssl.ebpf.c"
#include "gotls/gotls.ebpf.c"
#include "openssl/openssl.ebpf.c"

char _license[] SEC("license") = "GPL";
2 changes: 1 addition & 1 deletion src/ebpf/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
package ebpf

//go:generate sh -c "bpftool btf dump file /sys/kernel/btf/vmlinux format c > ./include/vmlinux.h"
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $GOARCH -cc clang -no-strip -cflags "-O2 -g -Wall" Bpf ./agent.ebpf.c -- -I.:/usr/include/bpf:/usr/include/linux -I./include -I./gotls -I./openssl -DTARGET_ARCH_$GOARCH
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $GOARCH -cc clang -no-strip -cflags "-O2 -g -Wall" Bpf ./agent.ebpf.c -- -I.:/usr/include/bpf:/usr/include/linux -I./ -DTARGET_ARCH_$GOARCH
5 changes: 2 additions & 3 deletions src/ebpf/gotls/gotls.ebpf.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//go:build ignore

#include "headers.h"
#include "maps.h"
#include "common.h"
#include "include/headers.h"
#include "include/events/events.h"

// ####################################################################### //
// Definitions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "filters.h"
#include "include/filters/filters.h"

static __inline __u32 get_pid() {
return bpf_get_current_pid_tgid() >> 32;
Expand Down
8 changes: 8 additions & 0 deletions src/ebpf/include/maps.h → src/ebpf/include/events/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,11 @@ struct {
__type(value, struct go_slice_t);
__uint(max_entries, 1024);
} go_tls_context SEC(".maps");

// ####################################################################### //
// Function declarations
// ####################################################################### //

static __inline __u32 get_pid();
static __inline int should_trace();
static __inline void send_event(struct pt_regs *ctx, __u64 buf, __u64 size, __u64 total_size, enum direction_t direction) ;
41 changes: 3 additions & 38 deletions src/ebpf/include/filters.h → src/ebpf/include/filters/filters.c
Original file line number Diff line number Diff line change
@@ -1,42 +1,7 @@
#pragma once

#define HOST_HEADER_LEN 6
#define AUTH_HEADER_LEN 14
#define MAX_HEADER_LENGTH 255
#include "filters.h"

#define HOST_HEADER "Host: "
#define AUTH_HEADER "Authorization: "

#define HOST_AWS "amazonaws.com"
#define HOST_AWS_LEN 13

struct http_request_t {
// Request headers
__u32 host_len;
char host[MAX_HEADER_LENGTH];

__u32 auth_len;
char auth[MAX_HEADER_LENGTH];

// Internal state
char cur_line[MAX_HEADER_LENGTH];
};

struct http_request_ctx_t {
__u8 *data;
int data_len;
__u32 line_start;
};

struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, __u32);
__type(value, struct http_request_t);
__uint(max_entries, 1);
} http_request_map SEC(".maps");

// TODO: This should be available in the BPF helpers - could not find it
static inline int helper_memcmp(const char *s1, const char *s2, int len) {
static __inline int helper_memcmp(const char *s1, const char *s2, int len) {
#pragma unroll
for (int i = 0; i < len; i++) {
if (s1[i] != s2[i]) {
Expand All @@ -46,7 +11,7 @@ static inline int helper_memcmp(const char *s1, const char *s2, int len) {
return 0; // Strings match
}

static inline bool is_http_request(__u8 *data, int data_len) {
static __inline bool is_http_request(__u8 *data, int data_len) {
int method_lens[] = {3, 4, 3, 6, 4, 7, 6};
const char *methods[] = {"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"};

Expand Down
43 changes: 43 additions & 0 deletions src/ebpf/include/filters/filters.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#define HOST_HEADER_LEN 6
#define AUTH_HEADER_LEN 14
#define MAX_HEADER_LENGTH 255

#define HOST_HEADER "Host: "
#define AUTH_HEADER "Authorization: "

#define HOST_AWS "amazonaws.com"
#define HOST_AWS_LEN 13

struct http_request_t {
// Request headers
__u32 host_len;
char host[MAX_HEADER_LENGTH];

__u32 auth_len;
char auth[MAX_HEADER_LENGTH];

// Internal state
char cur_line[MAX_HEADER_LENGTH];
};

struct http_request_ctx_t {
__u8 *data;
int data_len;
__u32 line_start;
};

struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__type(key, __u32);
__type(value, struct http_request_t);
__uint(max_entries, 1);
} http_request_map SEC(".maps");


// ####################################################################### //
// Function declarations
// ####################################################################### //

static __inline bool should_send_event(struct ssl_event_t *event);
62 changes: 62 additions & 0 deletions src/ebpf/include/filters/pci.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

#include "pci.h"

// Check if the character is a digit
static __inline bool is_digit(char c) {
return c >= '0' && c <= '9';
}

// Luhn check to validate a card number
// Ref: https://en.wikipedia.org/wiki/Luhn_algorithm
bool luhn_check(const char *card_number, int len) {
__u32 sum = 0;
bool even = true; // Start with alternating since the check digit is not doubled

// Process all digits except the last one (check digit)
for (int i = len - 2; i >= 0; i--) {
__u32 digit = card_number[i] - '0'; // Convert character to integer
if (digit < 0 || digit > 9) return false; // value may only contain digits
if (even) digit *= 2; // double the value
if (digit > 9) digit -= 9;

even = !even;
sum += digit;
}

// Add the check digit (last digit) to the sum
__u32 checksum = card_number[len - 1] - '0';
sum += checksum;

// If the total modulo 10 is 0, the number is valid
return (sum % 10 == 0);
}

// Helper function to check for card-like sequences
bool detect_card_number(const char *data, int data_len) {
int digit_count = 0;
char card_number[MAX_CARD_LEN]; // Store potential card number sequence

for (int i = 0; i < data_len; i++) {
if (is_digit(data[i])) {
card_number[digit_count] = data[i]; // Store digit
digit_count++;

// Reset count if we exceed the maximum card number length
if (digit_count > MAX_CARD_LEN) digit_count = 0;
} else {
// Check if we have a valid card number length and validate with Luhn check
if (digit_count >= MIN_CARD_LEN && digit_count <= MAX_CARD_LEN) {
if (luhn_check(card_number, digit_count)) return true;
}

digit_count = 0; // Reset count if non-digit found
}
}

// Check again at the end in case the card number is at the end of the string
if (digit_count >= MIN_CARD_LEN && digit_count <= MAX_CARD_LEN) {
return luhn_check(card_number, digit_count);
}

return false; // No valid card number detected
}
5 changes: 5 additions & 0 deletions src/ebpf/include/filters/pci.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

#define MIN_CARD_LEN 13
#define MAX_CARD_LEN 19

bool detect_card_number(const char *data, int data_len);
3 changes: 1 addition & 2 deletions src/ebpf/include/headers.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>

#include <bpf/bpf_core_read.h>
13 changes: 12 additions & 1 deletion src/ebpf/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@ var Objs BpfObjects
var Specs BpfSpecs

func init() {
// Load and assign specs
specs, err := LoadBpf()
if err != nil {
logrus.Fatalf("error loading specs: %s", err)

}
err = specs.Assign(&Specs)
if err != nil {
logrus.Fatalf("error assigning specs: %s", err)
}

// Load pre-compiled programs and maps into the kernel.
if err := LoadBpfObjects(&Objs, nil); err != nil {
logrus.Fatalf("loading objects: %s", err)
logrus.Fatalf("error loading objects: %s", err)
}

logrus.Info("Loaded gotls objects")
Expand Down
6 changes: 2 additions & 4 deletions src/ebpf/openssl/openssl.ebpf.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
//go:build ignore

#include "headers.h"
#include "maps.h"
#include "common.h"

#include "include/headers.h"
#include "include/events/events.h"

SEC("uprobe/otterize_SSL_write")
void BPF_KPROBE(otterize_SSL_write, void* ssl, uintptr_t buffer, int num) {
Expand Down

0 comments on commit e2cea47

Please sign in to comment.