From 755c43f450138fa0a7c4b75d35fa13986e705690 Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Wed, 21 Sep 2022 22:08:39 +0100 Subject: [PATCH] Run mod_security logs through a JSON converter --- Dockerfile | 6 ++ .../conf-available/modsecurity-custom.conf | 2 + modsec_logger.go | 67 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 modsec_logger.go diff --git a/Dockerfile b/Dockerfile index 9dd0bad9..1b0bfc0a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,8 @@ +FROM golang:1.19 AS gobuild +COPY modsec_logger.go /src/modsec_logger.go +WORKDIR /src +RUN go build -tags netgo -o modsec_logger modsec_logger.go + FROM composer:2.2.9 as build ADD . /build @@ -15,6 +20,7 @@ COPY docker/wp-config.php /opt/noblogs/www/wp-config.php COPY docker/wp-cache-config.php /opt/noblogs/www/wp-content/wp-cache-config.php COPY docker/conf /tmp/conf COPY docker/build.sh /tmp/build.sh +COPY --from=gobuild /src/modsec_logger /usr/local/bin/modsec_logger RUN /tmp/build.sh && rm /tmp/build.sh diff --git a/docker/conf/apache2/conf-available/modsecurity-custom.conf b/docker/conf/apache2/conf-available/modsecurity-custom.conf index 10340f55..07b6877f 100644 --- a/docker/conf/apache2/conf-available/modsecurity-custom.conf +++ b/docker/conf/apache2/conf-available/modsecurity-custom.conf @@ -6,5 +6,7 @@ SecRuleEngine Off </Location> + ErrorLog "|/usr/local/bin/modsec_logger" + </IfModule> </IfModule> diff --git a/modsec_logger.go b/modsec_logger.go new file mode 100644 index 00000000..2988f3ad --- /dev/null +++ b/modsec_logger.go @@ -0,0 +1,67 @@ +// Tool to rewrite mod_security2 logs (very difficult to parse +// although they are in semi-structured format) to JSON. +// +package main + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + "os" + "regexp" +) + +var ( + outerRx = regexp.MustCompile(`\[[^\]]+]`) + innerRx = regexp.MustCompile(`\[([^ ]+) \"?(.*)\"\]$`) + needle = []byte("ModSecurity: ") +) + +func parseModSec(w io.Writer, line []byte) bool { + if !bytes.Contains(line, needle) { + return false + } + + fields := make(map[string]interface{}) + var tags []string + for _, inner := range outerRx.FindAll(line, -1) { + for _, matches := range innerRx.FindAllSubmatch(inner, -1) { + field := string(matches[1]) + value := string(matches[2]) + switch field { + case "tag": + tags = append(tags, value) + case "client", "unique_id", "file", "line": + // Suppress these tags. + default: + fields[field] = value + } + } + } + if len(fields) == 0 { + return false + } + if len(tags) > 0 { + fields["tag"] = tags + } + + data, _ := json.Marshal(fields) + fmt.Fprintf(w, "@cee:{\"modsec\":%s}\n", data) + return true +} + +func main() { + outw := bufio.NewWriter(os.Stdout) + defer outw.Flush() + + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + line := scanner.Bytes() + if !parseModSec(outw, line) { + outw.Write(line) + io.WriteString(outw, "\n") + } + } +} -- GitLab