Windows.Detection.BinaryHunter

This artifact enables hunting for binary attributes.

The artifact takes a glob targetting input, then checks each file in scope for an MZ header. The artifact also queries Authenticode details and parses out PE attributes.

Both PE and Authenticode output can be queried for relevant strings using a regex filter and whitelist to hunt with. This enables unique capability to hunt for specific things such as PE imports, exports or other attributes.

Note: this artifacts filters are cumulative so a hash based hit will return no results if the file is filtered out by other filters. For most performant searches leverage path, size and and date filters. By default the artifact leverages the ‘auto’ data accessor but can also be changed as desired.


name: Windows.Detection.BinaryHunter
author: "Matt Green - @mgreen27"
description: |
    This artifact enables hunting for binary attributes.

    The artifact takes a glob targetting input, then checks each file in scope for an MZ header.
    The artifact also queries Authenticode details and parses out PE attributes.

    Both PE and Authenticode output can be queried for relevant strings using a regex filter and whitelist to hunt with.
    This enables unique capability to hunt for specific things such as PE imports, exports or other attributes.

    Note: this artifacts filters are cumulative so a hash based hit will return
    no results if the file is filtered out by other filters.
    For most performant searches leverage path, size and and date filters. By default
    the artifact leverages the 'auto' data accessor but can also be changed as desired.

parameters:
  - name: TargetGlob
    description: Glob to target.
    default: "C:/Users/**/*"
  - name: Accessor
    description: Velociraptor accessor to use. Changing to ntfs will increase scan time.
    default: auto
  - name: UnexpectedExtension
    description: "Exclude binaries with expected extension: com|cpl|dll|drv|exe|mui|scr|sfx|sys|winmd"
    type: bool
  - name: ExcludeTrusted
    description: Exclude binaries with Trusted Authenticode certificates.
    type: bool
  - name: AuthenticodeRegex
    description: Regex to search through all authenrticode data.
    default: .
    type: regex
  - name: AuthenticodeWhitelistRegex
    description: Regex to whitelist in all Authenticode data.
    default:
    type: regex
  - name: PEInformationRegex
    description: Regex to filter for PE information. e.g VersionInformation, exports etc
    default: .
    type: regex
  - name: PEInformationWhitelistRegex
    description: Regex to whitelist for PE information. e.g VersionInformation, exports etc
    default:
    type: regex
  - name: DateAfter
    description: Search for binaries with timestamps after this date. YYYY-MM-DDTmm:hh:ssZ
    type: timestamp
  - name: DateBefore
    description: Search for binaries with timestamps before this date. YYYY-MM-DDTmm:hh:ssZ
    type: timestamp
  - name: SizeMax
    description: Return binaries only under this size in bytes.
    type: int64
    default: 4294967296
  - name: SizeMin
    description: Return binaries only over this size in bytes.
    type: int64
    default: 0
  - name: MD5List
    description: MD5 hash list to hunt for. New MD5 hash on each line
    default:
  - name: SHA1List
    description: SHA1 hash list to hunt for. New SHA1 hash on each line
    default:
  - name: SHA256List
    description: SHA256 hash list to hunt for. New SHA256 hash on each line
    default:
  - name: DISABLE_DANGEROUS_API_CALLS
    type: bool
    description: |
      Enable this to disable potentially flakey APIs which may cause
      crashes.

sources:
  - query: |
      -- setup hash lists if needed
      LET MD5Array <= split(sep='\\s+',string=MD5List)
      LET SHA1Array <=  split(sep='\\s+',string=SHA1List)
      LET SHA256Array <= split(sep='\\s+',string=SHA256List)

      -- firstly find files in scope with performance
      LET find_files = SELECT *,
            read_file(filename=OSPath,accessor=Accessor,offset=0,length=2) as _Header
        FROM if(condition=DateBefore AND DateAfter,
            then={
                SELECT OSPath, Name, Size,Mtime,Atime,Ctime,Btime
                FROM glob(globs=TargetGlob,accessor=Accessor)
                WHERE NOT IsDir AND NOT IsLink
                    AND Size > SizeMin AND Size < SizeMax
                    AND ( Mtime < DateBefore OR Ctime < DateBefore OR Btime < DateBefore )
                    AND ( Mtime > DateAfter OR Ctime > DateAfter OR Btime > DateAfter )
            },
            else={ SELECT * FROM  if(condition=DateBefore,
                then={
                    SELECT OSPath, Name, Size,Mtime,Atime,Ctime,Btime
                    FROM glob(globs=OSPath,accessor=Accessor)
                    WHERE NOT IsDir AND NOT IsLink
                        AND Size > SizeMin AND Size < SizeMax
                        AND ( Mtime < DateBefore OR Ctime < DateBefore OR Btime < DateBefore )
                },
                else={ SELECT * FROM  if(condition=DateAfter,
                then={
                    SELECT OSPath, Name, Size,Mtime,Atime,Ctime,Btime
                    FROM glob(globs=TargetGlob,accessor=Accessor)
                    WHERE NOT IsDir AND NOT IsLink
                        AND Size > SizeMin AND Size < SizeMax
                        AND ( Mtime > DateAfter OR Ctime > DateAfter OR Btime > DateAfter )
                },
                else={
                    SELECT OSPath, Name, Size,Mtime,Atime,Ctime,Btime
                    FROM glob(globs=TargetGlob,accessor=Accessor)
                    WHERE NOT IsDir AND NOT IsLink
                        AND Size > SizeMin AND Size < SizeMax
                })})})
        WHERE _Header = 'MZ'
            AND if(condition= UnexpectedExtension,
                then= NOT Name =~ '\.(com|cpl|dll|drv|exe|mui|scr|sfx|sys|winmd)$',
                else= True)


      -- parse PE attributes and run final filters
      SELECT
        dict(OSPath=OSPath,Name=Name,Size=Size,
            Timestamps=dict(Mtime=Mtime,Atime=Atime,Ctime=Ctime,Btime=Btime)
                ) as File,
        authenticode(filename=OSPath) as Authenticode,
        parse_pe(file=OSPath) as PE,
        hash(path=OSPath) as Hash
      FROM find_files
      WHERE
        serialize(item=Authenticode) =~ AuthenticodeRegex
        AND NOT if(condition=WhitelistRegex,
            then= serialize(item=Authenticode) =~ AuthenticodeWhitelistRegex,
            else= False)
        AND serialize(item=PE) =~ PEInformationRegex
        AND NOT if(condition=PEInformationWhitelistRegex,
            then= serialize(item=PE) =~ PEInformationWhitelistRegex,
            else= False)
        AND if(condition= ExcludeTrusted,
                then= NOT Authenticode.Trusted = "trusted",
                else= True)
        AND if(condition= MD5List OR SHA1List OR SHA256List,
            then=(
                    if(condition= MD5List,
                    then= Hash.MD5 in MD5Array)
                 OR if(condition= SHA1List,
                        then= Hash.SHA1 in SHA1Array)
                 OR if(condition= SHA256List,
                        then= Hash.SHA256 in SHA256Array)
            ), else = True )