MacOS.Applications.SavedState

On macOS, certain application state is saved in /Users/*/Library/Saved Application State/.

We can check these files to determine the last time an application was opened, the title of the application window, and when the application/window was later restored, such as after login or reboot.

In general, the following has been observed:

  • The ‘SavedState’ files are created when the application is started.
  • SavedState directory - Btime - Last time the application was opened by the user.
  • SavedState directory - ModTime - When the application state was last restored (such as after login/reboot).
  • data.data files - the actual data within the app, such as the scrollback for a Terminal window. The data within can be an (AES-128-CBC) encrypted blob. This data can be decrypted using the appropriate NSDataKey value found in windows.plist.
  • data.data - ModTime - changes when new data is added to the state, for example, when interacting with the Terminal application.
  • windows.plist – contains the name of application windows (NSTitle, as well as other information such as:
    • NSDataKey
    • NSDockMenu.name – names respective to the user’s dock/etc.
    • NSWindowID – can be used to link the NSDataKey to the PersistentUIRecord value in the data.data file.
  • windows.plist - BTime - last time application was restored
  • windows.plist - ModTime - changes when new data is added to the state, for example, when interacting with the Terminal application.

name: MacOS.Applications.SavedState
description: |
   On macOS, certain application state is saved in `/Users/*/Library/Saved Application State/`. 
   
   We can check these files to determine the last time an application was opened, the title of the application window, and when the application/window was later restored, such as after login or reboot.
   
   In general, the following has been observed:
   
   - The 'SavedState' files are created when the application is started.
   - `SavedState` directory - `Btime` - Last time the application was opened by the user.
   - `SavedState` directory - `ModTime` - When the application state was last restored (such as after login/reboot).
   - `data.data` files - the actual data within the app, such as the scrollback for a `Terminal` window. The data within can be an (AES-128-CBC) encrypted blob. This data can be decrypted using the appropriate `NSDataKey` value found in `windows.plist`.
   - `data.data` - `ModTime` - changes when new data is added to the state, for example, when interacting with the Terminal application.
   - `windows.plist` -- contains the name of application windows (NSTitle, as well as other information such as:
     - `NSDataKey` 
     - `NSDockMenu.name` -- names respective to the user's dock/etc.
     - `NSWindowID` -- can be used to link the `NSDataKey` to the `PersistentUIRecord` value in the `data.data` file. 
   - `windows.plist` - `BTime` - last time application was restored
   - `windows.plist` - `ModTime` - changes when new data is added to the state, for example, when interacting with the Terminal application.
reference:
  - https://www.sans.org/blog/osx-lion-user-interface-preservation-analysis/
  - https://www.crowdstrike.com/blog/reconstructing-command-line-activity-on-macos/
type: CLIENT

author: Wes Lambert - @therealwlambert|@weslambert@infosec.exchange

parameters:
- name: SavedStateGlob
  default: /Users/*/Library/Saved Application State/com.apple.**
- name: NameFilter
  default: .
  description: Filter used for targeting results by application name
- name: UserFilter
  default: .
  description: Filter used for targeting results by user name
precondition:
      SELECT OS From info() where OS = 'darwin'

sources:
  - query: |
      LET SavedStateList = SELECT ModTime,
                                  Btime,
                                  OSPath,
                                  regex_replace(source=OSPath[4], replace="", re=".savedState") AS Name,
                                  OSPath[1] AS _User
                           FROM glob(globs=split(string=SavedStateGlob, sep=","))
      SELECT *,
             if(condition = OSPath =~ "windows.plist", then=items(item=plist(file=OSPath))._value.NSDockMenu.name)[0][0] AS DockMenuName,
             if(condition = OSPath =~ "windows.plist", then=items(item=plist(file=OSPath))._value.NSTitle)[0] AS WindowTitle,
             if(condition = OSPath =~ "windows.plist", then=plist(file=OSPath)) AS _WindowDetails
      FROM foreach(row=SavedStateList)
      WHERE Name =~ NameFilter
      AND _User =~ UserFilter