Screensaver Plist File Modified by Unexpected Process

Identifies when a screensaver plist file is modified by an unexpected process. An adversary can maintain persistence on a macOS endpoint by creating a malicious screensaver (.saver) file and configuring the screensaver plist file to execute code each time the screensaver is activated.

Elastic rule (View on GitHub)

 1[metadata]
 2creation_date = "2021/10/05"
 3integration = ["endpoint"]
 4maturity = "production"
 5min_stack_comments = "New fields added: required_fields, related_integrations, setup"
 6min_stack_version = "8.3.0"
 7updated_date = "2023/06/22"
 8
 9[rule]
10author = ["Elastic"]
11description = """
12Identifies when a screensaver plist file is modified by an unexpected process. An adversary can maintain persistence on
13a macOS endpoint by creating a malicious screensaver (.saver) file and configuring the screensaver plist file to execute
14code each time the screensaver is activated.
15"""
16from = "now-9m"
17index = ["auditbeat-*", "logs-endpoint.events.*"]
18language = "eql"
19license = "Elastic License v2"
20name = "Screensaver Plist File Modified by Unexpected Process"
21note = """## Triage and analysis
22
23- Analyze the plist file modification event to identify whether the change was expected or not
24- Investigate the process that modified the plist file for malicious code or other suspicious behavior
25- Identify if any suspicious or known malicious screensaver (.saver) files were recently written to or modified on the host
26
27## Setup
28
29If enabling an EQL rule on a non-elastic-agent index (such as beats) for versions <8.2, events will not define `event.ingested` and default fallback for EQL rules was not added until 8.2, so you will need to add a custom pipeline to populate `event.ingested` to @timestamp for this rule to work.
30"""
31references = [
32    "https://posts.specterops.io/saving-your-access-d562bf5bf90b",
33    "https://github.com/D00MFist/PersistentJXA",
34]
35risk_score = 47
36rule_id = "e6e8912f-283f-4d0d-8442-e0dcaf49944b"
37severity = "medium"
38tags = ["Domain: Endpoint", "OS: macOS", "Use Case: Threat Detection", "Tactic: Persistence", "Data Source: Elastic Defend"]
39timestamp_override = "event.ingested"
40type = "eql"
41
42query = '''
43file where host.os.type == "macos" and event.type != "deletion" and
44  file.name: "com.apple.screensaver.*.plist" and
45   file.path : (
46      "/Users/*/Library/Preferences/ByHost/*",
47      "/Library/Managed Preferences/*",
48      "/System/Library/Preferences/*"
49      ) and
50  (
51    process.code_signature.trusted == false or
52    process.code_signature.exists == false or
53
54    /* common script interpreters and abused native macOS bins */
55    process.name : (
56      "curl",
57      "mktemp",
58      "tail",
59      "funzip",
60      "python*",
61      "osascript",
62      "perl"
63      )
64   ) and
65
66  /* Filter OS processes modifying screensaver plist files */
67  not process.executable : (
68    "/usr/sbin/cfprefsd",
69    "/usr/libexec/xpcproxy",
70    "/System/Library/CoreServices/ManagedClient.app/Contents/Resources/MCXCompositor",
71    "/System/Library/CoreServices/ManagedClient.app/Contents/MacOS/ManagedClient"
72    )
73'''
74
75
76[[rule.threat]]
77framework = "MITRE ATT&CK"
78[[rule.threat.technique]]
79id = "T1546"
80name = "Event Triggered Execution"
81reference = "https://attack.mitre.org/techniques/T1546/"
82
83
84[rule.threat.tactic]
85id = "TA0003"
86name = "Persistence"
87reference = "https://attack.mitre.org/tactics/TA0003/"

Triage and analysis

  • Analyze the plist file modification event to identify whether the change was expected or not
  • Investigate the process that modified the plist file for malicious code or other suspicious behavior
  • Identify if any suspicious or known malicious screensaver (.saver) files were recently written to or modified on the host

Setup

If enabling an EQL rule on a non-elastic-agent index (such as beats) for versions <8.2, events will not define event.ingested and default fallback for EQL rules was not added until 8.2, so you will need to add a custom pipeline to populate event.ingested to @timestamp for this rule to work.

References

Related rules

to-top