微软公式编辑器系列漏洞分析(一):CVE-2017-11882
0x00 简介
CVE-2017-11882为Office内存破坏漏洞。攻击者可以利用漏洞以当前登录的用户的身份执行任意命令。所影响的组件是Office 公式编辑器。需要注意的是这里是老版本的公式编辑器,微软在新版本的office中已经默认不使用了。不过,微软仍然保留老版本的公式编辑器,为了兼容。在编辑使用老版本的公式编辑器制作的公式时,才会使用老版本的公式编辑器。
0x01 漏洞分析
打开exploit.rtf
后直接弹出计算器,看到计算器是EQNEDT32.EXE
的子进程。判断漏洞出现在EQNEDT32.EXE
。
我们使用windbg
在kernel32!WinExec
下断点,断下来后看调用栈。
可以看到,此时kernel32!WinExec
的参数为cmd.exe /c calc.exe
就是PoC
触发后的WinExec
调用。接着,我们回溯调用栈。看看kernel32!WinExec
是哪个函数调用的。
继续向上回溯,看上一个函数
继续看0x004115a7
伪代码很简单,下个断点跟一下。在执行完sub_41160F
后计算器已经弹出,说明漏洞出现在sub_41160F
中。随后,我们在sub_41160F
下断点。
函数结束时即到达ret
指令时
发现返回地址已经被修改,变成了00430c12
,我们继续回看Exploit
。
这就是明显的栈溢出。
0x02 Exploit 分析
使用rtfobj.py
将OLE Data
导出来。
这里,Equation Native
的结构为Equation Native = Equation Stream Header + MTEF Header + MTEF Data
。
其中Equation Stream Header
的结构为
MTEF Header
的结构为
Description |
Size (byte) |
Value |
Comment |
---|---|---|---|
MTEF Version |
1 |
0x3 |
MTEFv3 |
Generating Platform |
1 |
0x3 |
Windows |
Generating Product |
1 |
0x1 |
Equation Editor |
Product Version |
1 |
0x3 |
|
Product Subversion |
1 |
0xa |
MTEF Data
的结构为
Description |
Size (byte) |
Value |
Comment |
---|---|---|---|
Tag |
1 |
0x8 |
0x8 denotes Font record |
Typeface Number |
1 |
0x5a |
|
Style |
1 |
0x5a |
|
Font Name |
Variable, NULL terminated |
“cmd.exe /c calc.exe AAAAAAAAAAAAAAAAAAAAAAAA” + 0x00430c12 |
到这里,问题就很明显了。原因就是在于在处理字体名称的时候,没有做长度判断。导致使用strcpy
拷贝字体名称导致栈溢出。
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); // overflow here
_strupr(&v12);
...
}
这里,a1
是字体名称字符串,可见在strcpy
进行字符串拷贝时没有进行长度判断,导致栈溢出。
0x03 Patch Diff
此时ecx = strlen(a1) + 1
,所以微软在这里对字体长度做了限制,不大于0x21
,所以这里不会有问题了。
- 仿今天头条加载环境文字闪动效果
- Myexclipse创建Junit测试
- 基于ASP.NET MVC(C#)和Quartz.Net组件实现的定时执行任务调度
- 第五章 正则表达式的拆分
- android 防止反编译的若干方法
- 支持Ajax跨域访问ASP.NET Web Api 2(Cors)的简单示例教程演示
- android 股票K线图
- github搭建个人网站
- Android:一个高效的UI才是一个拉风的UI
- 什么是ORM?为什么用ORM?浅析ORM的使用及利弊
- .NET[C#]中实现实体对象深拷贝(克隆/复制)的几种方法
- Android中图片大小和屏幕密度的关系讲解
- C# WINFORM通过委托和事件窗体间(跨窗体)传值(自定义事件参数)--实例详解
- Apache Spark 2.0预览:机器学习模型持久性
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- rabbitmq路由
- python学习笔记(2)——groupby
- JavaScript开发中的常用代码参考
- rabbitmq主题订阅
- AI算法让图片动起来,深情演唱Unravel
- python 学习笔记(1)——python中的lambda函数用法
- SpringBoot过滤器的简单使用
- SpringBoot拦截器的简单使用
- dotNET Core:编码规范
- K8s——Ingress-nginx原理及配置
- Java的类加载器
- 如何启动HiveServer2
- dotnet 如何调试 SmartSql 的实际执行 SQL 语句
- dotnet 关于 SmartSql 的 SQL 语句的属性替换前缀说明
- 为什么java初学者要学习一点前端技术?