上周处理一台终端异常时,用户跟我说,电脑突然变卡,右下角还反复弹出奇怪的窗口。我查了PowerShell操作日志,发现就在一小时前,这台机器执行了一条非常可疑的命令——它先向一个陌生域名发起了DNS TXT查询,然后把拿到的内容拼接成一段脚本运行。进一步追问才知道,用户之前在某个网站看到“浏览器异常,点击修复”的提示,按照页面指引按下Win+R并粘贴了一段“修复代码”。这就是典型的Click Fix攻击:攻击者不直接给你传文件,而是让你自己动手把恶意PowerShell命令送进系统。更巧妙的是,命令本体不是藏在网页里,而是藏在一段看起来人畜无害的DNS TXT记录中。
要理解这种攻击,需要同时搞懂三件事:攻击者如何让人乖乖执行命令(社会工程)、为什么用DNS TXT传递负载(信道选择)、以及PowerShell拿到负载后做了什么(执行逻辑)。这篇文章我按攻防双方的视角,把整套链路拆开讲清楚,并给出检测、取证和防御的可落地方法。适合安全运维、蓝队成员,以及想搞明白“为什么不能随便复制终端命令”的普通用户。
1. 攻击链路全景拆解:一次点击修复背后发生了什么
1.1 什么是Click Fix:伪装成“修复”的社会工程诱导
Click Fix(点击修复)并非某个软件的名字,而是安全圈对一类攻击手法的统称。它的核心套路是:在页面上模拟一个“系统出问题需要修复”的界面,常见的有四类:
- 伪浏览器错误页:提示“浏览器组件已损坏,请点击Fix”;
- 伪验证码页面:提示“人机验证失败,请运行命令完成验证”;
- 伪软件激活页:提示“Office许可证异常,请按步骤修复”;
- 伪安全警报:提示“检测到病毒,请执行清理命令”。
每类页面的终点几乎一样:让用户复制一段精心构造的命令,按Win+R调出运行框,粘贴后回车。为什么攻击者要绕这么大一圈,而不是直接投放exe文件?因为浏览器下载exe会被拦截提示,邮件网关也会扫描附件;而复制粘贴命令属于用户主动操作,很多杀毒软件不会对运行框里的内容做严格检查。从攻击者角度看,这是把恶意代码“合法化”为一次本地用户操作,远比投毒exe的成功率高。
1.2 DNS TXT记录:为什么攻击者选择它作为载荷分发通道
DNS TXT记录原本是一个很朴素的机制:给域名附加一段人类可读的文本说明,后来大量用于SPF邮件校验、站点所有权验证这些场景。它的特点是存储和查询都非常简单,几乎不会触发内容安全网关对“下载文件”的检查。攻击者看中的正是这一点。
把恶意PowerShell命令塞进TXT记录有几个现实好处:
- 查询流量看起来就是普通DNS请求,很多防火墙不会对DNS流量做深度内容检测;
- 载荷不在受害者的磁盘上出现,静态文件的扫描完全失效;
- 攻击者可以随时修改TXT记录里的内容,相当于拥有一个即时更新的恶意代码分发源;
- 托管成本极低,一个域名、一条解析记录就能反复使用。
和HTTP下载相比,DNS TXT不需要等待文件传输,查询速度快,而且浏览器安全策略对DNS查询管得很少。当然,TXT记录能承载的数据量有限(实际可用通常在几百到几千字节),所以攻击者一般用它传递第一阶段的小型loader命令,再让这个loader从HTTP服务器拉取更大的工具包。
1.3 完整攻击链:从诱饵页面到持久化后门
把前面两部分串起来,一次典型的Click Fix + DNS TXT攻击可以分为六个阶段:
| 阶段 | 攻击行为 | 攻击者的目标 |
|---|---|---|
| 投放 | 通过恶意广告、钓鱼邮件或SEO挂马把受害者引到伪造页面 | 建立信任 |
| 诱导 | 页面展示“复制-运行”操作指引 | 让用户主动执行命令 |
| 启动 | 受害者按Win+R粘贴并运行PowerShell命令 | 完成代码执行入口 |
| 拉取 | PowerShell解析域名,查询TXT记录获取载荷 | 绕过文件检测 |
| 执行 | 解码载荷,下载并运行后续恶意模块 | 落地植入 |
| 持久化 | 写入开机自启、计划任务或注册表 | 维持控制 |
这里最关键的是“诱导”和“拉取”两个阶段。前者决定攻击能不能开张,后者决定攻击能不能躲过检测。很多安全团队在防范时只盯着“是否有恶意文件落地”,结果这套攻击从第一行命令开始就不落文件,自然容易漏掉。
2. 恶意载荷的技术拆解:DNS TXT里的PowerShell如何被解析执行
在分析和防御这套攻击前,必须把DNS TXT和PowerShell的执行机制弄明白。
2.1 DNS TXT记录的基本原理
TXT记录本质上是一组由引号包裹的字符串,用来描述域名的附加信息。在命令行工具里,你可以用nslookup直接查询:
nslookup -type=TXT clickfix.example.com在PowerShell中则用:
Resolve-DnsName -Type TXT clickfix.example.com查询结果通常返回类似"Q2xpY2tGaXggRXhhbXBsZQ=="这样的字符串。这个字符串就是攻击者藏在DNS里的内容。由于TXT记录本身只是一种数据存储,DNS服务器并不关心内容含义,所以它既能存正常文本,也能存完全被Base64编码后的命令。
这里有一个容易踩的坑:用 Resolve-DnsName 返回的TXT记录往往带着两端的引号,实际写脚本解析时要用 Trim('"') 去掉,否则后续Base64解码会多出两个字符报错。
2.2 攻击者常用的编码与混淆手法
单纯把命令放TXT里显然太显眼,所以攻击者会先做几层处理:
- Base64编码:最基础却最实用,PowerShell原生支持从Base64还原字节;
- ASCII转进制:把每个字符转成十六进制或八进制再拼接;
- 反转字符串:执行时再反转回来;
- 变量拼接:把一条长命令拆成多段变量,运行时拼接再调用;
- 减少特征词:用
-e短参数替代-EncodedCommand,用-nop替代-NoProfile。
例如一段命令可能长这样:
powershell -nop -w hidden -e <Base64编码内容>这里的-e后面跟的就是Base64编码的脚本。这类命令最容易被杀软拦截,但攻击者会再套一层“动态拼接”来降低检测概率,比如用$a='IEX'+'(...)'的方式延迟关键特征的暴露。
我在实际分析中也见过更“讲究”的:攻击者把字符串拆成多个单字符变量,通过[char]方式还原,这样即使杀软扫描TXT记录内容,也看不出任何明显的恶意函数名。
2.3 解码与静态分析方法
拿到一个疑似恶意TXT负载,我习惯按三步走。
第一步,先看原始字符串。在隔离分析机中执行Resolve-DnsName查询,把返回内容保存到文本文件里,不要把内容直接丢进PowerShell执行。
第二步,判断编码类型。先尝试Base64还原,用PowerShell做一个无害演示:
$encoded = "Q2xpY2tGaXggRXhhbXBsZQ==" [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($encoded))执行后输出ClickFix Example,说明还原成功。如果输出乱码,常见原因是原始内容不是UTF8编码,需要换成ASCII或Unicode再试。这里顺便提醒一句,日常排查PowerShell文件乱码问题,也通常是编码没选对,用VS Code把文件转成带BOM的UTF-8或系统默认编码,基本都能解决。
第三步,阅读还原后的内容。正常的第二阶段脚本通常包含下载器逻辑、持久化写入、反弹连接其中至少一种。看到IEX、DownloadString、FromBase64String、Start-Process这些词,基本可以确认是恶意行为。
2.4 为什么这类载荷能绕过常规检测
把攻击链串起来看,这套方案最聪明的地方在于“不落盘不落地”。恶意脚本从TXT记录里被拉取后,直接在PowerShell进程的内存中解码执行,文件系统上全程没有exe或dll出现。传统的文件扫描引擎完全看不到攻击活动;HTTP流量检测器如果不看DNS流量,也拿不到证据;就算用户复制命令到运行框那一刻被抓到,如果安全软件只关注“下载文件”而不关注“执行命令”,依然会漏。
另外,攻击者还会故意使用-ExecutionPolicy Bypass这类参数,在命令行层面绕过Windows默认的PowerShell执行策略。一旦进入内存执行环节,AMSI(反恶意软件扫描接口)是少数能在脚本执行前拦一把的机制,但攻击者也会尝试通过混淆和内存patch绕过AMSI。这也是为什么这类攻击需要从进程、网络、日志多个层面联动检测。
3. 检测与取证:在真实环境中揪出Click Fix攻击
看完了攻击原理,接下来讲排查。真实环境里我不会一上来就跑扫描器,而是先建立时间线和进程线索。
3.1 终端侧:从进程与日志找蛛丝马迹
Windows的事件日志是第一个要看的地方。重点关注三处:
- 安全日志4688(进程创建):记录命令行的进程信息,前提是开启了命令行审计;
- PowerShell日志4104(脚本块日志):PowerShell会把被执行的脚本块内容记录下来;
- Sysmon事件1(进程创建)和事件22(DNS查询):如果部署了Sysmon,可以直接看到进程与DNS查询的对应关系。
如果你需要手动看可疑进程,PowerShell里最常用的是:
Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match 'PowerShell' }输出里的命令行字段就是判断关键凭据。如果发现某个由explorer或cmd启动的PowerShell进程带着-nop -w hidden -e这串参数,基本上可以断定是恶意。如果怀疑有隐藏脚本文件,可以再配合:
Get-ChildItem -Path C:\Users\xxx -Recurse -Filter *.ps1 -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 20按修改时间倒序翻一遍,往往能发现刚落地还没被清理的恶意脚本。
3.2 网络侧:DNS TXT查询异常的特征
在DNS服务器或内网出口设备上,可以关注这类查询:
- 大量TXT记录查询,且查询域名与业务无关;
- 一个域名突然出现多条TXT记录;
- TXT记录的内容经过Base64编码,出现类似
==结尾的字符串; - 查询行为集中在某个终端,与该终端上进程启动时间吻合。
这类特征单看一条可能不明显,但结合终端侧的PowerShell启动事件,往往能快速锁定问题机器。
3.3 浏览器与剪贴板取证
如果用户还能回忆起访问的网址,去浏览器历史里找回页面是最直接的思路。伪造页面的前端通常有一段JavaScript,用来生成要复制的命令。在浏览器的缓存或开发者工具中可以看到原始命令内容。
这里有个实操禁忌:不要在受害者的正常工作机上直接复制粘贴未知命令到PowerShell里,哪怕只是为了“看看内容”。正确做法是把命令写入文本文件,在隔离分析机或沙箱里打开。
3.4 快速判断一段命令是否恶意的几个特征
给一个快速排查清单:
- 参数包含
-EncodedCommand或-e; - 命令中混有
FromBase64String、IEX、DownloadString; - 使用
-WindowStyle Hidden隐藏窗口; - 结合
-NoProfile或-nop跳过配置文件加载; - 命令内容本身不是完整逻辑,只是拉取远程内容。
达到其中两三条,就需要按应急事件处理。
4. 防御与处置:从用户习惯到企业级管控
4.1 用户意识:别让“修复”变成攻击入口
说句扎心的话,这套攻击最大的漏洞不是系统,而是“用户那一刻的默认信任”。页面说“请复制并运行”,用户很少会质疑。所以要反复强调一个常识:任何正规系统都不会让你按Win+R、粘一段代码来“修复浏览器”或“完成验证”。
对个人用户,我的建议是:看到这类提示,先关页面,换个官方渠道核实;如果已经复制了命令,宁可多花两分钟发给身边懂行的人看一眼,也别直接运行。对安全团队来说,结合钓鱼演练和短小的即时提示,会让员工形成条件反射:凡是让复制代码到运行框的,一律视为攻击。
4.2 主机加固:AMSI、AppLocker与受限语言模式
终端侧的防御不是靠装一个杀软就完事,需要做组合:
- 确保AMSI工作正常:Windows Defender开启实时保护后会为PowerShell提供AMSI扫描,日志记录也可以通过PowerShell 5.0+的事件通道查看;
- 用AppLocker或WDAC限制PowerShell可执行范围:只允许管理员或特定程序调用PowerShell;
- 启用PowerShell受限语言模式:对部分行业用户,可以设置
$ExecutionContext.SessionState.LanguageMode为ConstrainedLanguage,限制脚本中的危险性调用; - 关闭不必要的PowerShell远程管理端口、限制WinRM访问。
这里有另一个值得注意的点:攻击者为了“解除PowerShell限制”,会尝试用-ExecutionPolicy Bypass绕过执行策略。要真正防住,不能只靠执行策略,还需要AppLocker、AMSI和日志审计配合。
4.3 网络层防护:对DNS TXT异常查询的监测
网络侧的核心是“给DNS流量加一双眼睛”。常见做法包括:
- 在内网DNS上开启查询日志,重点记录TXT类型查询;
- 用SIEM把DNS日志和终端进程日志做关联分析;
- 对已知恶意域名引入威胁情报,查询命中即告警;
- 防火墙或DNS安全设备对异常TXT响应内容做解码预检。
DNS流量量大,刚开始做告警时会有大量误报。我的经验是先拿“TXT查询 + PowerShell进程启动 + 外连HTTP子域名”三个条件做组合告警,准确率会明显提升。
4.4 应急处置:发现中毒后的应对流程
如果已经确认有终端被Click Fix打入,按这个流程走:
- 先把机器断网,阻止继续外连,但不要关机,避免丢失内存线索;
- 采集证据:进程列表、PowerShell日志、DNS查询日志、浏览器历史、启动项;
- 查持久化:Run注册表键、启动文件夹、计划任务、WMI事件订阅;
- 清理恶意项,修改相关账号密码,检查是否有横向移动;
- 在不破坏证据的前提下更新防病毒定义,全盘扫描;
- 观察24小时,确认无反弹连接后恢复正常使用。
整个处置过程,最忌讳的是急着重装系统。重装虽然能清除恶意软件,但会丢掉攻击入口和攻击手法的证据,安全团队很难再做复盘和溯源。
5. 实战中踩过的坑与排查心得
最后这部分,把实际排查中经常遇到的问题整理成速查表,再加上几条经验之谈。
5.1 常见问题速查表
| 问题 | 常见原因 | 解决办法 |
|---|---|---|
| 解码Base64后出现乱码 | 源内容不是UTF8编码 | 依次尝试UTF8、ASCII、Unicode,检查是否混入多余引号 |
| 查询TXT记录返回空 | 域名不存在TXT记录,或解析服务器缓存了旧记录 | 换公共DNS或指定权威DNS服务器再查 |
| PowerShell执行策略显示受限 | 组策略覆盖了注册表设置 | 检查本地组策略,不要轻易用Bypass全覆盖 |
| 杀毒软件没有报警但行为异常 | 恶意载荷只存在于内存,文件扫描失效 | 收集内存镜像和PowerShell脚本块日志分析 |
| 清除启动项后仍然外连 | 存在计划任务或WMI事件订阅持久化 | 用Get-ScheduledTask和WMI查询完整检查 |
| 找不到攻击来源页面 | 用户无法回忆网址,缓存被清 | 查浏览器历史、DNS解析日志和代理访问日志 |
5.2 几条实战排查心得
第一,永远在隔离环境里复现。用一台干净的虚拟机去模拟查询TXT记录和解码过程,不要在受害机上反复尝试。你永远不知道哪一步会把残留的恶意逻辑再次触发。
第二,先把时间线图画明白。用户说“我没打开奇怪网站”,但日志可能显示3分钟前有PowerShell启动和TXT查询记录。以日志为准,以时间线为导向,排查效率会高很多。
第三,注意观察“最像正常”的异常。有一次我排查到某台机器持续外连,启动项和计划任务都很干净,最后发现攻击者在一个看似正常服务名的计划任务里用了隐藏参数。很多时候恶意行为和正常系统管理行为只有一两个参数之差,多问一句“这个任务是谁建的、什么时候建的”就能找出线索。
第四,不要小看日志保留周期。PowerShell脚本块日志默认可能有大小限制,DNS日志也经常因为磁盘配额被截断。提前把日志转到集中采集平台,比事后补救重要得多。
说实话,Click Fix这类攻击并不需要多高深的技术,真正难防的是“让用户在某个瞬间失去警惕”这件事。我在实际排查中见过太多类似场景:用户很谨慎,却恰好在非常疲惫或着急时点了那一下。所以我的建议一直很朴素——把“不要随意复制粘贴命令到运行框”当成和“不点陌生链接”一样的基本习惯。对安全团队来说,真正有效的不是某一款神器,而是把DNS查询审计、PowerShell日志、进程监控这几件事持续做下去。哪怕只是一个简单的TXT记录查询,在平时是噪音,在关键时间点就是抓住攻击者的那根线。别怕麻烦,这些基础工作,最后都会在应急响应时救你一次。