写点什么

IE 安全系列:脚本先锋(2)

  • 2015-07-29
  • 本文字数:5286 字

    阅读完需:约 17 分钟

声明:为了更好地向读者输出更优质的内容,InfoQ 将精选来自国内外的优秀文章,经过整理审校后,发布到网站。本篇文章作者为乌云白帽子 blast,原文链接。本文是《IE 安全系列》第四篇,已由乌云网授权InfoQ 中文站转载。欢迎转发,但请保留原作者信息!


作者 blast

正文

接着上一篇的来,本文多为JavaScript 的脚本阅读和解释,阅读都是自行完成,所以不免可能会出现一些错误或者联想过度的情况,如果你发现了哪儿有问题请重重地拍出来。

1、HTML 与网马攻击 4 — Virus In the Wild

本篇中我们将从真实的 Exploit Kit 的利用代码入手介绍分析方式,文中例子采用 Angler Exploit Kit 和 Magnitude Exploit Kit(下简称为 AEK 和 MEK)在 2015 年 4 月初最新的代码。

AEK 和 MEK 是互联网上最著名的漏洞利用工具包,在 Phoenix Exploit Kit 作者锒铛入狱之后,这两个 Exploit Kit 的“市场份额”一下子窜到了前面,因为作者更新快,采用加密方式繁多,导致杀毒软件更新特征也较为困难,这让它们有充足的机会去攻击有漏洞的电脑。本文将介绍这两个 Exploit Kit 的加密方式和解密方法。

首先,让我们从 AEK 开始,AEK 和 MEK 都需要有一个 Landing Page,用于将用户定向到恶意页面上,打开 Landing Page,我们会发现 AEK 为了做混淆,给 Landing Page 加了很多无用的垃圾数据,并将加密后的数据混淆插入在这些代码中:

(点击放大图像)

图:code 部分是加密后的代码

将页面向下拖动,快到最后的地方就是它的解密脚本了:

图:AEK 的脚本

是的,这就是一个高度混淆后的脚本,因为JavaScript 代码(或者说类C 语言语法)的宽松性,作者在这里面使用了大量的空白、回车、缩进符,同时还替换了变量名,使用大量的数学函数来做混淆。

对于人来说,要阅读这样的代码简直是一个非常恶心的工作,所以在此推荐使用一些代码规范化工具,例如Malzilla 提供的JS 标准化,或者这里还有一个小技巧:使用Notepad++ 或者类似工具的括号匹配功能:

将光标移动到function 的大括号处,此类软件会自动标示出函数范围,可见上图中该函数范围是LN268-LN385。这样,我们就能清晰的知道这个代码的结构了:

而之前我们也说过,Function 除外的Global 代码,会从上往下执行,因此,攻击者如果想要实现读取- 解密- 执行的步骤,执行必然是最后一步,因此我们只需要在它执行之前将要执行的数据找到即可。

翻到最后,可以发现LN568-574 的Script 段其实和上面LN558-565 几乎一样。这意味着这段代码很可能包含着解密和执行两步的内容。

从最后一句入手,

LN564:

复制代码
rqNNhndhLxLVVb[nmfAbWwoA]('TQgaaGLDVYlaQT',QXuSacI)

逐个查看变量的作用,

LN267 表明:

复制代码
rqNNhndhLxLVVb = window;

这是因为 JavaScript 中允许将任何对象赋值给某个变量,因此 rqNNhndhLxLVVb 此时实际上可以看作是 window 的“别名”或者“同义词”。

看看第二个变量 nmfAbWwoA 的来源:

LN561 可以发现是该变量的第一次使用的地方:

复制代码
nmfAbWwoA = "ezVI"+"Migbc".substr(6,8) //ezVI
nmfAbWwoA = nmfAbWwoA+[].join(dLpy) + "xlyG"

变量 dLpy 经过阅读可知在:

LN437 处赋值:

