做过不少ctf中的pwn,但还是头一次复现windows的溢出漏洞。
目的有二:
- 第一:学会使用windbg,了解它的适用情况和优势。
- 第二:体验在windows下调试溢出漏洞,看看和linux下调试有何不同。
#0x01 漏洞背景
2017.11.14 微软发布11月补丁,修复了包括CVE-2017-11882在内的多个漏洞。 随后不久,安全公司EMBEDI在官方博客上公开了其向微软提交的编号为CVE-2017-11882的Office远程代码执行漏洞:https://embedi.com/blog/skeleton-closet-ms-office-vulnerability-you-didnt-know-about,讲述了漏洞的发现过程和部分细节。
漏洞出现在模块EQNEDT32.EXE中,该模块为公式编辑器,在Office的安装过程中被默认安装。该模块以OLE技术(Object Linking and Embedding,对象链接与嵌入)将公式嵌入在Office文档内。当插入和编辑数学公式时,EQNEDT32.EXE并不会被作为Office进程(如Word等)的子进程创建,而是以单独的进程形式存在。这就意味着对于WINWORD.EXE, EXCEL.EXE等Office进程的保护机制,无法阻止EQNEDT32.EXE这个进程被利用。
漏洞存在于EQNEDT32.EXE处理Office OLE Equation对象中标记为字体名称记录的字节流中,如果Equation对象中存在标记为字体名称的超长字节流,则程序在处理该字符串的过程,会由于判断字符串长度而发生栈溢出漏洞。
攻击者可以通过刻意构造的数据内容覆盖掉栈上的函数地址,从而劫持程序流程,可以利用漏洞以当前登录的用户的身份执行任意命令。而且该漏洞没有弹窗,用户感觉不到。
影响版本:
Office 365 Microsoft Office 2000 Microsoft Office 2003 Microsoft Office 2007 Service Pack 3 Microsoft Office 2010 Service Pack 2 Microsoft Office 2013 Service Pack 1 Microsoft Office 2016
#0x02 漏洞复现
复现环境:win7sp1+Microsoft office 2013
首先在github上找一个poc:https://github.com/embedi/CVE-2017-11882
在漏洞环境上运行成功弹出计算器。

通过Process Explorer查看进程情况,可以看到最终执行命令的父进程是EQNEDT32.EXE。

根据漏洞的描述可知,EQNEDT32.EXE是一个单独执行的进程。所以对它的调试相当于调试一个由进程创建的另一个进程。
大佬们早已给出了方法:https://www.52pojie.cn/thread-196194-1-1.html
在HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersioinImage File Execution Options下创建字段EQNEDT32.EXE。

下面创建一个名为debugger的字符串,值为windbg的路径。
由于触发结果是创建了进程打开cmd.exe。
所以可以在WinExec和CreateProcessw下断点。然后执行。

bp 下断点 bl 显示断点 g GO执行 bc [index]删除断点
程序中断后,观察栈里的返回地址和参数。

定位到代码里,是对winexec的调用。

再往上找:

继续跟进找到第一个call:

查看伪代码其伪代码:
int __cdecl sub_41160F(char *a1, char *a2, int a3)
{
int result; // eax@12
char v4; // [sp+Ch] [bp-88h]@5
char v5; // [sp+30h] [bp-64h]@4
__int16 v6; // [sp+51h] [bp-43h]@5
char *v7; // [sp+58h] [bp-3Ch]@7
int v8; // [sp+5Ch] [bp-38h]@1
__int16 v9; // [sp+60h] [bp-34h]@1
int v10; // [sp+64h] [bp-30h]@1
__int16 v11; // [sp+68h] [bp-2Ch]@1
char v12; // [sp+6Ch] [bp-28h]@1
int v13; // [sp+90h] [bp-4h]@1
LOWORD(v13) = -1;
LOWORD(v8) = -1;
v9 = strlen(a1);
strcpy(&v12, a1);
_strupr(&v12);
v11 = sub_420FA0();
LOWORD(v10) = 0;
while ( v11 > (signed __int16)v10 )
{
if ( sub_420FBB(v10, &v5) )
{
strcpy(&v4, &v5);
if ( v6 == 1 )
_strupr(&v4);
v7 = strstr(&v4, a1);
if ( v7 || (v7 = strstr(&v4, &v12)) != 0 )
{
if ( !a2 || !strstr(&v4, a2) )
{
if ( (signed __int16)strlen(&v5) == v9 )
{
strcpy((char *)a3, &v5);
return 1;
}
if ( v7 == &v4 )
LOWORD(v8) = v10;
else
LOWORD(v13) = v10;
}
}
}
LOWORD(v10) = v10 + 1;
}
if ( (signed __int16)v8 < 0 )
{
if ( (signed __int16)v13 < 0 )
{
result = 0;
}
else
{
sub_420FBB(v13, &v5);
strcpy((char *)a3, &v5);
result = 1;
}
}
else
{
sub_420FBB(v8, &v5);
strcpy((char *)a3, &v5);
result = 1;
}
return result;
}
可以看到在其对strcpy的处理中没有限制长度,复制位置在bp-0x28,如果a1长度超过0x28,就会覆盖接下来的ebp和返回地址。
查看其参数情况:


在执行完strcpy后,ebp-0x28的位置被修改。
而返回地址被修改为0x00430c12,就是执行winexec的地址:

所以可以对应到poc的关键位置。

修改payload:


打开新的poc文件,成功弹出notepad:

ps:获取shell的方法可以利用mshta,参考:https://blog.csdn.net/qq_27446553/article/details/78694488
#0x03 参考
- https://bbs.pediy.com/thread-247740.htm
- https://www.freebuf.com/vuls/154462.html