FreeBSD.Sys.Utx

Parse the utx file of the system (similar to wtmp on Linux). This covers user sessions, boots, shutdowns and system time changes. Because FreeBSD discards fields for the entries of the utx file based on type (see man getutxent), no direct parsing of the file using “vtypes” is done (too complicated for me to define a structure for parsing), but rather native tools are used for accessing the data.

Using a value of “time” with the “userRegex” Parameter will give you all entries related to boots, shutdowns and system time changes.

Beware: logout times are given in localtime! Furthermore, that column is not automatically parsed into timestamp values, because the tool output is not consistently a recognizable datetime.


name: FreeBSD.Sys.Utx
author: Herbert Bärschneider
description: |
  Parse the utx file of the system (similar to wtmp on Linux). This covers user sessions, boots, shutdowns and system time changes.
  Because FreeBSD discards fields for the entries of the utx file based on type (see `man getutxent`), no direct parsing of the file using "vtypes" is done (too complicated for me to define a structure for parsing), but rather native tools are used for accessing the data.
  
  Using a value of "time" with the "userRegex" Parameter will give you all entries related to boots, shutdowns and system time changes.
  
  Beware: logout times are given in localtime! Furthermore, that column is not automatically parsed into timestamp values, because the tool output is not consistently a recognizable datetime.

type: CLIENT

parameters:
  - name: utxGlobs
    default: /var/log/utx.log*
    description: |
      glob for covering the files that should be parsed; default covers the usual location of the utx file on FreeBSD
  - name: userRegex
    type: regex
    default: "."
    description: |
      Regex for filtering the users, showing those you are interested in 
  - name: DateAfter
    type: timestamp
    description: |
      timestamp used for filtering the login time
  - name: DateBefore
    type: timestamp
    description: |
      timestamp used for filtering the login time

sources:
  - precondition:
      SELECT OS From info() where OS = 'freebsd'
    query: |
      -- timestamps given by the system command "last" are in local time, so we tell Velociraptor to handle them accordingly when converting with the VQL function "timestamp()"
      LET PARSE_TZ <= "local"
      
      -- time test function (taken from Windows.NTFS.MFT)
      LET time_test(stamp) =
            if(condition= DateBefore AND DateAfter,
                then= stamp < DateBefore AND stamp > DateAfter,
                else=
            if(condition=DateBefore,
                then= stamp < DateBefore,
                else=
            if(condition= DateAfter,
                then= stamp > DateAfter,
                else= True
            )))
      
      -- expand the glob and get all files that are matched by it
      LET Files = SELECT OSPath FROM glob(globs=split(string=utxGlobs, sep=","))
      
      -- for each targeted file, parse the data out of it using system built-in command 
      LET UtxParsing = SELECT * FROM foreach(row=Files,
      query={
        -- TODO: try the command while setting env variable "TZ" to UTC and check, if the timestamps are changed accordingly
        SELECT * 
        FROM execve(argv=["last", "-wy", "--libxo=json", "-f", OSPath])
        WHERE log(message="stderr: " + Stderr) 
      })
      
      -- parse the output from each file as json
      LET UtxContent = SELECT parse_json(data=Stdout) as Content FROM UtxParsing
      
      -- pull out the interesting information from the nested json content
      LET s = scope() -- a little helper to suppress "symbol not found error" for elements of the content that are sometimes missing
      LET FormatedContent = SELECT * FROM foreach(row=UtxContent,
      query={
        SELECT user, timestamp(string=`login-time`) AS login_time, s.`logout-time` AS logout_time, s.`session-length` AS session_length, s.tty AS tty, s.`from` AS remote, Content.`last-information`.utxdb AS utx_log FROM foreach(row=Content.`last-information`.last)
      })
      
      SELECT * FROM FormatedContent WHERE
        user =~ userRegex
        AND time_test(stamp=login_time)