复制代码
dLpy= ('EoVzQHTfRyGU').substr(12,12) //””

因此 nmfAbWwoA 的值实际上只是“ezVIxlyG”。

第三个变量: LN558 可以发现是该变量第一次赋值的地方:

复制代码
var QXuSacI;
QXuSacI= ['Y', 'r', 'a', 'd', 'P'].join(dLpy)

由于 dLpy 我们已经知道是空字符了,所以实际上 QXuSacI 的值就是”Yradp”。

这样,将三处组合,LN564 的原始语句实际上是:

复制代码
window[”ezVIxlyG”]('TQgaaGLDVYlaQT', ‘Yradp’);

这个 ezVIxlyG 的原型是什么呢?搜索代码,找到它的赋值点:

LN438:

复制代码
var D1Kx;
ezVIxlyG= !!D1Kx?true:( function (){ ……} );

这里有一个约定俗成的内容,可以看到 D1Kx 是刚刚定义而且未赋值的,将其作为布尔型来处理时,其默认值是 false,因此,!!D1Kx 的值实际也是 false。

这样该三目表达式实际上只是相当于一个普通的赋值:

复制代码
ezVIxlyG = function(){……}

由于此时我们还没处理该函数,因此这个混淆后的代码应该是十分难读的,所以,我们对其进行一个简单的处理: 复制 LN439-545

  • 替换所有双空格、三空格 -> 单空格,直到没有 2 个以上连续空格为止。
  • \n、\r 全部删除
  • 使用工具将代码重新格式化。

完成后,代码如下所示:

(点击放大图像)

可见代码还是难以理解,这是因为其中包含了大量的变量:

你可以看到这个地方定义的变量大部分都会分散地被之后的代码使用到。

所以我们要关注的还是函数的最后:

复制代码
if(flag == 1)
{
rqNNhndhLxLVVb [YPub] ( UjcS )
}
else
{
rqNNhndhLxLVVb [YPub] ( UjcS )
}

这里又是一个无用分支,rqNNhndhLxLVVb 我们已经知道是 window 对象了,YPub 是什么呢,可以看看上面的代码,最好倒着看,我的注也是从 5 开始倒着写到 1 处的,请注意:

复制代码
YPub=tP+yMwnso (注:eval)
tP= 'e' 、 yMwnso= ('Rv'+('uapt') ['re'+'place'] ( 'u', dLpy)) [iCQl0] ( K1DMU, 2 ) +'l' (注:val)
iCQl0= (wRxKW+'snubnstrn') [F9k2c] ( /n/g , qm3sXy) (注:substr)
F9k2c=qm3sXy+'r'+ yMwnso + 'pl' + qm3sXy + 'ac' +yMwnso (注:replace)
K1DMU=3-2

因此我们看到了这句实际上是:

复制代码
window[”eval”](UjcS);

现在知道做什么了吗?对,先把 eval 换成 alert!

然后,直接运行该 HTML,得到解密后数据:

(点击放大图像)

等等,共4 次,将这些内容合起来就是解密后的代码了。可以看到这个代码利用了多个新漏洞,甚至包括卡巴斯基控件的安全漏洞。

2、HTML 与网马攻击 5 - Virus In The Wild

让我们再看看 Magnitude Exploit Kit 这款 EK 的代码,相比 AEK 而言,难度是高还是低。

(点击放大图像)

图:MEK 的Landing Page

可以看出来,相比而言它的代码貌似要简单得多,可以清晰的看到document 和eval 被分别赋予了两个不同的变量。

通过将eval 修改为alert,执行后得到:

完了?显然没有,将eval 换成alert 之后得到的数据是一个function,而点击确定之后,得到了一个脚本错误:

图:脚本错误

仔细阅读一下,首先,这个eval 的范围是:

(点击放大图像)

在它之后出现了一个从未见到过的函数:

(点击放大图像)

而对比我们之前弹出的alert 可以发现,这个函数就是eval 解出来的结果,因此,我们应该做的是把eval 部分换成解密后的内容:

