Detection rules › Elastic

VirtualProtect API via Stack Truncation

Source
github.com/elastic/protections-artifacts

Identifies VirtualProtect API calls from call stacks that are unexpectedly short. This may be an attempt to conceal the true source of the call.

MITRE ATT&CK coverage

TacticTechniques
Stealth

Rule body

[rule]
description = """
Identifies VirtualProtect API calls from call stacks that are unexpectedly short. This may be an attempt to conceal the
true source of the call.
"""
id = "ef47dbfc-5e0b-4e97-83f6-d40026634999"
license = "Elastic License v2"
name = "VirtualProtect API via Stack Truncation"
os_list = ["windows"]
version = "1.0.4"

query = '''
api where process.Ext.api.name == "VirtualProtect" and
 process.thread.Ext.call_stack_final_user_module.name in ("Unknown", "Undetermined") and
_arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info : "c:\\windows\\sys?????\\ntdll.dll!??ProtectVirtualMemory*") and
(
 (process.thread.Ext.call_stack_summary == "ntdll.dll|Unknown" and process.Ext.api.behaviors == "native_api" and
  process.Ext.api.behaviors in ("hollow_unbacked", "image_indirect_call")) or

 (process.Ext.api.behaviors == "truncated_stack" and process.thread.Ext.call_stack_summary == "ntdll.dll" and
  process.Ext.api.parameters.size > 4096 and
  not _arraysearch(process.thread.Ext.call_stack, $entry,
                   $entry.symbol_info: ("c:\\windows\\sys?????\\ntdll.dll!RtlUserThreadStart*",
                                        "c:\\windows\\sys?????\\ntdll.dll!LdrInitializeThunk*",
                                        "c:\\windows\\sys?????\\ntdll.dll!RtlCaptureStackContext*",
                                        /* covered by 9906a386-771f-4003-b426-fbe75bdd6e73 */
                                        "c:\\windows\\system32\\ntdll.dll!NtTestAlert*")) and
  not _arraysearch(process.thread.Ext.call_stack, $entry, $entry.protection_provenance like ("Kernel", "Kernel|*")))
) and
/* Dr.Web Shellguard anti-exploit module */
not (process.thread.Ext.call_stack_summary == "ntdll.dll|Unknown" and
     process.executable : ("C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE",
                           "C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE",
                           "C:\\Program Files\\Microsoft Office\\root\\Office16\\POWERPNT.EXE") and
     process.parent.executable : ("C:\\Windows\\System32\\svchost.exe",
                                  "C:\\Windows\\explorer.exe",
                                  "C:\\Windows\\System32\\OpenWith.exe"))
'''

min_endpoint_version = "8.14.0"
optional_actions = []
[[actions]]
action = "kill_process"
field = "process.entity_id"
state = 0

[[threat]]
framework = "MITRE ATT&CK"
[[threat.technique]]
id = "T1055"
name = "Process Injection"
reference = "https://attack.mitre.org/techniques/T1055/"


[threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"

[internal]
min_endpoint_version = "8.14.0"

Stages and Predicates

Stage 1: api

api where process.Ext.api.name == "VirtualProtect" and
 process.thread.Ext.call_stack_final_user_module.name in ("Unknown", "Undetermined") and
_arraysearch(process.thread.Ext.call_stack, $entry, $entry.symbol_info : "c:\\windows\\sys?????\\ntdll.dll!??ProtectVirtualMemory*") and
(
 (process.thread.Ext.call_stack_summary == "ntdll.dll|Unknown" and process.Ext.api.behaviors == "native_api" and
  process.Ext.api.behaviors in ("hollow_unbacked", "image_indirect_call")) or
 (process.Ext.api.behaviors == "truncated_stack" and process.thread.Ext.call_stack_summary == "ntdll.dll" and
  process.Ext.api.parameters.size > 4096 and
  not _arraysearch(process.thread.Ext.call_stack, $entry,
                   $entry.symbol_info: ("c:\\windows\\sys?????\\ntdll.dll!RtlUserThreadStart*",
                                        "c:\\windows\\sys?????\\ntdll.dll!LdrInitializeThunk*",
                                        "c:\\windows\\sys?????\\ntdll.dll!RtlCaptureStackContext*",
                                        "c:\\windows\\system32\\ntdll.dll!NtTestAlert*")) and
  not _arraysearch(process.thread.Ext.call_stack, $entry, $entry.protection_provenance like ("Kernel", "Kernel|*")))
) and
not (process.thread.Ext.call_stack_summary == "ntdll.dll|Unknown" and
     process.executable : ("C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE",
                           "C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE",
                           "C:\\Program Files\\Microsoft Office\\root\\Office16\\POWERPNT.EXE") and
     process.parent.executable : ("C:\\Windows\\System32\\svchost.exe",
                                  "C:\\Windows\\explorer.exe",
                                  "C:\\Windows\\System32\\OpenWith.exe"))

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
process.Ext.api.behaviorseq
  • native_api corpus 4 (elastic 4)
  • truncated_stack corpus 2 (elastic 2)
field:"process.Ext.api.behaviors" kind:eq
process.Ext.api.behaviorsin
  • hollow_unbacked
  • image_indirect_call
field:"process.Ext.api.behaviors" kind:in
process.Ext.api.nameeq
  • VirtualProtect corpus 19 (elastic 19)
field:"process.Ext.api.name" kind:eq value:"VirtualProtect"
process.Ext.api.parameters.sizegt
  • 4096 transforms: number corpus 5 (elastic 5)
field:"process.Ext.api.parameters.size" kind:gt value:"4096"
process.thread.Ext.call_stack_final_user_module.namein
  • Undetermined corpus 4 (elastic 4)
  • Unknown corpus 2 (elastic 2)
field:"process.thread.Ext.call_stack_final_user_module.name" kind:in
process.thread.Ext.call_stack_summaryeq
  • ntdll.dll corpus 3 (elastic 3)
  • ntdll.dll|Unknown corpus 2 (elastic 2)
field:"process.thread.Ext.call_stack_summary" kind:eq