name: vyos-journal fieldsToBeRemovedBeforeParsing: [] $schema: https://schemas.humio.com/parser/v0.3.0 script: |- // VyOS 1.5 Parser // Author: Andrew James (semaja2) // Credit: Based on Crowdstrike NG-SIEM Linux Journal Parser // Version: 1.0 // Description: Parser for logs ingested via journald using Logscale Collector, not to be used for logs ingested via syslog // #region PREPARSE /************************************************************ ****** Parse timestamp and log headers ****** Extract message field for parsing ****** Parse structured data ************************************************************/ | case { @collect.source_type="journald" | rename([[__CURSOR, Vendor.__CURSOR], [__MONOTONIC_TIMESTAMP, Vendor.__MONOTONIC_TIMESTAMP], [__REALTIME_TIMESTAMP, Vendor.__REALTIME_TIMESTAMP], [_AUDIT_LOGINUID, Vendor._AUDIT_LOGINUID], [_AUDIT_SESSION, Vendor._AUDIT_SESSION], [_BOOT_ID, Vendor._BOOT_ID], [_CAP_EFFECTIVE, Vendor._CAP_EFFECTIVE], [_CMDLINE, Vendor._CMDLINE], [_COMM, Vendor._COMM], [CONTAINER_ID, Vendor.CONTAINER_ID], [CONTAINER_ID_FULL, Vendor.CONTAINER_ID_FULL], [CONTAINER_NAME, Vendor.CONTAINER_NAME], [CONTAINER_PARTIAL_MESSAGE, Vendor.CONTAINER_PARTIAL_MESSAGE], [CONTAINER_TAG, Vendor.CONTAINER_TAG], [_EXE, Vendor._EXE], [_GID, Vendor._GID], [_HOSTNAME, Vendor._HOSTNAME], [_MACHINE_ID, Vendor._MACHINE_ID], [_PID, Vendor._PID], [_SELINUX_CONTEXT, Vendor._SELINUX_CONTEXT], [_SOURCE_REALTIME_TIMESTAMP, Vendor._SOURCE_REALTIME_TIMESTAMP], [_SYSTEMD_CGROUP, Vendor._SYSTEMD_CGROUP], [_SYSTEMD_INVOCATION_ID, Vendor._SYSTEMD_INVOCATION_ID], [_SYSTEMD_OWNER_UID, Vendor._SYSTEMD_OWNER_UID], [_SYSTEMD_SESSION, Vendor._SYSTEMD_SESSION], [_SYSTEMD_SLICE, Vendor._SYSTEMD_SLICE], [_SYSTEMD_UNIT, Vendor._SYSTEMD_UNIT], [_SYSTEMD_USER_SLICE, Vendor._SYSTEMD_USER_SLICE], [_SYSTEMD_USER_UNIT, Vendor._SYSTEMD_USER_UNIT], [_TRANSPORT, Vendor._TRANSPORT], [_UID, Vendor._UID], [CODE_FILE, Vendor.CODE_FILE], [CODE_FUNC, Vendor.CODE_FUNC], [CODE_FUNCTION, Vendor.CODE_FUNCTION], [CODE_LINE, Vendor.CODE_LINE], [INVOCATION_ID, Vendor.INVOCATION_ID], [JOB_RESULT, Vendor.JOB_RESULT], [JOB_TYPE, Vendor.JOB_TYPE], [MESSAGE, Vendor.MESSAGE], [MESSAGE_ID, Vendor.MESSAGE_ID], [PRIORITY, Vendor.PRIORITY], [RESULT, Vendor.RESULT], [SYSLOG_FACILITY, Vendor.SYSLOG_FACILITY], [SYSLOG_IDENTIFIER, Vendor.SYSLOG_IDENTIFIER], [SYSLOG_PID, Vendor.SYSLOG_PID], [UNIT, Vendor.UNIT], [USER_INVOCATION_ID, Vendor.USER_INVOCATION_ID], [USER_UNIT, Vendor.USER_UNIT], [USERSPACE_USEC, Vendor.USERSPACE_USEC], [_STREAM_ID, Vendor._STREAM_ID], ["_AUDIT_FIELD_A0","_AUDIT_FIELD_A0"], ["_AUDIT_FIELD_A1", "Vendor._AUDIT_FIELD_A1"], ["_AUDIT_FIELD_A1", "Vendor._AUDIT_FIELD_A1"], ["_AUDIT_FIELD_A1", "Vendor._AUDIT_FIELD_A1"], ["_AUDIT_FIELD_APPARMOR", "Vendor._AUDIT_FIELD_APPARMOR"], ["_AUDIT_FIELD_ARCH", "Vendor._AUDIT_FIELD_ARCH"], ["_AUDIT_FIELD_ARGC", "Vendor._AUDIT_FIELD_ARGC"], ["_AUDIT_FIELD_CAP_FE", "Vendor._AUDIT_FIELD_CAP_FE"], ["_AUDIT_FIELD_CAP_FI", "Vendor._AUDIT_FIELD_CAP_FI"], ["_AUDIT_FIELD_CAP_FP", "Vendor._AUDIT_FIELD_CAP_FP"], ["_AUDIT_FIELD_CAP_FROOTID", "Vendor._AUDIT_FIELD_CAP_FROOTID"], ["_AUDIT_FIELD_CAP_FVER", "Vendor._AUDIT_FIELD_CAP_FVER"], ["_AUDIT_FIELD_CWD", "Vendor._AUDIT_FIELD_CWD"], ["_AUDIT_FIELD_DENIED_MASK", "Vendor._AUDIT_FIELD_DENIED_MASK"], ["_AUDIT_FIELD_DEV", "Vendor._AUDIT_FIELD_DEV"], ["_AUDIT_FIELD_EXIT", "Vendor._AUDIT_FIELD_EXIT"], ["_AUDIT_FIELD_INODE", "Vendor._AUDIT_FIELD_INODE"], ["_AUDIT_FIELD_ITEM", "Vendor._AUDIT_FIELD_ITEM"], ["_AUDIT_FIELD_ITEMS", "Vendor._AUDIT_FIELD_ITEMS"], ["_AUDIT_FIELD_KEY", "Vendor._AUDIT_FIELD_KEY"], ["_AUDIT_FIELD_MODE", "Vendor._AUDIT_FIELD_MODE"], ["_AUDIT_FIELD_NAME", "Vendor._AUDIT_FIELD_NAME"], ["_AUDIT_FIELD_NAMETYPE", "Vendor._AUDIT_FIELD_NAMETYPE"], ["_AUDIT_FIELD_OGID", "Vendor._AUDIT_FIELD_OGID"], ["_AUDIT_FIELD_OPERATION", "Vendor._AUDIT_FIELD_OPERATION"], ["_AUDIT_FIELD_OUID", "Vendor._AUDIT_FIELD_OUID"], ["_AUDIT_FIELD_PROFILE", "Vendor._AUDIT_FIELD_PROFILE"], ["_AUDIT_FIELD_RDEV", "Vendor._AUDIT_FIELD_RDEV"], ["_AUDIT_FIELD_REQUESTED_MASK", "Vendor._AUDIT_FIELD_REQUESTED_MASK"], ["_AUDIT_FIELD_SGID", "Vendor._AUDIT_FIELD_SGID"], ["_AUDIT_FIELD_SUCCESS", "Vendor._AUDIT_FIELD_SUCCESS"], ["_AUDIT_FIELD_SUID", "Vendor._AUDIT_FIELD_SUID"], ["_AUDIT_FIELD_SYSCALL", "Vendor._AUDIT_FIELD_SYSCALL"], ["_AUDIT_ID", "Vendor._AUDIT_ID"], ["_AUDIT_TYPE", "Vendor._AUDIT_TYPE"], ["_AUDIT_TYPE_NAME", "Vendor._AUDIT_TYPE_NAME"], ["_EGID", "Vendor._EGID"], ["_EUID", "Vendor._EUID"], ["_FSGID", "Vendor._FSGID"], ["_FSUID", "Vendor._FSUID"], ["_PPID", "Vendor._PPID"], ["_TTY", "Vendor._TTY"], ["ERRNO", "Vendor.ERRNO"], [USER_ID, Vendor.USER_ID], [SESSION_ID, Vendor.SESSION_ID], [LEADER, Vendor.LEADER], [SEAT_ID, "Vendor.SEAT_ID"]]); *; } | case { Vendor._SOURCE_REALTIME_TIMESTAMP=* | regex(field="Vendor._SOURCE_REALTIME_TIMESTAMP", regex="(?^\\d{13})") | parseTimestamp(field="temptime", format=unixtimeMillis) | drop([temptime]); Vendor.__REALTIME_TIMESTAMP=* | regex(field="Vendor.__REALTIME_TIMESTAMP", regex="(?^\\d{13})") | parseTimestamp(field="temptime", format=unixtimeMillis) | drop([temptime]); * | @timestamp:=@ingesttimestamp; } // #endregion // #region METADATA /************************************************************ ****** Static Metadata Definitions ************************************************************/ | Vendor := "vyos" | Parser.version := "1.0.0" | ecs.version := "8.11.0" | Cps.version := "1.0.0" // #endregion // #region NORMALIZATION /************************************************************ ****** Parse unstructured data (i.e. message field) ****** Normalize fields to data model ************************************************************/ | container.id := Vendor.CONTAINER_ID_FULL | container.name := Vendor.CONTAINER_NAME | array:append("container.image.tag[]", values=[Vendor.CONTAINER_TAG]) | event.created := Vendor.__REALTIME_TIMESTAMP | host.boot.id := Vendor._BOOT_ID | host.id := Vendor._MACHINE_ID | host.name := lower(Vendor._HOSTNAME) | message := Vendor._MESSAGE | process.user.id := Vendor._AUDIT_LOGINUID | process.session_leader.entity_id := Vendor._AUDIT_SESSION | array:append("process.thread.capabilities.effective[]", values=[Vendor._CAP_EFFECTIVE]) | process.command_line := Vendor._CMDLINE | process.executable := Vendor._EXE | process.name := Vendor._COMM | process.pid := Vendor._PID | process.entity_id := Vendor._GID | process.entity_id := Vendor._UID | log.syslog.facility.code := Vendor.SYSLOG_FACILITY | log.syslog.msgid := Vendor.SYSLOG_IDENTIFIER | log.syslog.procid := Vendor.SYSLOG_PID | log.syslog.priority := Vendor.PRIORITY //This handles additional parsing for cron.service, crond.service, sshd.service, and systemd-logind.service | case { @collect.unit="cron.service" OR @collect.unit="crond.service" | case { //pam_unix(cron:session): session opened for user root by (uid=0) @collect.unit="cron.service" AND /session\sopened/ | regex(field="@rawstring", regex="user\\s(?\\w+)") | array:append("event.category[]", values=["authentication", "session"]) | array:append("event.type[]", values=["start"]) | event.action:="login" | event.outcome:="success"; //(root) CMD (command) @collect.unit="cron.service" AND /CMD/ | regex(field="@rawstring", regex="\\((?\\w+)\\)\\s\\w+\\s\\((?.*)\\)") | array:append("event.category[]", values=["process"]) | array:append("event.type[]", values=["start"]) | event.action:="cron-execution" | event.outcome:="success"; //pam_unix(cron:session): session closed for user root @collect.unit="cron.service" AND /session\sclosed/ | regex(field="@rawstring", regex="user\\s(?\\w+)") | array:append("event.category[]", values=["session"]) | array:append("event.type[]", values=["end"]) | event.action:="logout" | event.outcome:="success"; *; } | case { //(root) CMD (command) @collect.unit="crond.service" AND /CMD/ | regex(field="@rawstring", regex="\\((?\\S+)\\)\\sCMD\\s\\((?.*)\\)") | array:append("event.category[]", values=["process"]) | array:append("event.type[]", values=["start"]) | event.action:="cron-execution" | event.outcome:="success"; //(username) ERROR (getpwnam() failed) @collect.unit="crond.service" AND /ERROR/ | regex(field="@rawstring", regex="\\((?\\S+)\\)\\sERROR\\s(?.*)") | event.outcome:="failure" | event.action:="cron-execution" | array:append("event.category[]", values=["process"]) | array:append("event.type[]", values=["info"]); //Catch all for crond service @collect.unit="crond.service" | regex(field="@rawstring", regex="^\\((?\\S+)\\)\\s(?.*)") | event.action:="cron-execution" | array:append("event.category[]", values=["process"]); // no valid event.type atm *; }; @collect.unit="ssh@default.service" OR @collect.unit="systemd-logind.service" | case { //Accepted password for username from ip port port ssh2 "@collect.unit"="ssh@default.service" AND /^Accepted/ | regex(field="@rawstring", regex="(?\\w+\\s\\w+)\\sfor\\s(?\\S+)\\s\\w+\\s(?\\S+)\\s\\w+\\s(?\\S+)") | array:append("event.category[]", values=["authentication", "session"]) | array:append("event.type[]", values=["start"]) | event.action:="login" | event.outcome:="success"; //Failed password for username from ip port port ssh2 "@collect.unit"="ssh@default.service" AND /^Failed/ | regex(field="@rawstring", regex="(?\\w+\\s\\w+)\\sfor\\s(invalid user\\s)?(?\\S+)\\s\\w+\\s(?\\S+)\\s\\w+\\s(?\\S+)") | array:append("event.category[]", values=["authentication", "session"]) // no valid event.type atm | event.action:="login" | event.outcome:="failure"; //pam_sss(sshd:auth): authentication success; logname= uid=0 euid=0 tty=ssh ruser= rhost= user= "@collect.unit"="ssh@default.service" AND /authentication\ssuccess/ | regex(field="@rawstring", regex=";\\s(?.*)") | array:append("event.category[]", values=["authentication", "session"]) | array:append("event.type[]", values=["start"]) | event.action:="login" | kvParse(field=eventtemp, as=Vendor.sshd, separatorPadding="no", excludeEmpty=true) | source.domain := lower(Vendor.sshd.rhost) | user.name:=Vendor.sshd.user | drop([eventtemp]) | event.outcome:="success"; //pam_sss(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost= user= "@collect.unit"="ssh@default.service" AND /authentication\sfailure/ | regex(field="@rawstring", regex=";\\s(?.*)") | array:append("event.category[]", values=["authentication", "session"]) // no valid event.type atm | event.action:="login" | kvParse(field=eventtemp, as=Vendor.sshd, separatorPadding="no", excludeEmpty=true) | source.domain := lower(Vendor.sshd.rhost) | user.name:=Vendor.sshd.user | drop([eventtemp]) | event.outcome:="failure"; //pingid.c(455) Successfully authenticated user "@collect.unit"="ssh@default.service" AND /Successfully\sauthenticated\suser/ | regex(field="@rawstring", regex="\\'(?\\S+)\\'$") | array:append("event.category[]", values=["authentication", "session"]) | array:append("event.type[]", values=["start"]) | event.action:="login" | event.outcome:="success"; //pam_sss Authentication failure "@collect.unit"="ssh@default.service" AND /Authentication\sfailure/ | regex(field="@rawstring", regex="user\\s(?\\S+):\\s\\d+\\s\\((?.*?)\\)") | array:append("event.category[]", values=["authentication", "session"]) // no valid event.type atm | event.action:="login" | event.outcome:="failure"; //Handle some errors "@collect.unit"="ssh@default.service" AND /^error/ | error.message:=@rawstring | array:append("event.category[]", values=["session"]) // no valid event.type atm | event.outcome:="failure"; //Catch all for sshd.service "@collect.unit"="ssh@default.service" | message := @rawstring | array:append("event.category[]", values=["authentication"]); // no valid event.type atm *; } | case { //User logging in "@collect.unit"="systemd-logind.service" AND /^New\ssession/ | user.id:=Vendor.USER_ID | array:append("event.category[]", values=["authentication", "session"]) | array:append("event.type[]", values=["start"]) | event.action:="login" | event.outcome:="success"; //user logging out "@collect.unit"="systemd-logind.service" AND /^Session\s\d+/ | user.id:=Vendor.USER_ID | array:append("event.category[]", values=["authentication", "session"]) | array:append("event.type[]", values=["end"]) | event.action:="logout" | event.outcome:="success"; *; }; Vendor.SYSLOG_IDENTIFIER = "kernel" | case { /^\[(?[\w\d-]+)\](?.*)/ | kvParse(field=msg, excludeEmpty=false, separator="=", separatorPadding=no) | drop(msg) | rename(field="PROTO", as="network.transport") | rename(field="SPT", as="source.port") | rename(field="SRC", as="source.ip") | rename(field="DPT", as="destination.port") | rename(field="DST", as="destination.ip") | rename(field="IN", as="network.interface.input") | rename(field="OUT", as="network.interface.output") | rename(field="LEN", as="network.bytes") | rename(field="ID", as="network.transport.id") | rename(field="PREC", as="network.ip.precedence") | rename(field="RES", as="network.ip.reserved") | rename(field="TOS", as="network.ip.tos") | rename(field="TTL", as="network.ip.ttl") | rename(field="URGP", as="network.transport.urgp") | rename(field="WINDOW", as="network.transport.window") | regex(field=MAC, regex="(?([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}):(?([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}):(?([0-9a-fA-F]{2}[:-]){1}[0-9a-fA-F]{2})", strict=false) | drop(MAC) | log.prefix match { "*-A" => event.outcome := "success"; "*-MASQ" => event.outcome := "success"; "*-D" => event.outcome := "failure"; * => event.outcome := "unknown" } | event.module := "firewall"; *; }; *; } // #endregion // #region POST-NORMALIZATION /************************************************************ ****** Post Normalization ****** Custom parser logic needed after normalization ************************************************************/ // #endregion tagFields: - Cps.version - Vendor - ecs.version - event.dataset - event.kind - event.module - event.outcome - observer.type