复制代码
function t1g6(a,b){var inn =
document.getElementById('avp6').innerText;var out='';var
c=inn.split('*');for(var k=a;k<b;k++) out +=
String.fromCharCode(c[k]-21);return out;}

用上述内容替换掉 eval 块,得到:

(点击放大图像)

但是之后显然没有eval 了,这时,其实我们只需要了解document[”XXX”] 将返回document 下的XXX 对象,这个对象是可以作为函数来调用的(或者不如说函数就是一个对象:) )就可以了:

(点击放大图像)

因此后面的c1h82by0(document)就显得很是危险,所以让我们看看s4tb[0] 的内容并注释掉后面的内容,记得之前说的嘛?一个script 块中的代码一直到出错为止都是可以正常运行的,所以不用管之后的代码会不会出错了,主要是后面的代码很可能是恶意代码,不能让恶意代码在我们自己的电脑上跑起来。

图:执行结果

因此,可以知道这里是在做document[“createElement”] 这个操作,司马昭之心,路人皆知,再将其内容改为alert(s4tb1),执行可得:

图:执行结果

串上后面的内容可以知道,这段代码事实上正在创建一个iframe,其src 执行漏洞代码页面: hXXp://bf29df.e66.83.1c.3d8a.54.1393d.bc7dc6b.6.scg512374t1.changesmoves.in/47b1d0b4466375c9306821f48abcd6b5(放心,此时这个网站已经无法访问了。)

至此,这个页面的核心内容我们已经全部了解了,至于后面的几个变量,解法也是一样的,如果想要练手的话,可以试着将页面内容全部还原成无混淆状态试试看。页面内容见附件(密码drops.wooyun.org )。

3、HTML 与网马攻击 6- 利用 arguments.callee 实现“递归解密”的网马以及解密

希腊神话中有一条名为 Ouroboros 的蛇,它咬着自己的尾巴,它的姿态象征着“不死”、“完全、“无限”、“世界”、“睿智”等种种意味。

图:乌洛波洛斯,网络图

在编程中,称作递归,递归在 JavaScript 中可以像 C 的代码一样来调用:

复制代码
function a(){ a();}

不仅如此,JavaScript 还支持一种 arguments.callee 的方式来调用。callee 为对当前函数的引用,故可以作为类似递归的方式来调用自身。

不过,递归还是需要谨慎的,稍有不慎,一个 bug 即可导致整个程序出现不可知的情况。

图:IE10 递归导致死循环,栈空间全部用完导致崩溃

言归正传,先让我们看两个例子大致理解一下普通递归和 arguments.callee:

以下两个例子输出均为:1 2 3。

普通递归,

复制代码
function mylog(current, max)
{
if(current <= max)
{
console.log(current);
add(current+1, max);
}
}
mylog(1,3);

以及 arguments.callee:

function f(x)
{
console.log(x);
return arguments.callee;
}
f(1)(2)(3);

从实际入手吧,请参考如下网马的例子:

(点击放大图像)

是否第一眼就看到了倒数第二行出现了

eval(I3qVh4gPT);

如果你试图将它改为 alert(I3qVh4gPT);,那么这个函数的解密结果必然会失败:

(点击放大图像)

原因是什么呢?请看第一行出现了。

复制代码
v ar
eJmF3VT3H=arguments.callee.toString().replace(/\W/g,'').toUpperCase();

我们知道 arguments.callee 是对当前函数的引用,那么这个引用转为字符串是什么呢?让我们测试一下:

原来就是返回了当前函数。

仔细一看,这里会把函数自己当成参数来解密。

所以,如果我们想要解开这个脚本的加密应该怎么弄呢?

A、简单阅读代码

从最后来,

①eval(I3qVh4gPT); 引用了变量 I3qVh4gPT。

②I3qVh4gPT+=String.fromCharCode(EHxDfdAM5); 引用了变量 EHxDfdAM5。

