Linux.Detection.Honeyfiles

This artifact deploys honeyfiles according to the Honeyfiles CSV parameter. It then monitors access to these files using eBPF. The process tracker must be enabled, we use this to enrich events. You also must be using Velociraptor >= 0.74 to support eBPF. Honeyfiles created by this artifact are removed at exit.

  • TargetPath - Location to create honeyfile.
  • Enabled - Only generate the honeyfile if this is set to ‘Y’
  • MagicBytes - The starting magic bytes of the honeyfile.
  • MinSize,MaxSize - The size of the honeyfile will be a random value between MinSize and MaxSize.

name: Linux.Detection.Honeyfiles
author: Zane Gittins & Matt Green (@mgreen27).
description: |
    This artifact deploys honeyfiles according to the Honeyfiles CSV parameter. It then monitors access to these files using eBPF.  The process tracker must be enabled, we use this to enrich events. You also must be using Velociraptor >= 0.74 to support eBPF. Honeyfiles created by this artifact are removed at exit.

    * TargetPath - Location to create honeyfile.
    * Enabled - Only generate the honeyfile if this is set to 'Y'
    * MagicBytes - The starting magic bytes of the honeyfile.
    * MinSize,MaxSize - The size of the honeyfile will be a random value between MinSize and MaxSize.

type: CLIENT_EVENT

parameters:
   - name: Honeyfiles
     description: The honeyfiles to generate and monitor.
     type: csv
     default: |
         TargetPath,Enabled,MagicBytes,MinSize,MaxSize
         "%USERPROFILE%/.ssh/my_id_rsa",Y,2D2D2D2D2D424547494E205253412050524956415445204B45592D2D2D2D2D,10249,20899
         "%USERPROFILE%/.aws/credentials",Y,5B64656661756C745D,512,2048
         "%USERPROFILE%/.gcloud/credentials.db",Y,53514c69746520666f726d6174203300,512,2048
         "%USERPROFILE%/.azure/azureProfile.json",Y,7B0D0A,512,2048
   - name: ProcessExceptionsRegex
     description: Except these processes from detections when they access honeyfiles.
     type: string
     default: "/usr/bin/updatedb"
   - name: HoneyUserRegex
     description: User name regex that will be used to host honeyfiles.
     type: string
     default: "."
sources:
  - precondition:
        SELECT OS From info() where OS = 'linux' AND version(plugin="watch_ebpf") >= 0

    query: |
       LET RandomChars(size) = SELECT
           format(format="%02x", args=rand(range=256)) AS HexByte
         FROM range(end=size)
       
       LET check_exist(path) = SELECT
           OSPath,
           Size,
           IsDir,
           if(condition=read_file(filename=OSPath)[-7:] =~ 'VRHoney',
              then=True,
              else=False) AS IsHoneyFile
         FROM stat(filename=path)
       
       LET enumerate_path = SELECT regex_replace(source=TargetPath,
                                                 re='''\%USERPROFILE\%''',
                                                 replace=Homedir) AS TargetPath,
                                   *,
                                   check_exist(path=regex_replace(
                                                 source=TargetPath,
                                                 re='''\%USERPROFILE\%''',
                                                 replace=Homedir))[0] AS Exists,
                                   MaxSize - rand(range=(MaxSize - MinSize)) -
                                     len(list=unhex(string=MagicBytes)) - 7 AS _PaddingSize
         FROM Honeyfiles
       
       LET target_users = SELECT User,
                                 Homedir,
                                 Uid
         FROM Artifact.Linux.Sys.Users()
         WHERE int(int=Uid) >= 1000
          AND NOT Homedir = '/nonexistent'
               AND User =~ HoneyUserRegex
       
       LET show_honeyfiles = SELECT TargetPath,
                                    Enabled,
                                    MagicBytes,
                                    MinSize,
                                    MaxSize,
                                    _PaddingSize,
                                    Exists.Size AS Size,
                                    Exists.IsHoneyFile AS IsHoneyFile
         FROM foreach(row=target_users, query=enumerate_path)
       
       LET copy_honeyfiles = SELECT
           *, if(condition=Enabled =~ "^(Y|YES)$"
                  AND (NOT Size OR IsHoneyFile),
                 then=log(message="Creating file %v", dedup=-1, args=TargetPath)
                  AND copy(dest=TargetPath,
                           create_directories='y',
                           accessor='data',
                           filename=unhex(
                             string=MagicBytes + join(
                               array=RandomChars(size=_PaddingSize).HexByte) +
                               format(format='%x', args='VRHoney'))),
                 else="File does not exist") AS CreateHoneyFile
         FROM show_honeyfiles
       
       LET remove_honeyfiles = SELECT
           *, _PaddingSize,
           if(condition=IsHoneyFile,
              then=log(message="Removing %v", args=TargetPath, dedup=-1)
               AND rm(filename=TargetPath),
              else="File does not exist") AS RemoveHoneyFile
         FROM show_honeyfiles
       
       LET add_honeyfiles = SELECT
           TargetPath,
           Enabled,
           MagicBytes,
           MinSize,
           MaxSize,
           check_exist(path=TargetPath)[0].Size AS Size,
           check_exist(path=TargetPath)[0].IsHoneyFile AS IsHoneyFile
         FROM copy_honeyfiles
       
       LET _ <= atexit(query={ SELECT * FROM remove_honeyfiles })
       
       LET WatchFiles <= to_dict(item={
           SELECT TargetPath AS _key,
                  IsHoneyFile AS _value
           FROM add_honeyfiles
           WHERE IsHoneyFile
         })
       
       LET CurrentPid <= getpid()
       
       LET TargetEvents = SELECT *
         FROM watch_ebpf(events=["security_file_open"])
         WHERE System.EventName = "security_file_open"
          AND System.ProcessID != CurrentPid
       
       LET AuditEvents = SELECT
           *, timestamp(string=System.Timestamp) AS Timestamp,
           get(item=WatchFiles, field=EventData.pathname) AS IsHoneyFile
         FROM TargetEvents
         WHERE IsHoneyFile != NULL
       
       LET Track = SELECT
           Timestamp,
           System.ProcessID AS Pid,
           EventData.pathname AS FileName,
           process_tracker_get(id=System.ProcessID).Data AS ProcInfo,
           join(array=process_tracker_callchain(id=System.ProcessID).Data.Name,
                sep="->") AS CallChain,
           (System.ProcessID+EventData.pathname) as DedupKey
         FROM AuditEvents
         WHERE NOT ProcInfo.Exe =~ ProcessExceptionsRegex
       
       SELECT 
         Timestamp,
         Pid,
         FileName,
         ProcInfo,
         CallChain 
       FROM dedup(query={
          SELECT *,
          FROM delay(query=Track, delay=5)
       },key="DedupKey",timeout=2)