Beyond good ol' LaunchAgent - part 1

Published: 2018-11-04
Last Updated: 2018-11-04 15:56:37 UTC
by Pasquale Stirparo (Version: 3)
0 comment(s)

Last week, on the inception diary of this series [1], I’ve talked about LaunchAgent and LaunchDaemon, probably the most known and popular persistence mechanisms under macOS. But there are other mechanisms, definitely not new and well known in the *nix world, which are still linked or managed by launchd [2]:

  1. at commands
  2. Cronjob
  3. Periodic

at commands and cronjobs [3][4] are the traditional *nix mechanism to schedule task execution and recurring execution respectively. Those are very much linked to LaunchDaemons, since Apple has replaced those functionalities with Daemons. However, although are deprecated mechanisms, Apple has still legacy support, which means that can be still (ab)used by malware.

AT command

Differently from cronjobs, at commands are meant to be run only once, the next time they are scheduled. In the new OS versions, at daemon has been moved to LaunchDaemon to be handled by the launchd process, and it is disabled by default, as you can verify here:

$ plutil -p /System/Library/LaunchDaemons/
 "Disabled" => 1
 " Label" => ""
 "ProgramArguments" => [
    0 => "/usr/libexec/atrun"
 "StartInterval" => 30

If enabled, standard at command can be used to schedule a task to run, such as
at 1450 tomorrow command_to_run
and you may still able to find evidence of those scheduled under /usr/lib/cron/jobs/


Cronjobs, as most of you already know, is the mechanism to tell the system to run specific tasks periodically at give intervals of time. The official way to do it in modern Apple systems, would be by using the StartCalendarInterval key in the Agent/Daemon plist file, as we have seen in the previous diary [1]. However, Apple still supports the legacy crontab mechanisms, which will run /usr/sbin/cron anytime a change in crontab or to files into /usr/lib/cron/tabs is detected [2]. To schedule a cronjob, it is sufficient to run crontab -e and insert the properly configured entry. As recap, the syntax is the following :

* * * * * command to execute

where the meaning of the asterisk is, in order from left to right:

  • min (0 - 59)
  • hour (0 - 23)
  • day of month (1 - 31)
  • month (1 - 12)
  • day of week (0 - 6), Sunday to Saturday, 7 is Sunday, same as 0

Some example of recurring execution:

Recurrence Example
Every day at 3pm 0 15 * * * /path/to/my/
Every work day at 3pm 0 15 * * 1-5 /path/to/my/ --argument
Every hour (at exactly hh:00) 0 * * * * /path/to/my/


One more way to schedule recurring tasks is to use periodic, part of the FreeBSD inheritance. Although commonly used to run system maintenance scripts, it can as well be abused to hide persistence mechanisms, also considering that is not often considered. Basically, periodic will run the scripts in the folders /etc/periodic/daily/, /etc/periodic/weekly/ and /etc/periodic/monthly/, the recurrence of which is easily comprehensible from the folders name. There you may be able to find traces of malicious recurring tasks as well.

Artifacts summary

Here a quick summary of the specific paths for the forensics artifacts of interest [5]:

AT Command:



Happy Hunting,


[1] - SANS ISC, “Beyond good ol’ LaunchAgent - part 0”,
[2] - Jonathan Levin (@Morpheus______), “*OS Internals”, 
[3] - MITRE ATT&CK (@MITREattack), “MacOS Techniques - Local Job Scheduling”,
[4] - Patrick Warlde (@patrickwardle), “OSX Malware Persistence”,
[5] - Pasquale Stirparo (@pstirparo), “mac4n6 Artifacts Project”,


Pasquale Stirparo,

0 comment(s)


Diary Archives