最近在研究APT攻击,我选择研究APT的方法通过一个APT组织入手,我选择的是APT28这个组织,APT28组织是一个与俄罗斯政府组织的高级攻击团伙,我将分析该组织的攻击样本、攻击方法、攻击目的来研究一个APT组织。本次分析的是该团伙使用的CVE-2015-1641漏洞样本,所有资料均来自互联网。
本次分析的样本来自unit42披露的针对美国政府发送的鱼叉钓鱼攻击,此次攻击的社会工程学包括:
1 攻击邮件的发件人使用真实另一个国家外交部的电子邮件,推测,该外交部的主机或账号遭到入侵。
2 邮件主题跟名称都是关于美国和格鲁吉亚之间联合北约培训工作。
此次分析的样本一共如下:
文件名称 Exercise_Noble_Partner_16.rtf
SHA-256 03cb76bdc619fac422d2b954adfa511e7ecabc106adce804b1834581b5913bca
创建时间 2016-05-20 18:50:00
文件大小 0.98M

漏洞原理分析

两个文件都是rtf文件,我们使用oletools分析其中一个文件,并使用-s all 参数保存这些OLE文件,可以看到共三个OLE文件,我们重点分析下这三个文件


我们分析这3个文件,发现在打开id=2的文件的时候,出现了crash,我们重点关注下这个文件,我们发现程序在读取ecx的时候发现了错误


分析发现这块地址并未分配,而ecx 7c38bd50是从什么地方来的


进行栈回溯


进行解压,并查看里面的文件,从document.xml文件中,发现smartTag标签中出现了0x7c38BD50,跟Ecx里面的值一样,导致Crash,可以猜测道ecx里面的值来自smart标签的element属性。


我们来说一下这个漏洞的原理,该漏洞是由于wwlib.dll模块在处理标签内容时存在类型混淆漏洞,windbg具体跟下来看下漏洞的具体位置,通过栈回溯函数,发现了其中的XML解析函数,具体看下msxml6!Reader::ParseElementN,微软给了符号函数


我们看到Reader::ParseElementN函数肯定会调用GetTokenValueQName 函数


这个函数是获取标签名,fortinet下的断点是这样的
bp msxml6!Reader::ParseElementN+0x6a “.echo Parsing XML tag:;r $t0=ebp-20;dc @@c++(((StringPtr)@$t0)->pwh) l@@c++(((StringPtr)@$t0)->n/2); gc”


下断点,发现在crash之前解析的标签smartTag跟子标签moveFromRangeStart、
MoveFromRangeEnd,进一步印证我们上面的猜测


可以发现最后解析的两个标签moveFromRangeStart、moveFromRangeEnd都含有displacedByCustomXml 这个字段主要意思是当前标签处需要被一个customXML中的内容替代


首先断到漏洞相关函数,相关断点如下
wwlib!DllGetClassObject+0x424d ".if(ecx =0x7c38bd50){}.else{gc}",重点关注参数
eax里面存储的为 smart 标签中的element 属性0x7c38bd50,esi表示标签层级
[ebp+Src]里面存储的id值 0xffffe696


通过查看栈帧往上查看v18指向smartTag对象,*(v18+4) 为 smart 标签中的element 属性0x7c38bd50,src里面为moveFromRangeStart的id值,但是此流程传入的不应该是smartTag对象,而应该是costomXml标签,而由于使用了displacedByCustomXml属性,导致这里类型混淆,本来会被上一个或者下一个customXml标签代替


由于此流程不是处理smartTag对象,会导致传入element属性值会被当做一个地址传入,并计算出一个地址,最后将moveFromRangeStart的id拷贝到这个地址,就会造成任意地址写


看一下calc_addr函数,正常的计算公式为
TagList基址+HeadSize+TagObjectSize*CurrIndex
首先看一下TagList结构体
TagList{
DWORD current_index; 当前标签层级
DWORD ? ; 未知
DWORD TagObjecSize; TagObjec大小
DWORD headsize; head大小
}


而传入element属性(0x7c38bd50)被误认为Taglist基址,并计算出来为0x7c38bd74,并传入拷贝函数将moveFromRangeStart的id拷贝到这个地址。


这个地址是MSVCR71这个模块,然后这个模块开始是并没有的,漏洞利用者通过嵌入ProgID为 otkloader.WRAssembly.1的对象来加载OTKLOADR.DLL的模块来引入MSVCR71模块来绕过ASLR保护


执行后,可以看到7c38bd74已经被覆盖为ffffe696


通过样本可以看到一共进行了4轮拷贝,第二轮传入的假的Taglist基址为0x7c38bd68,而这次正好用到了第一次拷贝的值,计算为
0x7c38bd68+ffffe696+6*7=0x7c38a428


此地址原来存的为kernel32!FlsGetValueStub函数的地址


这次写入的值为0x7c376fc3


我们看到覆盖后的地址也是一串代码,这样在执行到0x7c38a428地址kernel32!FlsGetValueStub函数的时候,将执行这段代码


继续看后面覆盖的代码


第三次覆盖,为第四做铺垫


第四次通过计算将 0b800aa0 写入到7c38a430中


这次断到劫持的函数kernel32!FlsGetValueStub也就是0x7c38a428,发现ecx跟栈中都有之前写入0b800aa0


通过栈回溯,发现通过之前写入的地址读取了写入的值

分析堆喷与shellcode

首先分析下,esp返回的精心构造的地址为0b800aa0,看下这个地址


进行查看可以看到样本进行堆喷的地址


查看rtf文件中的ole文件,找到activeX进行堆喷的地方,将activeX2堆喷到进程空间中


我们分析的ROP链,如下所示


ROP主要使用函数
kernel32!VirtualAlloc:使用此函数声明0x0b800ae0这段内存可执行,来绕过DEP


之后跳转之后,就是shellcode了
Shellcode主要功能,通过解密出一个DLL文件


该DLL文件的主要作用,首先获取3个资源


一个是PE文件


一个RTF文件


是一段shellcode


之后开辟一段内存,并分别将shellcode跟pe文件拷贝到这段内存中


最后执行shellcode,shellcode主要是建立下面PE文件导入表等等的初始化工作


然后执行从资源文件中取出的PE文件,该文件主要是先创建两个DLL文件
C:\ProgramData\svchost.dll
C:\Users\sunqiang\AppData\Roaming\btecache.dll


最后在一个有趣的注册表
HKEY_CURRENT_USER\Software\Microsoft\Office test\Special\Perf键值


这个键值下是释放的DLL
C:\Users\sunqiang\AppData\Roaming\btecache.dll,这个不会随着开机启动,而是每次打开office程序时候,会加载这个DLL,实现木马的持久化


在测试中,资源中的rtf文件没有处理直接停止了进程

参考文章

点击收藏 | 0 关注 | 2
  • 动动手指,沙发就是你的了!
登录 后跟帖