③EHxDfdAM5=e3FP5e1M6-IA17ef3d3[bqjtxUvBR];if(EHxDfdAM5<0) {EHxDfdAM5=EHxDfdAM5+256;} 引用了变量 e3FP5e1M6、IA17ef3d3[0]。

④e3FP5e1M6=parseInt(EWX1TnOBq,16); 引用了变量 EWX1TnOBq,将其作为十六进制解析。

⑤var EWX1TnOBq=mXSYkqH0X.substr(PwgNCEKQL,2); 中,mXSYkqH0X 是参数,PwgNCEKQL 是计数器。

⑥for(PwgNCEKQL=0;PwgNCEKQL

⑦Oq32NWn5D=mXSYkqH0X.length; ,也即参数的长度,因此,这段代码在解密传入的参数。

还有,③中出现了另一个变量 IA17ef3d3,这个变量出现在⑧IA17ef3d3[PwgNCEKQL]=fgMN0vK2r.charCodeAt(va31p5um0);,这之中还引用了 fgMN0vK2r、va31p5um0 两个变量

⑨fgMN0vK2r=RsIkkqdYi[(fgMN0vK2r^eJmF3VT3H.charCodeAt(gMKy026SO))&255]^((fgMN0vK2r>>8)&16777215); 中出现了 fgMN0vK2r。RsIkkqdYi 是一个预设密钥组,eJmF3VT3H 是当前函数(arguments.callee.toString() 等处理后的结果),gMKy026SO 是计数器。因此这句是在基于一个密钥组产生一个密钥组;

⑩for(PwgNCEKQL=0;PwgNCEKQL<8;PwgNCEKQL++) {var va31p5um0=Oq32NWn5D+PwgNCEKQL;xy3D07u0l[PwgNCEKQL]=1;xy3D07u0l[PwgNCEKQL]=FSB4JaYie;if (va31p5um0>=8) {va31p5um0=va31p5um0-8;IA17ef3d3[PwgNCEKQL]=fgMN0vK2r.charCodeAt(va31p5um0);} 同样,va31p5um0 也在参与解密。

也即,将传入参数每隔 2 个字符作为一个 HEX,然后解出来,与将函数自身的字符串通过解密算法解出来的数据相减,两者结果小于 0 的话,加上 256,最终对所有字符都如此操作,将结果连接起来得到解密数据。

既然函数本身不能轻易修改,那么只好从最终的 eval 做突破了,JavaScript 中允许“劫持”一个对象。即和操作普通变量的赋值一样,函数也是可以通过赋值来覆盖的,请看第二部分。

B、函数劫持

(点击放大图像)

针对这个代码,因为最终它会通过eval 来运行恶意代码,所以添加eval=alert,在运行到eval 之前将其劫持即可。

运行代码可以得到:

(点击放大图像)

最后,总结一下,在 Jscript9.dll 中,脚本的函数中调用 arguments.callee.toString() 时,大致经历了如下几个步骤:

  • 解析脚本文字(ScriptSite::ParseScriptText);
  • 送与解析内核,生成字节码,通过字节码解释器(即 Intepreter)来执行;
  • 在处理到 arguments.callee.toString() 时,jscript 会将函数自身 marshal 成 BSTR,然后转换成 JsVar,传递给后续要使用它的代码。

题外话,这个代码其实是 2010 年发现的一个广告软件(是当时流行的 Rogue antivirus,也就是伪装成杀毒软件的广告程序)安装页的 Landing Page,当时我还特地上论坛和大家讨论了怎么解决,大家给出的思路也相当多,除了上述我说的方法之外,一些自动化解密工具也可以处理此类网马,例如 Malzilla 。不过建议大家不要过于依赖工具,而是把工具当作可以简化重复劳动的工具是最好。

到此为止,脚本先锋系列的解密部分就告一段落了,下一篇开始,将简单的介绍调试器的用法以及如何对网马中使用的 Shellcode 进行调试,其中也包括简单的对恶意 SWF、PDF 的分析的内容。

参考资料

  1. 文中恶意脚本打包下载,请在虚拟环境下测试与调试(密码 drops.wooyun.org )

感谢魏星对本文的策划和审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015-07-29 06:592060

评论

发布
暂无评论
发现更多内容

盘点分布式软总线数据传输技术中的黑科技|HDC2021技术分论坛

HarmonyOS开发者

HarmonyOS

前端开发环境搭建在内网是如何搭建的

@零度

大前端

50强诞生!2021 OceanBase 数据库大赛百所高校争霸!

OceanBase 数据库

数据库 开源 开发者 比赛 oceanbase

《新程序员》走进微软亚洲研究院

刘旭东

微软 hololens

淘宝客户端安全生产体系建设

阿里巴巴终端技术

ios android 淘宝 客户端 安全生产

鸿蒙轻内核源码分析:虚实映射

华为云开发者联盟

鸿蒙 虚拟内存 物理内存 页表 虚实映射

安全架构|云安全框架及虚拟化技术

明亮安全观

云计算 网络安全 云安全 安全架构

Java开发之集成开发环境

@零度

JAVA开发 Java学习 IED

HBase 调优详细剖析

五分钟学大数据

11月日更

拿捏这10点,玩转云原生应用

BeeWorks

面试官问:mysql中时间日期类型和字符串类型的选择

华为云开发者联盟

MySQL timestamp 时间日期 字符串类型

鸿蒙智联生态服务平台——智能硬件伙伴的最佳拍档|HDC2021技术分论坛

HarmonyOS开发者

HarmonyOS

质量基础设施“一站式”服务信息平台建设,NQI一站式线上搭建

电微13828808271

Hadoop企业级生产调优手册(一)

大数据技术指南

11月日更

连续 14 年!IBM 荣获 2021 年 Gartner 主存储魔力象限领导者

BeeWorks

自动驾驶汽车的安全架构体系 易筋 ARTS 打卡 Week 77

John(易筋)

ARTS 打卡计划

阿里一面灵魂一问:RPC或者HTTP什么时候需要序列化和反序列化?

热爱java的分享家

Java 架构 程序人生 编程语言 经验分享

【Pandas学习笔记02】处理数据实用操作

恒生LIGHT云社区

Python 数据分析 pandas

北京朝阳区有正规等保测评公司吗?联系电话多少?

行云管家

网络安全 等保测评 朝阳区

大会回顾丨游戏用户体验优化如何实践,看大咖怎么说(附PPT下载)

WeTest

Remix.run 新手教程

程序员铮铮

JavaScript 大前端 React SSR 教程分享

Linux一学就会之Linux详细基本命令操作

学神来啦

bash Linux centos 运维 Shell

记一次拿到后台权限的过程

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 安全漏洞

还有人不知道鸿蒙智联设备认证咋搞?|HDC2021技术分论坛

HarmonyOS开发者

HarmonyOS

35岁程序员创业,为何选择云原生赛道

行云创新

云计算 创业 程序员 云原生 CEO

Linux学习方法,《Linux一学就会》教你如何学习Linux

侠盗安全

Linux 运维 linux运维 云计算架构师 linux电子书

Java 项目中使用 Resilience4j 框架实现故障隔离

码语者

Java Resilience4j Bulkhead 故障隔离

这才是Springboot事务创建流程的正确打开方式(附源码分析!)

热爱java的分享家

Java 架构 程序人生 编程语言 经验分享

3分钟教你如何在github上精确的找开源项目?

热爱java的分享家

Java 架构 程序人生 编程语言 经验分享

大数据开发之如何用Scala进行spark开发

@零度

scala 大数据 spark

智能楼宇管理系统开发,智慧楼宇管控系统开发

电微13828808271

IE安全系列:脚本先锋(2)_安全_blast_InfoQ精选文章