Detection rules › Kusto

Ingress Tool Transfer - Certutil

Status
available
Severity
low
Time window
14d
Source
github.com/Azure/Azure-Sentinel

This detection addresses most of the known ways to utilize this binary for malicious/unintended purposes. It attempts to accommodate for most detection evasion techniques, like commandline obfuscation and binary renaming.

MITRE ATT&CK coverage

Event coverage

Rule body kusto

id: f0be11a9-ec48-4df6-801d-479556044d4e
name: Ingress Tool Transfer - Certutil
description: |
  This detection addresses most of the known ways to utilize this binary for malicious/unintended purposes. 
  It attempts to accommodate for most detection evasion techniques, like commandline obfuscation and binary renaming.
severity: Low
status: Available
requiredDataConnectors:
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceProcessEvents
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
  - DefenseEvasion
relevantTechniques:
  - T1105
  - T1564.004
  - T1027
  - T1140
query: |
  // Set the time span for the query.
  let Timeframe = 1h;
  // Set the HashTimeframe for the hash lookup; longer makes it more accurate, but obviously also more resource-intensive.
  let HashTimeframe = 14d;
  // Get all known SHA1 hashes for certutil executions or renamed files formerly named certutil.
  let CertUtilPESha1=materialize(DeviceProcessEvents | where Timestamp > ago(HashTimeframe)| where FileName has "certutil"  | where isnotempty(SHA1) | summarize sha1=make_set(SHA1));
  let CertUtilFESha1=materialize(DeviceFileEvents | where Timestamp > ago(HashTimeframe)| where PreviousFileName contains "certutil" or FileName contains "certutil"  | where isnotempty(SHA1) | summarize sha1=make_set(SHA1));
  DeviceProcessEvents
  | where Timestamp >= ago(Timeframe)
  // Get all executions by processes with a SHA1 hash that is or was named certutil.
  | where SHA1 in (CertUtilPESha1) or SHA1 in (CertUtilFESha1) or FileName =~ "certutil.exe" or ProcessCommandLine has "certutil"
  // Create a new field called CleanProcessCommandLine which gets populated with the value of ProcessCommandLine as Windows parses it for execution, 
  // removing any potential command line obfuscation. 
  | extend CleanProcessCommandLine=parse_command_line(ProcessCommandLine, "windows")
  // Search for de-obfuscated commands used. 
  // Urlcache is the documented attribute. However, url is also accepted.
  // Verifyctl is the documented attribute. However, verify is also accepted.
  | where CleanProcessCommandLine has_any ("decode", "encode", "verify","url") 
  | order by Timestamp
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: DeviceName
  - entityType: Account
    fieldMappings:
      - identifier: Sid
        columnName: AccountSid 
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountDomain
  - entityType: Process
    fieldMappings:
      - identifier: CommandLine
        columnName: ProcessCommandLine
version: 1.0.0
kind: Scheduled

Stages and Predicates

Parameters

let Timeframe = 1h;
let HashTimeframe = 14d;

Let binding: CertUtilPESha1

let CertUtilPESha1 = materialize(DeviceProcessEvents | where Timestamp > ago(HashTimeframe)| where FileName has "certutil"  | where isnotempty(SHA1) | summarize sha1=make_set(SHA1));

Derived from HashTimeframe.

Let binding: CertUtilFESha1

let CertUtilFESha1 = materialize(DeviceFileEvents | where Timestamp > ago(HashTimeframe)| where PreviousFileName contains "certutil" or FileName contains "certutil"  | where isnotempty(SHA1) | summarize sha1=make_set(SHA1));

Derived from HashTimeframe.

Stage 1: source

DeviceProcessEvents

Stage 2: where

| where Timestamp >= ago(Timeframe)

Stage 3: where

| where SHA1 in (CertUtilPESha1) or SHA1 in (CertUtilFESha1) or FileName =~ "certutil.exe" or ProcessCommandLine has "certutil"

References CertUtilFESha1, CertUtilPESha1 (defined above).

Stage 4: extend

| extend CleanProcessCommandLine=parse_command_line(ProcessCommandLine, "windows")

Stage 5: where

| where CleanProcessCommandLine has_any ("decode", "encode", "verify","url")

Stage 6: sort

| order by Timestamp

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
CleanProcessCommandLinematch
  • decode
  • encode
  • url
  • verify
FileNameeq
  • certutil.exe
ProcessCommandLinematch
  • certutil transforms: term corpus 12 (sigma 10, kusto 2)
SHA1in
  • CertUtilFESha1 transforms: cased
  • CertUtilPESha1 transforms: cased

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
CleanProcessCommandLineextend