Skip to content

plist Structure

macOS relies heavily on property list (plist) files to store configuration data for system services, user preferences, and launchd job definitions. Understanding the structure and syntax of these files is critical for red teams seeking to inject malicious configurations for persistence. Plist files are XML-based and often used to define launch agents, system services, or hidden process configurations. This section covers the fundamentals of plist syntax, common use cases, and techniques for parsing/modifying them.


Basic Syntax and Elements

Plist files are structured as nested dictionaries (<dict>), arrays (<array>), or strings/numbers. Key-value pairs are defined using <key> and <string>/<integer> tags.

Example: Simple Dictionary

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.example.malicious</string>
    <key>Program</key>
    <string>/path/to/malicious_binary</string>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

Key Elements Explained:
- <key>: Defines a configuration parameter (e.g., Label, Program).
- <string>: Stores textual values (e.g., binary paths).
- <true/>/<false/>: Boolean flags (e.g., RunAtLoad).
- <integer>: Numeric values (e.g., StartInterval).


Common Plist Use Cases for Persistence

Launchd plists are a primary target for persistence. By modifying these files, attackers can ensure their payloads run at system boot or under specific triggers.

Example: Launchd Agent for Persistence

<dict>
    <key>Label</key>
    <string>com.attacker.persist</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/python3</string>
        <string>/Users/attacker/malicious.py</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
This configuration ensures the payload runs immediately and persists across reboots.


Parsing and Modifying Plist Files

Use tools like plutil (command-line) or plutil (Python library) to parse and edit plists.

Convert Plist to JSON for Editing

# Convert plist to JSON
plutil -convert json /path/to/valid.plist -o /path/to/output.json

# Edit JSON file manually (e.g., add new keys)
nano /path/to/output.json

Reconvert to Plist Format

plutil -convert xml1 /path/to/output.json -o /path/to/modified.plist

Manual XML Editing
Use a text editor (e.g., vim, nano) to directly modify XML syntax. Ensure proper nesting and closing tags to avoid parsing errors.


Advanced Techniques and Pitfalls

  • Obfuscation: Use hex editors or base64 encoding to hide malicious payloads within plist values.
  • Validation: Always verify the plist structure with plutil -validate to avoid system rejections.
  • Permissions: Ensure modified plists have appropriate ownership (root:wheel) and permissions (644).

Example: Hidden Process via Plist

<dict>
    <key>Label</key>
    <string>com.apple.systemhelper</string>
    <key>Program</key>
    <string>/System/Library/CoreServices/ActivityMonitor.app/Contents/MacOS/ActivityMonitor</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>LD_LIBRARY_PATH</key>
        <string>/Users/attacker/lib</string>
    </dict>
</dict>
This example injects a custom library path to load malicious code into a trusted process.


Key takeaways

  • Plist files are XML-based and structured with dictionaries, arrays, and key-value pairs.
  • Launchd plists are ideal for persistence, enabling payloads to run at boot or on-demand.
  • Use plutil to convert between formats, and validate syntax to avoid errors.
  • Obfuscate payloads and leverage environment variables for stealthier execution.
  • Always ensure proper permissions and ownership when deploying modified plists.